예제 #1
0
 def test_3(self):
     """
     User object created
     """
     self.user = Account.objects().get(username=self.USER['email'],
         include="Store.Subscription,Store.Settings")
     return self.user is not None
예제 #2
0
 def clean_email(self):
     email = self.cleaned_data.get('email').strip().lower()
     if Account.objects().count(email=email) > 0:
         if self.account.email != email:
             raise forms.ValidationError("Email is already " +\
                 "being used.")
     return email
예제 #3
0
 def test_3(self):
     """
     User object created
     """
     self.user = Account.objects().get(
         username=self.USER['email'],
         include="Store.Subscription,Store.Settings")
     return self.user is not None
예제 #4
0
def delete(request, employee_id):
    """ 
    This will also remove the employee from the ACL,
    delete the employee object and also delete the Parse.User object
    if and only if it has no pointer to a Store or a Patron.
    """
    # get from the employees_approved_list in session cache
    employees_approved_list = SESSION.get_employees_approved_list(\
        request.session)
    i_remove, employee = 0, None
    for ind, m in enumerate(employees_approved_list):
        if m.objectId == employee_id:
            employee = m
            i_remove = ind
            break
            
    if not employee:
        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee has already been removed.'}))

    employees_approved_list.pop(i_remove)   
    request.session['employees_approved_list'] =\
        employees_approved_list
        
    acc = Account.objects().get(Employee=employee.objectId)
    if not acc: # employee may have been deleted
        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee has already been deleted.'}))
        
    # Always save session first whenever calling a cloud code
    request.session.save()
    
    res = cloud_call("delete_employee", {"employee_id": employee.objectId})
    
    request.session.clear()
    request.session.update(SessionStore(request.session.session_key))
    
    if 'error' not in res:
        store = SESSION.get_store(request.session)
        payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY }
        if acc.objectId in store.ACL and not store.is_owner(acc):
            del store.ACL[acc.objectId]
            store.update()
            payload["updatedStore"] = store.jsonify()
            request.session['store'] = store
            
        # only need to pass in the objectId
        deleted_employee = Employee(objectId=employee.objectId)
        payload["deletedEmployee"] = deleted_employee.jsonify()
            
        comet_receive(store.objectId, payload)

        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee has been deleted.'}))
                
    return redirect(reverse('employees_index')+ "?%s" %\
        urllib.urlencode({'success': 'Employee has already been deleted.'}))
예제 #5
0
def delete(request, employee_id):
    """ 
    This will also remove the employee from the ACL,
    delete the employee object and also delete the Parse.User object
    if and only if it has no pointer to a Store or a Patron.
    """
    # get from the employees_approved_list in session cache
    employees_approved_list = SESSION.get_employees_approved_list(\
        request.session)
    i_remove, employee = 0, None
    for ind, m in enumerate(employees_approved_list):
        if m.objectId == employee_id:
            employee = m
            i_remove = ind
            break

    if not employee:
        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee has already been removed.'}))

    employees_approved_list.pop(i_remove)
    request.session['employees_approved_list'] =\
        employees_approved_list

    acc = Account.objects().get(Employee=employee.objectId)
    if not acc:  # employee may have been deleted
        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee has already been deleted.'}))

    # Always save session first whenever calling a cloud code
    request.session.save()

    res = cloud_call("delete_employee", {"employee_id": employee.objectId})

    request.session.clear()
    request.session.update(SessionStore(request.session.session_key))

    if 'error' not in res:
        store = SESSION.get_store(request.session)
        payload = {COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY}
        if acc.objectId in store.ACL and not store.is_owner(acc):
            del store.ACL[acc.objectId]
            store.update()
            payload["updatedStore"] = store.jsonify()
            request.session['store'] = store

        # only need to pass in the objectId
        deleted_employee = Employee(objectId=employee.objectId)
        payload["deletedEmployee"] = deleted_employee.jsonify()

        comet_receive(store.objectId, payload)

        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee has been deleted.'}))

    return redirect(reverse('employees_index')+ "?%s" %\
        urllib.urlencode({'success': 'Employee has already been deleted.'}))
예제 #6
0
def deny(request, employee_id):
    """ same as delete except this uses the pending list """
    # get from the employees_pending_list in session cache
    employees_pending_list = SESSION.get_employees_pending_list(\
        request.session)
    i_remove, employee = 0, None
    for ind, m in enumerate(employees_pending_list):
        if m.objectId == employee_id:
            employee = m
            i_remove = ind
            break
            
    if not employee:
        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Pending employee not found.'}))
    
    # update session cache for employees_pending_list
    employees_pending_list.pop(i_remove)
    request.session['employees_pending_list'] =\
        employees_pending_list
        
        
    acc = Account.objects().get(Employee=employee.objectId)
    if not acc: # employee may have been deleted
        return redirect(reverse('employees_index')+ "?show_pending&%s" %\
            urllib.urlencode({'success': 'Employee has already been denied.'}))
        
    # Always save session first whenever calling a cloud code
    request.session.save()
    
    res = cloud_call("delete_employee", {"employee_id": employee.objectId})
    
    request.session.clear()
    request.session.update(SessionStore(request.session.session_key))
    
    if 'error' not in res:
        payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY }
        store = SESSION.get_store(request.session)
        # no need to check acl here but just in case
        if acc.objectId in store.ACL and not store.is_owner(acc):
            del store.ACL[acc.objectId]
            store.update()
            payload["updatedStore"] = store.jsonify()
            request.session['store'] = store
            
        # only need to pass in the objectId
        deleted_employee = Employee(objectId=employee.objectId)
        payload["deletedEmployee"] = deleted_employee.jsonify()
            
        comet_receive(store.objectId, payload)
    
        return redirect(reverse('employees_index')+ "?show_pending&%s" %\
            urllib.urlencode({'success': 'Employee has been denied.'}))
                
    return redirect(reverse('employees_index')+ "?%s" %\
        urllib.urlencode({'success': 'Employee has already been deleted.'}))
예제 #7
0
def deny(request, employee_id):
    """ same as delete except this uses the pending list """
    # get from the employees_pending_list in session cache
    employees_pending_list = SESSION.get_employees_pending_list(\
        request.session)
    i_remove, employee = 0, None
    for ind, m in enumerate(employees_pending_list):
        if m.objectId == employee_id:
            employee = m
            i_remove = ind
            break

    if not employee:
        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Pending employee not found.'}))

    # update session cache for employees_pending_list
    employees_pending_list.pop(i_remove)
    request.session['employees_pending_list'] =\
        employees_pending_list

    acc = Account.objects().get(Employee=employee.objectId)
    if not acc:  # employee may have been deleted
        return redirect(reverse('employees_index')+ "?show_pending&%s" %\
            urllib.urlencode({'success': 'Employee has already been denied.'}))

    # Always save session first whenever calling a cloud code
    request.session.save()

    res = cloud_call("delete_employee", {"employee_id": employee.objectId})

    request.session.clear()
    request.session.update(SessionStore(request.session.session_key))

    if 'error' not in res:
        payload = {COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY}
        store = SESSION.get_store(request.session)
        # no need to check acl here but just in case
        if acc.objectId in store.ACL and not store.is_owner(acc):
            del store.ACL[acc.objectId]
            store.update()
            payload["updatedStore"] = store.jsonify()
            request.session['store'] = store

        # only need to pass in the objectId
        deleted_employee = Employee(objectId=employee.objectId)
        payload["deletedEmployee"] = deleted_employee.jsonify()

        comet_receive(store.objectId, payload)

        return redirect(reverse('employees_index')+ "?show_pending&%s" %\
            urllib.urlencode({'success': 'Employee has been denied.'}))

    return redirect(reverse('employees_index')+ "?%s" %\
        urllib.urlencode({'success': 'Employee has already been deleted.'}))
예제 #8
0
def manage_admin_controls(request):
    """
    To turn on god_mode:
    ...repunch.com/manage/admin-controls?action=god_mode&flag=1&
    [email protected]&key=9p8437wk34z5ymurukdp9w34px7iuhsruhio
    """

    if request.method == "GET":
        params = request.GET.dict()
        key = params.get("key")
        action = params.get("action")

        if key == ADMIN_CONTROL_KEY:
            if action == "god_mode":
                flag = params.get("flag")
                email = params.get("email", "")
                acc = Account.objects().get(email=email,
                                            Store__ne=None,
                                            include="Store.Subscription")
                if not acc:
                    return HttpResponse("User with email %s not found." %\
                        (email,))

                sub = acc.store.subscription
                sub.god_mode = flag != "0"
                sub.update()

                payload = {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "updatedSubscription": sub.jsonify(),
                }
                comet_receive(acc.store.objectId, payload)

                # go out with the latest session in case this user is
                # the one that triggered this action
                request.session.clear()
                request.session.update(
                    SessionStore(request.session.session_key))

                if sub.god_mode:
                    on_off = "on"
                else:
                    on_off = "off"

                return HttpResponse("Successfully turned god mode "+\
                    "%s for user with email %s" % (on_off, email))

            else:
                return HttpResponse("Invalid action: %s" % (action, ))

        else:
            return HttpResponse("Wrong key: %s" % (key, ))

    return HttpResponse("Bad Request")
예제 #9
0
def rename_punchcode_username_to_userid():
    """
    PunchCode username column changed to user_id.
    WARNING! Assumes this assumes that # Patrons < 1000.
    """
    for acc in Account.objects().filter(Patron__ne=None,
        include="Patron", limit=999):
        pc = PunchCode.objects().get(punch_code=acc.patron.punch_code)
        pc.user_id = acc.objectId
        pc.update()
        print "Updated PunchCode " + acc.patron.punch_code
예제 #10
0
 def clean_email(self):
     # If an Account exist already with a Store object - then bad
     e = self.cleaned_data.get('email')
     if e:
         e = e.strip().lower()
         acc = Account.objects().get(email=e)
         if acc and acc.Store:
             raise forms.ValidationError(\
                 "Email is already being used.")
         elif acc: # save the object for later use
             setattr(self, "associated_account", acc)
     return e
예제 #11
0
def manage_admin_controls(request):
    """
    To turn on god_mode:
    ...repunch.com/manage/admin-controls?action=god_mode&flag=1&
    [email protected]&key=9p8437wk34z5ymurukdp9w34px7iuhsruhio
    """
    
    if request.method == "GET":
        params = request.GET.dict()
        key = params.get("key")
        action = params.get("action")
        
        if key == ADMIN_CONTROL_KEY:
            if action == "god_mode":
                flag = params.get("flag")
                email = params.get("email", "")
                acc = Account.objects().get(email=email, Store__ne=None,
                    include="Store.Subscription")
                if not acc:
                    return HttpResponse("User with email %s not found." %\
                        (email,))
                
                sub = acc.store.subscription
                sub.god_mode = flag != "0"
                sub.update()
                
                payload = {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "updatedSubscription": sub.jsonify(),
                }
                comet_receive(acc.store.objectId, payload)
                
                # go out with the latest session in case this user is
                # the one that triggered this action
                request.session.clear()                           
                request.session.update(SessionStore(request.session.session_key))
                
                if sub.god_mode:
                    on_off = "on"
                else:
                    on_off = "off"
                
                return HttpResponse("Successfully turned god mode "+\
                    "%s for user with email %s" % (on_off, email))
                
            else:
                return HttpResponse("Invalid action: %s" % (action,))
        
        else:
            return HttpResponse("Wrong key: %s" % (key,))
    
    return HttpResponse("Bad Request")
예제 #12
0
def edit(request, employee_id):
    data = {'employees_nav': True, 'employee_id': employee_id}
    
    # get from the employees_approved_list in session cache
    employees_approved_list = SESSION.get_employees_approved_list(\
        request.session)
    employee = None
    for m in employees_approved_list:
        if m.objectId == employee_id:
            employee = m
            break
            
    acc = Account.objects().get(Employee=employee.objectId)
    store = SESSION.get_store(request.session)
    
    if not employee or not acc:
        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee does not exist.'}))

    if request.method == "POST":
        store.set_access_level(acc, request.POST["ACL"])
                
        store.update()
        request.session['store'] = store
        # notify other dashboards of this change
        payload = {
            COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
            "updatedStore":store.jsonify()
        }
        comet_receive(store.objectId, payload)
        
        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee has been updated.'}))
        
    form = EmployeeForm(employee.__dict__.copy())
    form.data['email'] = acc.get('email')
    
    data.update({
        'ACCESS_ADMIN': ACCESS_ADMIN[0],
        'ACCESS_PUNCHREDEEM': ACCESS_PUNCHREDEEM[0],
        'ACCESS_NONE': ACCESS_NONE[0],
        'form': form,
        'employee': employee,
        'employee_acl': store.get_access_level(acc)[0],
    })

    return render(request, 'manage/employee_edit.djhtml', data)
예제 #13
0
def edit(request, employee_id):
    data = {'employees_nav': True, 'employee_id': employee_id}

    # get from the employees_approved_list in session cache
    employees_approved_list = SESSION.get_employees_approved_list(\
        request.session)
    employee = None
    for m in employees_approved_list:
        if m.objectId == employee_id:
            employee = m
            break

    acc = Account.objects().get(Employee=employee.objectId)
    store = SESSION.get_store(request.session)

    if not employee or not acc:
        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee does not exist.'}))

    if request.method == "POST":
        store.set_access_level(acc, request.POST["ACL"])

        store.update()
        request.session['store'] = store
        # notify other dashboards of this change
        payload = {
            COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
            "updatedStore": store.jsonify()
        }
        comet_receive(store.objectId, payload)

        return redirect(reverse('employees_index')+ "?%s" %\
            urllib.urlencode({'success': 'Employee has been updated.'}))

    form = EmployeeForm(employee.__dict__.copy())
    form.data['email'] = acc.get('email')

    data.update({
        'ACCESS_ADMIN': ACCESS_ADMIN[0],
        'ACCESS_PUNCHREDEEM': ACCESS_PUNCHREDEEM[0],
        'ACCESS_NONE': ACCESS_NONE[0],
        'form': form,
        'employee': employee,
        'employee_acl': store.get_access_level(acc)[0],
    })

    return render(request, 'manage/employee_edit.djhtml', data)
예제 #14
0
    def __init__(self, fetch_user=True, user_include="Patron,Store,Employee"):
        """
        tests has the following format:
        [ {'test_name': "Test title"}, ... ]
        """
        self.name = UN_CAMEL_RE.sub(r'\1 \2', self.__class__.__name__)

        self._tests = []
        self._results = {
            "section_name": self.name,
            "parts": self._tests,
        }

        if fetch_user:
            self.account = Account.objects().get(email=\
                self.USER['email'], include=user_include)
            self.patron = self.account.patron
            self.store = self.account.store
            self.employee = self.account.employee
예제 #15
0
 def handle(self, *args, **options):
     # for logging when ran by CRON
     print "Running passed_user_limit: " + str(timezone.now())
     
     now = timezone.now()
     b4_now = now + relativedelta(hours=-1)
     
     # get 500 subscriptions at a time
     LIMIT = 500
     
     # first scan though all the stores and set their
     # date_passed_user_limit if so
     # TODO optimize with a relational query? possible with Parse?
     #### SUB_TYPE 0
     skip = 0
     sub_count = Subscription.objects().count(\
         date_passed_user_limit=None, subscriptionType=0)
     max_users = sub_type[0]['max_users']
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit=None, god_mode=False,
             limit=LIMIT, skip=skip, order="createdAt"):
             store = sub.store
             if store.get("patronStores", count=1, limit=0) >\
                 max_users:
                 sub.date_passed_user_limit = b4_now
                 sub.update()
                 # notify the dashboards of these changes
                 payload={
                     COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                     "updatedSubscription": sub.jsonify()
                 }
                 comet_receive(sub.Store, payload)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT   
         
     # TODO optimize with a relational query? possible with Parse?
     #### SUB_TYPE 1
     skip = 0
     sub_count = Subscription.objects().count(\
         date_passed_user_limit=None, subscriptionType=1)
     max_users = sub_type[1]['max_users']
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit=None, god_mode=False,
             limit=LIMIT, skip=skip, order="createdAt"):
             store = sub.store
             if store.get("patronStores", count=1, limit=0) >\
                 max_users:
                 sub.date_passed_user_limit = b4_now
                 sub.update()
                 # notify the dashboards of these changes
                 payload={
                     COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                     "updatedSubscription": sub.jsonify()
                 }
                 comet_receive(sub.Store, payload)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT   
     
     ################
     conn = mail.get_connection(fail_silently=(not DEBUG))
     conn.open()
     # 1st day time range
     day1_end = now.replace()
     day1_start = day1_end + relativedelta(hours=-24)
     # 4th day time range
     day4_end = now + relativedelta(days=-4)
     day4_start = day4_end + relativedelta(hours=-24)
     # 8th day time range
     day8_end = now + relativedelta(days=-8)
     day8_start = day8_end + relativedelta(hours=-24)
     # 14th day time range
     day14_end = now + relativedelta(days=-14)
     day14_start = day14_end + relativedelta(hours=-24)
     
     
     #### SUB_TYPE 0
     ## 1st day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=0, date_passed_user_limit__lte=day1_end,
         date_passed_user_limit__gte=day1_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit__lte=day1_end,
             date_passed_user_limit__gte=day1_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             # with pp_cc_id
             if sub.pp_cc_id and len(sub.pp_cc_id) > 0:
                 sub.subscriptionType = 1
                 sub.date_passed_user_limit = None
                 sub.update()
                 # notify the dashboards of these changes
                 payload={
                     COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                     "updatedSubscription": sub.jsonify()
                 }
                 comet_receive(sub.Store, payload)
                 package = {
                     "status": "upgraded",
                     "sub_type": sub_type[0]["name"],
                     "new_sub_type": sub_type[1]["name"],
                     "new_sub_type_cost": sub_type[1]["monthly_cost"],
                     "new_max_patronStore_count":\
                         sub_type[1]["max_users"], 
                     "patronStore_count": sub.store.get(\
                         "patronStores", limit=0, count=1),
                 }
                     
             # no pp_cc_id
             else:
                 package = {
                     "sub_type": sub_type[0]["name"],
                     "max_patronStore_count": sub_type[0]["max_users"],
                     "patronStore_count": sub.store.get(\
                         "patronStores", limit=0, count=1),
                     "disable_date": sub.date_passed_user_limit + 
                         relativedelta(days=\
                             USER_LIMIT_PASSED_DISABLE_DAYS),
                 }
                 
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
   
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT   
         
     
     ## 4th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=0, date_passed_user_limit__lte=day4_end,
         date_passed_user_limit__gte=day4_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit__lte=day4_end,
             date_passed_user_limit__gte=day4_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = {
                 "sub_type": sub_type[0]["name"],
                 "max_patronStore_count": sub_type[0]["max_users"],
                 "patronStore_count": sub.store.get(\
                     "patronStores", limit=0, count=1),
                 "disable_date": sub.date_passed_user_limit + 
                     relativedelta(days=\
                         USER_LIMIT_PASSED_DISABLE_DAYS),
             }
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT   
         
                 
     ## 8th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=0, date_passed_user_limit__lte=day8_end,
         date_passed_user_limit__gte=day8_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit__lte=day8_end,
             date_passed_user_limit__gte=day8_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = {
                 "sub_type": sub_type[0]["name"],
                 "max_patronStore_count": sub_type[0]["max_users"],
                 "patronStore_count": sub.store.get(\
                     "patronStores", limit=0, count=1),
                 "disable_date": sub.date_passed_user_limit + 
                     relativedelta(days=\
                         USER_LIMIT_PASSED_DISABLE_DAYS),
             }
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT  
         
             
     ## 14th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=0, date_passed_user_limit__lte=day14_end,
         date_passed_user_limit__gte=day14_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=0, include="Store", 
             date_passed_user_limit__lte=day14_end,
             date_passed_user_limit__gte=day14_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = { "status": "disabled" }
             
             # deactivate the store
             sub.store.active = False
             sub.store.update()
             payload = {
                 COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                 "updatedStore":sub.store.jsonify(),
             }
             comet_receive(sub.Store, payload)
             
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
     
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT  
     
     
     #### SUB_TYPE 1
     ## 1st day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=1, date_passed_user_limit__lte=day1_end,
         date_passed_user_limit__gte=day1_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit__lte=day1_end,
             date_passed_user_limit__gte=day1_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             # with pp_cc_id
             if sub.pp_cc_id and len(sub.pp_cc_id) > 0:
                 sub.subscriptionType = 2
                 sub.date_passed_user_limit = None
                 sub.update()
                 # notify the dashboards of these changes
                 payload={
                     COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                     "updatedSubscription": sub.jsonify()
                 }
                 comet_receive(sub.Store, payload)
                 package = {
                     "status": "upgraded",
                     "sub_type": sub_type[1]["name"],
                     "new_sub_type": sub_type[2]["name"],
                     "new_sub_type_cost": sub_type[2]["monthly_cost"],
                     "new_max_patronStore_count": "Unlimited",
                     "patronStore_count": sub.store.get(\
                         "patronStores", limit=0, count=1),
                 }
                 
             # no pp_cc_id
             else:
                 package = {
                     "sub_type": sub_type[1]["name"],
                     "max_patronStore_count": sub_type[1]["max_users"],
                     "patronStore_count": sub.store.get(\
                         "patronStores", limit=0, count=1),
                     "disable_date": sub.date_passed_user_limit + 
                         relativedelta(days=\
                             USER_LIMIT_PASSED_DISABLE_DAYS),
                 }
                 
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
                     
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT  
     
     ## 4th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=1, date_passed_user_limit__lte=day4_end,
         date_passed_user_limit__gte=day4_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit__lte=day4_end,
             date_passed_user_limit__gte=day4_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = {
                 "sub_type": sub_type[1]["name"],
                 "max_patronStore_count": sub_type[1]["max_users"],
                 "patronStore_count": sub.store.get(\
                     "patronStores", limit=0, count=1),
                 "disable_date": sub.date_passed_user_limit + 
                     relativedelta(days=\
                         USER_LIMIT_PASSED_DISABLE_DAYS),
             }
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
                 
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT  
         
         
     ## 8th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=1, date_passed_user_limit__lte=day8_end,
         date_passed_user_limit__gte=day8_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit__lte=day8_end,
             date_passed_user_limit__gte=day8_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = {
                 "sub_type": sub_type[1]["name"],
                 "max_patronStore_count": sub_type[1]["max_users"],
                 "patronStore_count": sub.store.get(\
                     "patronStores", limit=0, count=1),
                 "disable_date": sub.date_passed_user_limit + 
                     relativedelta(days=\
                         USER_LIMIT_PASSED_DISABLE_DAYS),
             }
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
          
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT         
          
     ## 14th day
     skip = 0
     sub_count = Subscription.objects().count(\
         subscriptionType=1, date_passed_user_limit__lte=day14_end,
         date_passed_user_limit__gte=day14_start)
     while sub_count > 0:
         for sub in Subscription.objects().filter(\
             subscriptionType=1, include="Store", 
             date_passed_user_limit__lte=day14_end,
             date_passed_user_limit__gte=day14_start,
             limit=LIMIT, skip=skip, order="createdAt"):
             package = { "status": "disabled" }
             
             # deactivate the store
             sub.store.active = False
             sub.store.update()
             payload = {
                 COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                 "updatedStore":sub.store.jsonify(),
             }
             comet_receive(sub.Store, payload)
             
             try:
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             except SMTPServerDisconnected:
                 conn = mail.get_connection(fail_silently=(not DEBUG))
                 conn.open()
                 send_email_passed_user_limit(Account.objects().get(\
                     Store=sub.Store), sub.store, package, conn)
             
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT       
     
     try:
         conn.close()
     except Exception:
         pass
예제 #16
0
def test_employees():
    """
    Tests for employee approve, deny, remove, details. etc.
    """
    # TODO test employee graph
    # TODO test employee punches history
    
    # delete the employees and associated User objects in the relation
    account = Account.objects().get(username=TEST_USER['username'],
        include="Store.Settings")
    store = account.store
    settings = store.settings
    
    emps = store.get("employees")
    if emps:
        for emp in emps:
            Account.objects().get(Employee=emp.objectId).delete()
            emp.delete()
    
    store.set("employees", None)  
    
    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Cloud code register_employee works"},
        {'test_name': "Employee is saved in store's Employees " +\
            "relation"},
        {'test_name': "Employee is initially pending (Parse)"},
        {'test_name': "Employee is initially pending (Dashboard)"},
        {'test_name': "Email must be valid (cloud code)"},
        {'test_name': "Email must be unique (cloud code)"},
        {'test_name': "Username must be unique (cloud code)"},
        {'test_name': "Retailer PIN must exist (cloud code)"},
        {'test_name': "Clicking deny prompts the user to confirm"},
        {'test_name': "The user is redirected to employee index"},
        {'test_name': "The denied employee is removed from the " +\
            "pending table"},
        {'test_name': "The employee is deleted from parse"},
        {'test_name': "The account/user is deleted from parse"},
        {'test_name': "Approving the employee moves it from " +\
            "pending to approved"},
        {'test_name': "Employee status is set to approved in Parse"},
        {'test_name': "Employee initially has 0 punches."},
        {'test_name': "Clicking on the approved employee row " +\
            " redirects user to employee edit page"},
        {'test_name': "Clicking delete prompts the user to confirm"},
        {'test_name': "The user is redirected to employee index"},
        {'test_name': "The deleted employee is removed from the " +\
            "pending table"},
        {'test_name': "The employee is deleted from parse"},
        {'test_name': "The account/user is deleted from parse"},
        {'test_name': "Multiple employees (3) registering at once" +\
            " shows up in dashboard"},
    ]
    section = {
        "section_name": "Employees page working properly?",
        "parts": parts,
    }
    test.results.append(section)
    
    ##########  User needs to be logged in to access page"
    test.open(reverse("employees_index")) # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("employees_index"))
        
    # login
    selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
    )
    test.action_chain(0, selectors, "send_keys") # ACTION!
    sleep(7) 
    
    def register_employee(first_name, last_name, username=None, 
        password=None, email=None, retailer_pin=None):
        
        if username is None: 
            username = first_name
        if password is None: 
            password = first_name
        if email is None: 
            email = first_name + "@" + last_name + ".com"
        if retailer_pin is None: 
            retailer_pin = settings.retailer_pin
            
        return cloud_call("register_employee", {
            "first_name": first_name,
            "last_name": last_name,
            "username": username,
            "password": password,
            "email": email,
            "retailer_pin": retailer_pin,
        })
        
    first_name, last_name, username, email =\
    "vandolf1", "estrellado", "*****@*****.**", "*****@*****.**"
        
    ##########  Cloud code register_employee works"
    try:
        res = register_employee(first_name, last_name, username,
            email=email)
        parts[1]['success'] = "error" not in res
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
    ##########  Employee is saved in store's Employees relation"
    try:
        emp = store.get("employees")[0]
        parts[2]['success'] = emp is not None
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
    ##########  Employee is initially pending (Parse)"
    try:
        parts[3]['success'] = emp.status == PENDING
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
    ##########  Employee is initially pending (Dashboard)"
    try:
        sleep(COMET_PULL_RATE*2 + 1) # wait for dashboard to receive
        test.find("#tab-pending-employees").click()
        parts[4]['success'] = test.element_exists(\
            "#tab-body-pending-employees div.tr div.td.approve")
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)
    ##########  Email must be valid (cloud code)"
    try:
        res = register_employee("vman", "vman", email="vmahs@vman")
        parts[5]['success'] = res['error'] == 'EMAIL_INVALID'
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
    ##########  Email must be unique (cloud code) "
    try:
        res = register_employee("vman", "vman",
            email=email)
        parts[6]['success'] = res['error'] == 'EMAIL_TAKEN'
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)
    ##########  Username must be unique (cloud code) "
    try:
        res = register_employee("vman", "vman", username=username)
        parts[7]['success'] = res['error'] == 'USERNAME_TAKEN'
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
    ##########  Retailer PIN must exist (cloud code) "
    try:
        res = register_employee("vman", "vman", retailer_pin="sdgdgs")
        parts[8]['success'] = res['error'] == "RETAILER_PIN_INVALID"
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)
    ##########  Clicking deny prompts the user to confirm"
    try:
        test.find("#tab-pending-employees").click()
        test.find("#tab-body-pending-employees div.tr " +\
            "div.td.approve a.deny").click()
        alert = test.switch_to_alert()
        parts[9]['success'] = alert.text == "Deny employee?"
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
    ##########  The user is redirected to employee index"
    try:
        sleep(1)
        alert.accept()
        sleep(2)
        parts[10]['success'] = test.is_current_url(reverse(\
            "employees_index") +\
            "?show_pending&success=Employee+has+been+denied.")
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    ##########  The denied employee is removed from the pending table"
    try:
        parts[11]['success'] = not test.element_exists(\
        "#tab-body-pending-employees div.tr " +\
            "div.td.approve a.approve")
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
    ##########  The employee is deleted from parse"
    try:
        store.set("employees", None)
        parts[12]['success'] = store.get("employees",\
            first_name=first_name, last_name=last_name, count=1) == 0
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)
    ##########  The account/user is deleted from parse"
    try:
        parts[13]['success'] = Account.objects().count(\
            username=username, email=email) == 0
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)
    ##########  Approving the employee moves it from pending to approved"
    try:
        register_employee(first_name, last_name, username,
            email=email)
        sleep(COMET_PULL_RATE*2 + 1) # wait for dashboard to receive
        test.find("#tab-pending-employees").click()
        approveRow = test.find("#tab-body-pending-employees " +\
            "div.tr")
        approveId = approveRow.get_attribute("id")
        approveRow.find_element_by_css_selector(\
            "div.td.approve a.approve").click()
        sleep(1)
        test.switch_to_alert().accept()
        sleep(2)
        test.find("#tab-approved-employees").click()
        parts[14]['success'] = test.element_exists(\
            "#tab-body-approved-employees " +\
            "div.tr div.td.remove a")
    except Exception as e:
        print e
        parts[14]['test_message'] = str(e)
    ##########  Employee status is set to approved in Parse"
    try:
        store.set("employees", None)
        emp = store.get("employees", first_name=first_name,
            last_name=last_name)[0]
        parts[15]['success'] = emp.status == APPROVED
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    ##########  Employee initially has 0 punches"
    try:
        parts[16]['success'] = emp.lifetime_punches == 0
    except Exception as e:
        print e
        parts[16]['test_message'] = str(e)
    ##########  Clicking on the approved employee row 
    ###         redirects user to employee edit page 
    try:
        test.find("#tab-approved-employees").click()
        test.find("#tab-body-approved-employees div#%s a" %\
            (emp.objectId,)).click()
        sleep(1)
        parts[17]['success'] = test.is_current_url(reverse(\
            "employee_edit", args=(emp.objectId,)))
    except Exception as e:
        print e
        parts[17]['test_message'] = str(e)
    ##########  Clicking delete prompts the user to confirm"
    try:
        test.find("#delete-button").click()
        alert = test.switch_to_alert()
        parts[18]['success'] = alert.text ==\
            "Are you sure you want to delete this employee?"
    except Exception as e:
        print e
        parts[18]['test_message'] = str(e)
    ##########  The user is redirected to employee index"
    try:
        sleep(1)
        alert.accept()
        sleep(2)
        parts[19]['success'] = test.is_current_url(reverse(\
            "employees_index") +\
            "?success=Employee+has+been+deleted.")
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
    ##########  The deleted employee is removed from the pending table"
    try:
        parts[20]['success'] = not test.element_exists(\
            "#tab-body-approved-employees div#%s a" %(emp.objectId,))
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    ##########  The employee is deleted from parse"
    try:
        store.set("employees", None)
        parts[21]['success'] = store.get("employees", 
            objectId=emp.objectId, count=1) == 0
    except Exception as e:
        print e
        parts[21]['test_message'] = str(e)
    ##########  The account/user is deleted from parse"
    try:
        parts[22]['success'] = Account.objects().count(\
            username=username, email=email) == 0
    except Exception as e:
        print e
        parts[22]['test_message'] = str(e)
    ##########  Multiple employees (4) registering at once
    ###         shows up in dashboard"
    try:
        for i in range(3):
            register_employee(first_name + str(i), last_name + str(i))
        sleep(COMET_PULL_RATE*2 + 3)
        test.find("#tab-pending-employees").click()
        parts[23]['success'] = len(test.find(\
            "#tab-body-pending-employees div.tr " +\
            "div.td.approve a.approve", multiple=True)) == 3
    except Exception as e:
        print e
        parts[23]['test_message'] = str(e)
    
    
    # END OF ALL TESTS - cleanup
    return test.tear_down() 
예제 #17
0
def test_messages():
    # TODO test that patrons are getting the messages!!!
    # setup
    account = Account.objects().get(username=TEST_USER['username'],
        include="Store.Subscription")
    store = account.store
    subscription = store.subscription

    # set subscriptionType to free
    subscription.subscriptionType = 0
    subscription.update()

    # clear the sent messages relation
    sent_messages = store.get("sentMessages", keys="")
    if sent_messages:
        store.remove_relation("SentMessages_",
            [m.objectId for m in sent_messages])
            
    store.set("sentMessages", None)
            
    # we can clear the list locally but just re-pull from parse
    account = Account.objects().get(username=TEST_USER['username'],
        include="Store.Subscription")
    store = account.store
    subscription = store.subscription
    
    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        
        # FIRST
        {'test_name': "Send message. Filter all. No offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SECOND
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # THIRD    
        {'test_name': "Send message. Filter idle. No offer. " +\
            "Message limit passed (free) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Upgrading account from the dialog sends the " +\
            "message and upgrades the account to middle"},
        {'test_name': "Email is sent notifying user the upgrade"},
        #
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # FOURTH
        {'test_name': "Send message. Filter idle. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # FIFTH
        {'test_name': "Send message. Filter most_loyal. No offer. " +\
            "Message limit passed (middle) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Upgrading account from the dialog sends the" +\
            " message and upgrades the account to heavy"},
        {'test_name': "Email is sent notifying user the upgrade"},
        #
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SIXTH
        {'test_name': "Send message. Filter most_loyal. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SEVENTH
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # EIGHTH
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # NINTH
        {'test_name': "Send message. Filter all. No offer. " +\
            "Message limit passed (heavy) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Account can no longer be upgraded." +\
            "Message cannot be sent. Clicking okay redirects "+\
            "user to messages index."},
        #
            
        {'test_name': "Subject is required"},
        {'test_name': "Body is required"},
        {'test_name': "Offer title not required if attach offer off"},
        {'test_name': "Expiration not required if attach offer off"},
        {'test_name': "Offer title is required if attach offer on"},
        {'test_name': "Expiration date required if attach offer on"},
        {'test_name': "Expiration date must be at a later date"},
        {'test_name': "Expiration date must be at most 1 year later"},
    ]
    section = {
        "section_name": "Sending messages works?",
        "parts": parts,
    }
    test.results.append(section)
    
    ##########  User needs to be logged in to access page
    test.open(reverse("messages_index")) # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("messages_index"))
        
    # login
    selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
    )
    test.action_chain(0, selectors, "send_keys") # ACTION!
    sleep(5) 
    
    def send_message(filter, subject, body,
            attach_offer=False, offer_title=None, exp_date=None,):
        """ Must be called at messages index page """
        test.find("#create_message").click()
        sleep(1)
        # set the filter
        test.find("//select[@id='filter']/option[@value='%s']" %\
            (filter,), type="xpath").click()
        # subject
        test.find("#id_subject").send_keys(subject)
        # body
        test.find("#id_body").send_keys(body)
        # attach_offer
        if attach_offer:
            test.find("#id_attach_offer").click()
            # offer title
            if offer_title:
                test.find("#id_offer_title").send_keys(offer_title)
            # exp_date
            if exp_date:
                test.find("#id_date_offer_expiration").send_keys(exp_date)
            
        # submit
        test.find("#send-now").click()
        sleep(5)
        
    def message_in_relation(message_id, test_number):
        if not message_id:
            return
            
        store.sentMessages = None
        parts[test_number]['success'] = store.get("sentMessages", 
            objectId=message_id, count=1, limit=0) == 1
            
    def message_in_page(message_id, test_number):
        if not message_id:
            return
            
        try:
            rows = test.find("#tab-body-sent div.tr a", multiple=True)
            for row in rows:
                if row.get_attribute("href").split("/")[5] ==\
                    message_id:
                    parts[test_number]['success'] = True
        except Exception as e:
            print e
            parts[test_number]['test_message'] = str(e)
        
    def message_viewable(message_id, test_number):
        if not message_id:
            return
        href = reverse("message_details", args=(message_id,))
        try:
            test.find("#tab-body-sent div.tr a[href='%s']" %\
                (href,)).click()
            sleep(2)
            parts[test_number]['success'] = test.is_current_url(href)
        except Exception as e:
            print e
            parts[test_number]['test_message'] = str(e)
        finally:
            # must go back to messages index for the other tests
            test.open(reverse("messages_index"))
                
    # FIRST
    ##########  Send message. Filter all. No offer. 
    message_id = None
    try:
        send_message("all", "msg #1", "body #1")
        parts[1]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
        
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 2)
    ##########  Message is visible in page. 
    message_in_page(message_id, 3)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 4)

    # SECOND
    ##########  Send message. Filter all. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #2", "body #2", True, "offer#2",
            exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[5]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 6)
    ##########  Message is visible in page. 
    message_in_page(message_id, 7)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 8) 
        
    # THIRD
    ##########  Send message. Filter idle. No offer. 
    ###         Message limit passed (free) dialog appears.
    message_id = None
    try:
        send_message("idle", "msg #3", "body #3")
        parts[9]['success'] = test.find("#upgrade") is not None
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Upgrading account from the dialog sends the 
    ###         message and upgrades the account to middle.
    try:
        test.find("#upgrade").click()
        sleep(2)
        test.find("#id_cc_cvv").send_keys("123")
        test.find("#id_recurring").click()
        test.find("#update-form-submit").click()
        sleep(5)
        message_id = test.driver.current_url.split("/")[5]
        subscription.subscriptionType = None
        parts[10]['success'] = test.is_current_url(\
            reverse("message_details", args=(message_id,))) and\
            subscription.get("subscriptionType") == 1
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
        
    # open the mail connection
    if SeleniumTest.CHECK_SENT_MAIL:
        mail = Mail()
        ##########  Email is sent notifying user the upgrade.
        try:
            parts[11]['success'] = mail.is_mail_sent(\
                EMAIL_UPGRADE_SUBJECT)
        except Exception as e:
            print e
            parts[11]['test_message'] = str(e)
    else:
        parts[11]['success'] = parts[10]['success']
        
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 12)
    ##########  Message is visible in page. 
    message_in_page(message_id, 13)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 14) 

    # FOURTH
    ##########  Send message. Filter idle. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("idle", "msg #4", "body #4", True, "offer#4",
            exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[15]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 16)
    ##########  Message is visible in page. 
    message_in_page(message_id, 17)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 18) 
        
    # FIFTH
    ##########  Send message. Filter most_loyal. No offer. 
    ###         Message limit passed (free) dialog appears.
    message_id = None
    try:
        send_message("most_loyal", "msg #5", "body #5")
        parts[19]['success'] = test.find("#upgrade") is not None
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Upgrading account from the dialog sends the 
    ###         message and upgrades the account to heavy.
    try:
        test.find("#upgrade").click()
        sleep(2)
        test.find("#id_cc_cvv").send_keys("123")
        test.find("#id_recurring").click()
        test.find("#update-form-submit").click()
        sleep(5)
        message_id = test.driver.current_url.split("/")[5]
        subscription.subscriptionType = None
        parts[20]['success'] = test.is_current_url(\
            reverse("message_details", args=(message_id,))) and\
            subscription.get("subscriptionType") == 2
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Email is sent notifying user the upgrade.
    if SeleniumTest.CHECK_SENT_MAIL:
        try:
            parts[21]['success'] = mail.is_mail_sent(\
                EMAIL_UPGRADE_SUBJECT)
        except Exception as e:
            print e
            parts[21]['test_message'] = str(e)
    else:
        parts[21]['success'] = parts[20]['success']
            
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 22)
    ##########  Message is visible in page. 
    message_in_page(message_id, 23)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 24) 

    # SIXTH
    ##########  Send message. Filter most_loyal. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("most_loyal", "msg #6", "body #6",
            True, "offer#6", exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[25]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[25]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 26)
    ##########  Message is visible in page. 
    message_in_page(message_id, 27)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 28) 

    # SEVENTH
    ##########  Send message. Filter all. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #7", "body #7", True, "offer#7",
            exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[29]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[29]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 30)
    ##########  Message is visible in page. 
    message_in_page(message_id, 31)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 32) 

    # EIGHTH
    ##########  Send message. Filter all. With offer. 
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #8", "body #8", True, "offer#8",
            exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[33]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[33]['test_message'] = str(e)
    finally: # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation. 
    message_in_relation(message_id, 34)
    ##########  Message is visible in page. 
    message_in_page(message_id, 35)
    ##########  Message can be view by clicking on row. 
    message_viewable(message_id, 36) 

    # NINTH
    ##########  Send message. Filter all. With offer. 
    ###         Message limit passed (heavy) dialog appears. 
    message_id = None
    try:
        send_message("all", "msg #9", "body #9")
        parts[37]['success'] = test.element_exists("#maxed_out")
    except Exception as e:
        print e
        parts[37]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Account can no longer be upgraded. Msg cannot be sent.
    ###         Clicking Okay redirects user to messages index.
    try:
        test.find("#maxed_out").click()
        sleep(1)
        parts[38]['success'] =\
            test.is_current_url(reverse("messages_index"))
    except Exception as e:
        print e
        parts[38]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # 
    
    # goto edit message page
    test.find("#create_message").click()
    sleep(2)
        
    selectors = (
        ("#id_subject", "   "),
        ("#id_body", "   "),
    )
    test.action_chain(0, selectors, action="send_keys")
    test.find("#send-now").click()
    sleep(1)
    ##########  Subject is required.
    try:
        parts[39]['success'] = test.find("#subject_e ul li").text ==\
            "This field is required."
    except Exception as e:
        print e
        parts[39]['test_message']= str(e)
    ##########  Body is required. 
    try:
        parts[40]['success'] = test.find("#body_e ul li").text ==\
            "This field is required."
    except Exception as e:
        print e
        parts[40]['test_message'] = str(e)
    ##########  Offer title not required if attach offer off. 
    try:
        parts[41]['success'] = not test.element_exists(\
            "#offer_title_e ul li")
    except Exception as e:
        print e
        parts[41]['test_message'] = str(e)
    ##########  Expiration not required if attach offer off. 
    try:
        parts[42]['success'] = not test.element_exists(\
            "#date_offer_expiration_e ul li")
    except Exception as e:
        print e
        parts[42]['test_message'] = str(e)
        
    test.find("#id_attach_offer").click()
    test.find("#send-now").click()
    sleep(1)
    ##########  Offer title is required if attach offer on. 
    try:
        parts[43]['success'] =\
            test.find("#offer_title_e ul li").text ==\
            "Please enter a title."
    except Exception as e:
        print e
        parts[43]['test_message'] = str(e)
    ##########  Expiration date required if attach offer on. 
    try:
        parts[44]['success'] =\
            test.find("#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date."
    except Exception as e:
        print e
        parts[44]['test_message'] = str(e)
        
    ##########  Expiration date must be at a later date. 
    try:
        # don't click attach offer again!
        # test.find("#id_attach_offer").click()
        exp_date = timezone.now() + relativedelta(days=-1)
        test.find("#id_date_offer_expiration").send_keys(\
            exp_date.strftime(DATE_PICKER_STRFTIME))
        test.find("#send-now").click()
        sleep(1)
        parts[45]['success'] = test.find(\
            "#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date that is later than today."
    except Exception as e:
        print e
        parts[45]['test_message'] = str(e)
    
    ##########  Expiration date must be at most 1 year later. 
    try:
        # don't click attach offer again!
        # test.find("#id_attach_offer").click()
        exp_date = timezone.now() + relativedelta(days=367)
        date_offer = test.find("#id_date_offer_expiration")
        date_offer.clear()
        date_offer.send_keys(\
            exp_date.strftime(DATE_PICKER_STRFTIME))
        test.find("#send-now").click()
        sleep(2)
        parts[46]['success'] = test.find(\
            "#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date that is less than a year."
    except Exception as e:
        print e
        parts[46]['test_message'] = str(e)
    
    
    # END OF ALL TESTS - cleanup
    if SeleniumTest.CHECK_SENT_MAIL:
        mail.logout()
        
    return test.tear_down() 
예제 #18
0
    def create_random_stores(self, amount):
        for i in range(amount):
            print "Creating store %s" % (str(i), )
            # create the store
            street, city, state, zip, country, phone_number =\
                self.addrs[i].split(", ")
            first_name, last_name = self.owners[i].split(" ")
            neighborhood = self.neighborhoods[i]
            store_name = self.stores[i]
            store_i = STORE.copy()
            store_location_i = STORE_LOCATION.copy()

            # create the thumbnaiil and cover (same image different size)
            self.get_store_location_image(i)

            thumbnail = create_png(TMP_IMG_PATH, IMAGE_THUMBNAIL_SIZE)
            while "error" in image:
                print "Retrying create_png"
                thumbnail = create_png(TMP_IMG_PATH)

            cover = create_png(TMP_IMG_PATH)
            while "error" in cover:
                print "Retrying create_png"
                cover = create_png(TMP_IMG_PATH)

            store_i.update({
                "store_name": store_name,
                "first_name": first_name,
                "last_name": last_name,
                "thumbnail_image": thumbnail.get("name"),
                "cover_image": cover.get("name"),
            })
            store_location_i.update({
                "street":
                street,
                "city":
                city,
                "state":
                state,
                "zip":
                zip,
                "neighborhood":
                neighborhood,
                "country":
                country,
                "phone_number":
                phone_number,
                "coordinates":
                self.get_random_coordinates(),
            })

            # create the store
            store = Store.objects().create(**store_i)

            # create the store location
            store_location = StoreLocation(**store_location_i)
            store_location.Store = store.objectId
            store_location.update()

            # create the settings
            settings = Settings.objects().create(Store=store.objectId)

            # create the subscription
            subscription =\
                Subscription.objects().create(Store=store.objectId,
                    date_last_billed=timezone.now())

            # create the user
            email = first_name + str(randint(0, 99)) + USER_EMAIL_POSTFIX
            email = email.lower()
            acc = Account.objects().create(\
                username=email, email=email,
                password=USER_PASSWORD, Store=store.objectId)
            if not acc.objectId:
                raise Exception("Account creation failed.")

            # link the store
            store.Settings = settings.objectId
            store.Subscription = subscription.objectId
            store.owner_id = acc.objectId
            store.ACL[acc.objectId] = {"read": True, "write": True}
            store.store_locations = [store_location]
            store.update()
예제 #19
0
 def handle(self, *args, **options):
     """
     get all of the subscriptions whose stores are active & who
     have been last billed 30+ days ago.
     IMPORTANT! This includes accounts of type FREE, which are
     not charged or included in the email notifications
     """
     # for logging when ran by CRON
     print "Running monthly_billing: " + str(timezone.now())
     
     date_30_ago = timezone.now() + relativedelta(days=-30)
     date_now = timezone.now()
     sub_count = pointer_query("Subscription",
         {"date_last_billed__lte":date_30_ago},
             "Store", "Store", {"active":True}, count=True)
             
     asiss = []
     # get 500 subscriptions at a time
     LIMIT, skip = 500, 0
     while sub_count > 0:
         for each in pointer_query("Subscription",
             {"date_last_billed__lte":date_30_ago}, "Store",
                 "Store", {"active":True}, limit=LIMIT,
                 skip=skip, order="createdAt")['results']:
             subscription = Subscription(**each)
             sub_cost = sub_type[subscription.get(\
                         "subscriptionType")]["monthly_cost"]
             store = None # prevent UnboundLocalError
             update_store = False
             if sub_cost == 0: # FREE account
                 subscription.date_last_billed =\
                     subscription.date_last_billed +\
                     relativedelta(days=30)
                 subscription.update()
             else: # PAID account
                 account = Account.objects().get(Store=\
                             subscription.get("Store"),
                             include="Store")
                 store = account.get("store")
                 invoice = subscription.charge_cc(\
                         sub_cost, "Repunch Inc. Recurring " +\
                         "monthly subscription charge", MONTHLY)
                 send_user_email = True
                 if invoice:
                     subscription.date_last_billed =\
                         subscription.date_last_billed +\
                         relativedelta(days=30)
                     subscription.date_charge_failed = None
                     subscription.update()
                 else:
                     subscription.date_charge_failed = date_now
                     # force entering new credit card!
                     subscription.cc_number = None
                     subscription.date_cc_expiration = None
                     subscription.update()
                 
                     # notify user via email- payment is done via 
                     # dashboard to also validate cc realtime
                     # 1st day time range
                     day0_end = date_30_ago.replace()
                     day0_start = day0_end + relativedelta(hours=-24)
                     # 4th day time range
                     day4_end = date_30_ago + relativedelta(days=-4)
                     day4_start = day4_end + relativedelta(hours=-24)
                     # 8th day time range
                     day8_end = date_30_ago + relativedelta(days=-8)
                     day8_start = day8_end + relativedelta(hours=-24)
                     # 14th day time range
                     day14_end = date_30_ago + relativedelta(days=-14)
                     day14_start = day14_end + relativedelta(hours=-24)
                     # only send email after 1, 4, and 8 days
                     last_billed = subscription.date_last_billed
                     if (last_billed >= day0_start and\
                         last_billed <= day0_end) or\
                         (last_billed >= day4_start and\
                         last_billed <= day4_end) or\
                         (last_billed >= day8_start and\
                         last_billed <= day8_end):
                         send_email_receipt_monthly_failed(account, store,
                             subscription)
                     elif last_billed >= day14_start and\
                         last_billed <= day14_end:
                         # send final notification
                         send_email_receipt_monthly_failed(account,
                             store, subscription, account_disabled=True)
                     else:
                         send_user_email = False
                             
                     # make sure that the store is deactivated after the 14th day
                     if last_billed <= day14_end:
                         store.active = False
                         store.update()
                         update_store = True
                     
                 # do not send email after account deactivation
                 if send_user_email:
                     asiss.append((account, store, invoice,
                         subscription))
                     
             # update the logged in users' subscription and store
             payload = {
                 COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                 "updatedSubscription":subscription.jsonify()
             }
             if store and update_store:
                 payload.update({"updatedStore":store.jsonify()})
             comet_receive(subscription.Store, payload)
                     
         # end of while loop
         sub_count -= LIMIT
         skip += LIMIT
         
     # everything is done - send the emails
     send_email_receipt_monthly_batch(asiss)
예제 #20
0
def register(request):
    """ 
    Adds a new employee to the currently logged in Store.
    This automatically sets this employee to approved.
    """
    data = {'employees_nav': True}

    settings = SESSION.get_settings(request.session)
    store = SESSION.get_store(request.session)

    if request.method == "POST":
        from_associated_account = False
        # check if this post is from the associated account dialog
        # if it is then skip form validations
        aaf_nonce_id = request.POST.get('aaf-nonce')
        aaf_account_id = request.POST.get('aaf-account_id')
        if len(aaf_nonce_id) > 0 and len(aaf_account_id) > 0:
            aa_nonce = AssociatedAccountNonce.objects.filter(\
                id=aaf_nonce_id, account_id=aaf_account_id)
            if len(aa_nonce) > 0 and aa_nonce[0].verified:
                aa_nonce[0].delete()
                from_associated_account = True

        account_form = EmployeeAccountSignUpForm(request.POST)
        employee_form = EmployeeForm(request.POST)

        if not from_associated_account:
            all_forms_valid = account_form.is_valid() and\
                employee_form.is_valid()
        else:
            all_forms_valid = True

        if all_forms_valid:
            postDict = request.POST.dict()

            # make the cloud call
            # see cloud param for possible access level values
            acl = postDict['acl']
            if acl == ACCESS_ADMIN[0]:
                access_level = "admin"
            elif acl == ACCESS_PUNCHREDEEM[0]:
                access_level = "punch_redeem"
            else:
                access_level = None

            params = {
                "retailer_pin": settings.get("retailer_pin"),
                "username": postDict['email'].strip().lower(),
                "first_name": postDict['first_name'].capitalize(),
                "last_name": postDict['last_name'].capitalize(),
                "email": postDict['email'].strip().lower(),
                "status": APPROVED,
                "access_level": access_level,
            }

            if from_associated_account:
                res = cloud_call("link_employee", params)
            else:
                params["password"] = postDict['password']
                res = cloud_call("register_employee", params)

            # don't forget to retrieve the latest session
            request.session.clear()
            request.session.update(SessionStore(request.session.session_key))

            # check if email already taken here to handle the case where
            # the user already has a patron/employee account
            # but also want to sign up for a Store account
            if "error" in res and res['error'] in ("EMAIL_TAKEN_AVAILABLE",
                                                   "USERNAME_TAKEN_AVAILABLE"):
                aa = Account.objects().get(
                    email=postDict['email'].strip().lower())
                aan = AssociatedAccountNonce.objects.create(\
                    account_id=aa.objectId)
                return HttpResponse(json.dumps({"associated_account":\
                    aa.objectId, "associated_account_nonce":aan.id,
                    "email": aa.email, "code": 0}),
                    content_type="application/json")
            elif "error" in res and res['error'] in ("EMAIL_TAKEN",
                                                     "USERNAME_TAKEN"):
                account_form._errors.setdefault(
                    "email",
                    ErrorList()).append(u"Email is already being used.")
            elif "error" not in res:
                # add the employee to the approved list
                employees_approved_list =\
                    SESSION.get_employees_approved_list(request.session)
                employees_approved_ids =\
                    [ emp.objectId for emp in employees_approved_list ]

                new_employee = Employee(**res["result"])
                if new_employee.objectId not in employees_approved_ids:
                    employees_approved_list.insert(0, new_employee)
                    request.session['employees_approved_list'] =\
                        employees_approved_list

                # update our local store's acl - don't wait for
                # the cloud post
                store = SESSION.get_store(request.session)
                store.set_access_level(Account.objects().get(\
                    email=postDict['email'].strip().lower()), acl)
                request.session['store'] = store

                # notify other dashboards of this change
                payload = {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "updatedStore": store.jsonify()
                }
                comet_receive(store.objectId, payload)

                return HttpResponse(json.dumps({"code": 2}),
                                    content_type="application/json")
            else:
                return HttpResponse(json.dumps({"code": 3}),
                                    content_type="application/json")

    else:
        employee_form = EmployeeForm(initial={"acl":\
            ACCESS_PUNCHREDEEM[0]})
        account_form = EmployeeAccountSignUpForm()

    data["employee_form"] = employee_form
    data["account_form"] = account_form

    return render(request, 'manage/employee_register.djhtml', data)
예제 #21
0
def test_cancel_account():
    """
    A test just for the cancel account link.
    """
    account =  Account.objects().get(username=TEST_USER['username'],
        include="Store")
    store = account.store
    
    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Clicking the cancel button brings up a " +\
            "confirmation dialog"},
        {'test_name': "Clicking cancel on the dialog dimisses the " +\
            "dialog and the account remains active"},
        {'test_name': "Clicking OK logs the user out"},
        {'test_name': "Clicking OK sets the store's active field " +\
            "to false on Parse"},
    ]
    section = {
        "section_name": "Deactivate store link functional?",
        "parts": parts,
    }
    self.results.append(section)
    
    ##########  User needs to be logged in to access page
    self.open(reverse("store_index")) 
    sleep(1)
    parts[0]['success'] = self.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("store_index"))
        
    # login
    selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
    )
    self.action_chain(0, selectors, "send_keys") 
    sleep(7)  
    
    ##########  Clicking the cancel button brings up a confrmtn dialog
    try:
        self.find("#deactivate_account").click()
        sleep(1)
        alert = self.switch_to_alert()
        parts[1]['success'] = alert is not None
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
        
    ##########  Clicking cancel on the dialog dimisses the 
    ###         dialog and the account remains active
    try:
        alert.dismiss()
        try:
            alert.text
        except NoAlertPresentException:
            store.active = None
            parts[2]['success'] = store.get("active")
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
        
    ##########  Clicking OK logs the user out
    try:
        self.find("#deactivate_account").click()
        sleep(1)
        alert = self.switch_to_alert()
        alert.accept()
        sleep(4)
        if SeleniumTest.DEV_LOGIN:
            parts[3]["success"] =\
                self.is_current_url(reverse("manage_dev_login")+"?next=/")
        else:
            parts[3]["success"] =\
                self.is_current_url(reverse("public_home"))
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
        
    ##########  Clicking OK sets the store's active 
    ###         field to false on Parse
    store.active = None
    parts[4]['success'] = not store.get("active")
    
    # undo
    store.active = True
    store.update()
    
    # END OF ALL TESTS - cleanup
    return self.tear_down()
예제 #22
0
def employee_is_owner(session, employee_id):
    account = Account.objects().get(Employee=employee_id)
    return SESSION.get_store(session).is_owner(account)
예제 #23
0
    def handle(self, *args, **options):
        # for logging when ran by CRON
        print "Running passed_user_limit: " + str(timezone.now())

        now = timezone.now()
        b4_now = now + relativedelta(hours=-1)

        # get 500 subscriptions at a time
        LIMIT = 500

        # first scan though all the stores and set their
        # date_passed_user_limit if so
        # TODO optimize with a relational query? possible with Parse?
        #### SUB_TYPE 0
        skip = 0
        sub_count = Subscription.objects().count(\
            date_passed_user_limit=None, subscriptionType=0)
        max_users = sub_type[0]['max_users']
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit=None, god_mode=False,
                limit=LIMIT, skip=skip, order="createdAt"):
                store = sub.store
                if store.get("patronStores", count=1, limit=0) >\
                    max_users:
                    sub.date_passed_user_limit = b4_now
                    sub.update()
                    # notify the dashboards of these changes
                    payload = {
                        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                        "updatedSubscription": sub.jsonify()
                    }
                    comet_receive(sub.Store, payload)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        # TODO optimize with a relational query? possible with Parse?
        #### SUB_TYPE 1
        skip = 0
        sub_count = Subscription.objects().count(\
            date_passed_user_limit=None, subscriptionType=1)
        max_users = sub_type[1]['max_users']
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit=None, god_mode=False,
                limit=LIMIT, skip=skip, order="createdAt"):
                store = sub.store
                if store.get("patronStores", count=1, limit=0) >\
                    max_users:
                    sub.date_passed_user_limit = b4_now
                    sub.update()
                    # notify the dashboards of these changes
                    payload = {
                        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                        "updatedSubscription": sub.jsonify()
                    }
                    comet_receive(sub.Store, payload)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ################
        conn = mail.get_connection(fail_silently=(not DEBUG))
        conn.open()
        # 1st day time range
        day1_end = now.replace()
        day1_start = day1_end + relativedelta(hours=-24)
        # 4th day time range
        day4_end = now + relativedelta(days=-4)
        day4_start = day4_end + relativedelta(hours=-24)
        # 8th day time range
        day8_end = now + relativedelta(days=-8)
        day8_start = day8_end + relativedelta(hours=-24)
        # 14th day time range
        day14_end = now + relativedelta(days=-14)
        day14_start = day14_end + relativedelta(hours=-24)

        #### SUB_TYPE 0
        ## 1st day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=0, date_passed_user_limit__lte=day1_end,
            date_passed_user_limit__gte=day1_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit__lte=day1_end,
                date_passed_user_limit__gte=day1_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                # with pp_cc_id
                if sub.pp_cc_id and len(sub.pp_cc_id) > 0:
                    sub.subscriptionType = 1
                    sub.date_passed_user_limit = None
                    sub.update()
                    # notify the dashboards of these changes
                    payload = {
                        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                        "updatedSubscription": sub.jsonify()
                    }
                    comet_receive(sub.Store, payload)
                    package = {
                        "status": "upgraded",
                        "sub_type": sub_type[0]["name"],
                        "new_sub_type": sub_type[1]["name"],
                        "new_sub_type_cost": sub_type[1]["monthly_cost"],
                        "new_max_patronStore_count":\
                            sub_type[1]["max_users"],
                        "patronStore_count": sub.store.get(\
                            "patronStores", limit=0, count=1),
                    }

                # no pp_cc_id
                else:
                    package = {
                        "sub_type": sub_type[0]["name"],
                        "max_patronStore_count": sub_type[0]["max_users"],
                        "patronStore_count": sub.store.get(\
                            "patronStores", limit=0, count=1),
                        "disable_date": sub.date_passed_user_limit +
                            relativedelta(days=\
                                USER_LIMIT_PASSED_DISABLE_DAYS),
                    }

                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 4th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=0, date_passed_user_limit__lte=day4_end,
            date_passed_user_limit__gte=day4_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit__lte=day4_end,
                date_passed_user_limit__gte=day4_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {
                    "sub_type": sub_type[0]["name"],
                    "max_patronStore_count": sub_type[0]["max_users"],
                    "patronStore_count": sub.store.get(\
                        "patronStores", limit=0, count=1),
                    "disable_date": sub.date_passed_user_limit +
                        relativedelta(days=\
                            USER_LIMIT_PASSED_DISABLE_DAYS),
                }
                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 8th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=0, date_passed_user_limit__lte=day8_end,
            date_passed_user_limit__gte=day8_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit__lte=day8_end,
                date_passed_user_limit__gte=day8_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {
                    "sub_type": sub_type[0]["name"],
                    "max_patronStore_count": sub_type[0]["max_users"],
                    "patronStore_count": sub.store.get(\
                        "patronStores", limit=0, count=1),
                    "disable_date": sub.date_passed_user_limit +
                        relativedelta(days=\
                            USER_LIMIT_PASSED_DISABLE_DAYS),
                }
                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 14th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=0, date_passed_user_limit__lte=day14_end,
            date_passed_user_limit__gte=day14_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=0, include="Store",
                date_passed_user_limit__lte=day14_end,
                date_passed_user_limit__gte=day14_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {"status": "disabled"}

                # deactivate the store
                sub.store.active = False
                sub.store.update()
                payload = {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "updatedStore": sub.store.jsonify(),
                }
                comet_receive(sub.Store, payload)

                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        #### SUB_TYPE 1
        ## 1st day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=1, date_passed_user_limit__lte=day1_end,
            date_passed_user_limit__gte=day1_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit__lte=day1_end,
                date_passed_user_limit__gte=day1_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                # with pp_cc_id
                if sub.pp_cc_id and len(sub.pp_cc_id) > 0:
                    sub.subscriptionType = 2
                    sub.date_passed_user_limit = None
                    sub.update()
                    # notify the dashboards of these changes
                    payload = {
                        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                        "updatedSubscription": sub.jsonify()
                    }
                    comet_receive(sub.Store, payload)
                    package = {
                        "status": "upgraded",
                        "sub_type": sub_type[1]["name"],
                        "new_sub_type": sub_type[2]["name"],
                        "new_sub_type_cost": sub_type[2]["monthly_cost"],
                        "new_max_patronStore_count": "Unlimited",
                        "patronStore_count": sub.store.get(\
                            "patronStores", limit=0, count=1),
                    }

                # no pp_cc_id
                else:
                    package = {
                        "sub_type": sub_type[1]["name"],
                        "max_patronStore_count": sub_type[1]["max_users"],
                        "patronStore_count": sub.store.get(\
                            "patronStores", limit=0, count=1),
                        "disable_date": sub.date_passed_user_limit +
                            relativedelta(days=\
                                USER_LIMIT_PASSED_DISABLE_DAYS),
                    }

                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 4th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=1, date_passed_user_limit__lte=day4_end,
            date_passed_user_limit__gte=day4_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit__lte=day4_end,
                date_passed_user_limit__gte=day4_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {
                    "sub_type": sub_type[1]["name"],
                    "max_patronStore_count": sub_type[1]["max_users"],
                    "patronStore_count": sub.store.get(\
                        "patronStores", limit=0, count=1),
                    "disable_date": sub.date_passed_user_limit +
                        relativedelta(days=\
                            USER_LIMIT_PASSED_DISABLE_DAYS),
                }
                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 8th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=1, date_passed_user_limit__lte=day8_end,
            date_passed_user_limit__gte=day8_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit__lte=day8_end,
                date_passed_user_limit__gte=day8_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {
                    "sub_type": sub_type[1]["name"],
                    "max_patronStore_count": sub_type[1]["max_users"],
                    "patronStore_count": sub.store.get(\
                        "patronStores", limit=0, count=1),
                    "disable_date": sub.date_passed_user_limit +
                        relativedelta(days=\
                            USER_LIMIT_PASSED_DISABLE_DAYS),
                }
                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        ## 14th day
        skip = 0
        sub_count = Subscription.objects().count(\
            subscriptionType=1, date_passed_user_limit__lte=day14_end,
            date_passed_user_limit__gte=day14_start)
        while sub_count > 0:
            for sub in Subscription.objects().filter(\
                subscriptionType=1, include="Store",
                date_passed_user_limit__lte=day14_end,
                date_passed_user_limit__gte=day14_start,
                limit=LIMIT, skip=skip, order="createdAt"):
                package = {"status": "disabled"}

                # deactivate the store
                sub.store.active = False
                sub.store.update()
                payload = {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "updatedStore": sub.store.jsonify(),
                }
                comet_receive(sub.Store, payload)

                try:
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)
                except SMTPServerDisconnected:
                    conn = mail.get_connection(fail_silently=(not DEBUG))
                    conn.open()
                    send_email_passed_user_limit(Account.objects().get(\
                        Store=sub.Store), sub.store, package, conn)

            # end of while loop
            sub_count -= LIMIT
            skip += LIMIT

        try:
            conn.close()
        except Exception:
            pass
예제 #24
0
def test_employee_access():
    """
    Tests for employee dashboard access.
    This tests any user with ACL of ACCESS_PUNCHREDEEM and NO_ACCESS.
    Tests for ACCESS_ADMIN are not necessary since all other tests
    involving the store owner covers it.
    """
    
    # delete the employees and associated User objects in the relation
    account = Account.objects().get(email=TEST_USER['username'],
        include="Store.Settings")
    store = account.store
    settings = store.settings
    
    emps = store.get("employees")
    if emps:
        for emp in emps:
            Account.objects().get(Employee=emp.objectId).delete()
            emp.delete()
    store.set("employees", None) 
        
    test = SeleniumTest()
    parts = [
        {"test_name" : "Pending employee has no access"},
        {"test_name" : "Approved employee initially not in store ACL"},
        {"test_name" : "Employee with ACCESS_NONE cannot login " +\
            "using  the login dialog"},
        {"test_name" : "Employee with ACCESS_NONE cannot login " +\
            "using the dedicated login page"},
        {"test_name" : "Employee with ACCESS_PUNCHREDEEM can " +\
            "login to the dashboard through the login dialog"},
        {"test_name" : "Employee with ACCESS_PUNCHREDEEM can " +\
            "login to the dashboard through the dedicated dialog pg"},
            
        {"test_name" : "Account settings accessible"},
        {"test_name" : "No store edit button"},
        {"test_name" : "Requesting edit store detail through url " +\
            "redirects user to store index"},
        {"test_name" : "No update subscription button"},
        {"test_name" : "Requesting update subscription through url " +\
            "redirects user to store index"},
        {"test_name" : "No deactivate my store button"},
        {"test_name" : "Requesting store deactivation through url " +\
            "redirects user to store index"},
            
        {"test_name" : "Rewards accessible"},
        {"test_name" : "No create new reward button"},
        {"test_name" : "Requesting create new reward through url " +\
            "redirects user to rewards index"},
        {"test_name" : "Rewards are not clickable"},
        {"test_name" : "Requesting edit reward through url " +\
            "redirects user to rewards index"},
            
        {"test_name" : "Messages accessible"},
        {"test_name" : "No create new message button"},
        {"test_name" : "Requesting create new message through url " +\
            "redirects user to messages index"},
        {"test_name" : "Sent messages are viewable"},
        {"test_name" : "Feedbacks are viewable"},
        {"test_name" : "No reply button"},
        {"test_name" : "Requesting reply through url " +\
            "redirects user to messages index"},
        {"test_name" : "No delete message button"},
        {"test_name" : "Requesting delete message through url " +\
            "redirects user to messages index"}, 
        
        {"test_name" : "Analysis accessible"},
        
        {"test_name" : "Employees accessible"},
        {"test_name" : "No register new employee button"},
        {"test_name" : "Requesting new employee registration"+\
            "redirects user to employees_index"},
        {"test_name" : "Approved employees are not clickable"},
        {"test_name" : "Requesting edit employee through url " +\
            "redirects user to employees index"},
        {"test_name" : "No remove button in approved employees"},
        {"test_name" : "Requesting remove employee through url " +\
            "redirects user to employees index"},
        {"test_name" : "No deny button in pending employees"},
        {"test_name" : "Requesting deny employee through url " +\
            "redirects user to employees index"},
        {"test_name" : "No approve button in pending employees"},
        {"test_name" : "Requesting approve employee through url " +\
            "redirects user to employees index"},
        
        {"test_name" : "Settings accessible"},
        {"test_name" : "No refresh button for retailer pin"},
        {"test_name" : "Requesting refresh through url returns " +\
            "a json object with error Permission denied"},
        {"test_name" : "Punches employee is readonly"},
        {"test_name" : "Punches facebook is readonly"},
        {"test_name" : "No save button"},
        {"test_name" : "No cancel changes button"},
            
        {"test_name" : "Workbench accessible"},
        {"test_name" : "Employee can punch"},
        {"test_name" : "Employee can reject redeem"},
        {"test_name" : "Employee can validate redeem"},
        
    ]
    section = {
        "section_name":\
            "Employee dashboard access working as expected?",
        "parts": parts,
    }
    test.results.append(section)
    
    try:
        # register the test employee
        register_employee("employee", "ex", TEST_EMPLOYEE['username'],
            TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'],
            settings.retailer_pin)
        sleep(3)
        employee_acc = Account.objects().get(username=TEST_EMPLOYEE[\
            'username'], include="Employee")
        employee = employee_acc.employee
    except Exception as e:
        print e
        
    ##########  Pending employee has no access 
    try:
        test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'],
            reverse("employees_index"))
        parts[0]['success'] =\
            test.find("#dialog-login-message").text ==\
            "You are not yet approved."
    except Exception as e:
        print e
        parts[0]['test_message'] = str(e)
        
    try:
        # login to approve
        test.login(TEST_USER['username'], TEST_USER['password'],
            reverse("employees_index"))
        # approve
        test.find("#tab-pending-employees").click()
        approveRow = test.find("#tab-body-pending-employees " +\
            "div.tr")
        approveRow.find_element_by_css_selector(\
            "div.td.approve a.approve").click()
        sleep(1)
        test.switch_to_alert().accept()
        sleep(2)
        test.logout()
    except Exception as e:
        print e
        
    ##########  Approved employee initially not in store ACL  
    try:
        # store.ACL = None cannot retrieve Parse built-ins!
        account = Account.objects().get(email=TEST_USER['username'],
            include="Store.Settings")
        store = account.store
        parts[1]['success'] = employee_acc.objectId not in store.ACL
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
        
    ##########  Employee with ACCESS_NONE cannot login 
    ###         using the login dialog 
    try:
        test.dev_login()
        test.login(TEST_EMPLOYEE['username'],
            TEST_EMPLOYEE['password'])
        parts[2]['success'] =\
            test.find("#dialog-login-message").text ==\
            "You do not have permission to access the dashboard."
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
        
    ##########  Employee with ACCESS_NONE cannot login 
    ###         using the dedicated login page 
    try:
        test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'],
            reverse("employees_index"))
        parts[3]['success'] =\
            test.find("#dialog-login-message").text ==\
            "You do not have permission to access the dashboard."
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
        
    ### Update the store's ACL
    store.ACL = {"*": {"read": True, "write": True}}
    store.set_access_level(employee_acc, ACCESS_PUNCHREDEEM[0])
    store.update()
    
    test.new_driver(False)
        
    ##########  Employee with ACCESS_PUNCHREDEEM can 
    ###         login to the dashboard through the login dialog
    try:
        test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'],
            final_sleep=6)
        parts[4]['success'] = test.is_current_url(reverse("store_index"))
        test.logout()
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)
        
    ##########  Employee with ACCESS_PUNCHREDEEM can 
    ###         login to the dashboard through the dedicated dialog page
    try:
        test.dev_login()
        test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'],
            reverse("employees_index"), final_sleep=6)
        parts[5]['success'] = test.is_current_url(reverse("employees_index"))
        sleep(4)
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
        
    ##########  Account settings accessible
    try:
        test.find("#header-right a").click()
        sleep(2)
        parts[6]['success'] = test.is_current_url(reverse("account_edit"))
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)
        
    ##########  No edit store detail button
    try:
        test.open(reverse("store_index"))
        sleep(2)
        test.set_to_implicit_wait(False)
        try: 
            test.find("#store-details a[href='%s']" % (reverse("store_edit"),))
        except NoSuchElementException:
            parts[7]['success'] = True
        
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting edit store detail through url 
    ###         redirects user to store details 
    try:
        test.open(reverse("store_edit"))
        sleep(2)
        parts[8]['success'] = test.is_current_url(reverse("store_index")+\
            "?" + urlencode({'error': "Permission denied"}))
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)
        
    ##########  No update subscription button 
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#account-options a[href='%s']" %\
                (reverse("subscription_update"),))
        except NoSuchElementException:
            parts[9]['success'] = True
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting update subscription through url 
    ###         redirects user to store index 
    try:
        test.open(reverse("subscription_update"))
        sleep(2)
        parts[10]['success'] = test.is_current_url(reverse(\
            "store_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
        
    ##########  No deactivate my store button 
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#deactivate_account")
        except NoSuchElementException:
            parts[11]['success'] = True
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting store deactivation through url 
    ###         redirects user to store index
    try:
        test.open(reverse("store_deactivate"))
        sleep(2)
        parts[12]['success'] = test.is_current_url(reverse(\
            "store_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)
        
    ##########  Rewards accessible
    try:
        test.open(reverse("rewards_index"))
        sleep(2)
        parts[13]['success'] = test.is_current_url(reverse("rewards_index"))
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)
        
    ##########  No create new reward button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#add_reward")
        except NoSuchElementException:
            parts[14]['success'] = True
        
    except Exception as e:
        print e
        parts[14]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting create new reward through url 
    ###         redirects user to rewards index
    try:
        test.open(reverse("reward_edit", args=(-1,)))
        sleep(2)
        parts[15]['success'] = test.is_current_url(reverse(\
            "rewards_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
        
    ##########  Rewards are not clickable
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("div.tr.reward a")
        except NoSuchElementException:
            parts[16]['success'] = True
            
    except Exception as e:
        print e
        parts[16]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting edit reward through url 
    ###         redirects user to rewards index
    try:
        test.open(reverse("reward_edit", args=\
            (int(test.find("div.tr.reward").get_attribute("id")),)))
        sleep(3)
        parts[17]['success'] = test.is_current_url(reverse(\
            "rewards_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
    except Exception as e:
        print e
        parts[17]['test_message'] = str(e)
        
    ##########  Messages accessible
    try:
        test.open(reverse("messages_index"))
        sleep(3)
        parts[18]['success'] = test.is_current_url(reverse(\
            "messages_index"))
    except Exception as e:
        print e
        parts[18]['test_message'] = str(e)
        
    ##########  No create new message button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#create_message")
        except NoSuchElementException:
            parts[19]['success'] = True
        
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting create new message through url 
    ###         redirects user to messages index
    try:
        test.open(reverse("message_edit", args=("0",)))
        sleep(3)
        parts[20]['success'] = test.is_current_url(reverse(\
            "messages_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
            
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
        
    ##########  Sent messages are viewable 
    try:
        row = test.find("#tab-body-sent div.tr a")
        # get id from /manage/messages/H1llFritVJ/details
        message_id = MESSAGE_DETAIL_RE.search(\
            row.get_attribute("href")).group(1)
        row.click()
        sleep(3)
        parts[21]['success'] = test.is_current_url(reverse(\
            "message_details", args=(message_id,)))
        
    except Exception as e:
        print e
        parts[21]['test_message'] = str(e)
        
    ##########  Feedbacks are viewable
    try:
        test.open(reverse("messages_index"))
        sleep(2)
        test.find("#tab-feedback").click()
        sleep(1)
        row = test.find("#tab-body-feedback div.tr a")
        # get id from /manage/messages/feedback/H1llFritVJ
        feedback_id = row.get_attribute("href").split("/")[-1]
        row.click()
        sleep(3)
        parts[22]['success'] = test.is_current_url(reverse(\
            "feedback_details", args=(feedback_id,)))
            
    except Exception as e:
        print e
        parts[22]['test_message'] = str(e)
        
    ##########  No reply button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#reply-button")
        except NoSuchElementException:
            parts[23]['success'] = True
        
    except Exception as e:
        print e
        parts[23]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting reply through url 
    ###         redirects user to messages index
    try:
        test.open(reverse("feedback_reply", args=(feedback_id,)))
        sleep(3)
        parts[24]['success'] = test.is_current_url(reverse(\
            "messages_index")+ "?" + urlencode({'error':\
            "Permission denied"}) + "&tab_feedback=1")
        
    except Exception as e:
        print e
        parts[24]['test_message'] = str(e)
        
    ##########  No delete message button
    try:
        test.open(reverse("feedback_details", args=(feedback_id,)))
        sleep(3)
        test.set_to_implicit_wait(False)
        try:
            test.find("#delete-button")
        except NoSuchElementException:
            parts[25]['success'] = True
        
    except Exception as e:
        print e
        parts[25]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting delete message through url 
    ###         redirects user to messages index 
    try:
        test.open(reverse("feedback_delete", args=(feedback_id,)))
        sleep(2)
        parts[26]['success'] = test.is_current_url(reverse(\
            "messages_index")+ "?" + urlencode({'error':\
            "Permission denied"}) + "&tab_feedback=1")
            
    except Exception as e:
        print e
        parts[26]['test_message'] = str(e)
    
    ##########  Analysis accessible
    try:
        test.open(reverse("analysis_index"))
        sleep(4)
        parts[27]['success'] = test.is_current_url(reverse(\
            "analysis_index"))
            
    except Exception as e:
        print e
        parts[27]['test_message'] = str(e)
    
    ##########  Employees accessible
    try:
        test.open(reverse("employees_index"))
        sleep(4)
        parts[28]['success'] = test.is_current_url(reverse(\
            "employees_index"))
            
    except Exception as e:
        print e
        parts[28]['test_message'] = str(e)
    
    ##########  No register new employee button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#register_employee")
        except NoSuchElementException:
            parts[29]['success'] = True
        
    except Exception as e:
        print e
        parts[29]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting new employee registration
    ###         redirects user to employees_index
    try:
        test.open(reverse("employee_register"))
        sleep(3)
        parts[30]['success'] = test.is_current_url(reverse(\
            "employees_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
            
    except Exception as e:
        print e
        parts[30]['test_message'] = str(e)
        
    ##########  Approved employees are not clickable
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#tab-body-approved-employees div.tr a")
        except NoSuchElementException:
            parts[31]['success'] = True
        
    except Exception as e:
        print e
        parts[31]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting edit employee through url 
    ###         redirects user to employees index
    try:
        row = test.find("#tab-body-approved-employees div.tr")
        employee_id = row.get_attribute("id")
        test.open(reverse("employee_edit", args=(employee_id,)))
        sleep(3)
        parts[32]['success'] = test.is_current_url(reverse(\
            "employees_index")+ "?" + urlencode({'error':\
            "Permission denied"}))

    except Exception as e:
        print e
        parts[32]['test_message'] = str(e)
        
    ##########  No remove button in approved employees
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#tab-body-approved-employees div.tr "+\
                "div.remove a")
        except NoSuchElementException:
            parts[33]['success'] = True
        
    except Exception as e:
        print e
        parts[33]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting remove employee through url 
    ###         redirects user to employees index
    try:
        test.open(reverse("employee_delete", args=(employee_id,)))
        sleep(3)
        parts[34]['success'] = test.is_current_url(reverse(\
            "employees_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
        
    except Exception as e:
        print e
        parts[34]['test_message'] = str(e)
        
    
    # create a pending 
    register_rand_employee(store.objectId)
    test.new_driver(False)
    test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'],
        reverse("employees_index"), final_sleep=6)
        
    ##########  No deny button in pending employees
    try:
        test.find("#tab-pending-employees").click()
        sleep(1)
        test.set_to_implicit_wait(False)
        try:
            test.find("#tab-body-pending-employees div.tr "+\
                "div.deny a")
        except NoSuchElementException:
            parts[35]['success'] = True
            
    except Exception as e:
        print e
        parts[35]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting deny employee through url 
    ###         redirects user to employees index
    try:
        test.find("#tab-pending-employees").click()
        row = test.find("#tab-body-pending-employees div.tr")
        employee_id = row.get_attribute("id")
        test.open(reverse("employee_deny", args=(employee_id,)))
        sleep(3)
        parts[36]['success'] = test.is_current_url(reverse(\
            "employees_index") + "?" + urlencode({'error':\
            "Permission denied"}))
            
    except Exception as e:
        print e
        parts[36]['test_message'] = str(e)
        
    ##########  No approve button in pending employees
    try:
        test.find("#tab-pending-employees").click()
        sleep(1)
        test.set_to_implicit_wait(False)
        try:
            test.find("#tab-body-pending-employees div.tr "+\
                "div.approve a")
        except NoSuchElementException:
            parts[37]['success'] = True
            
    except Exception as e:
        print e
        parts[37]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting approve employee through url 
    ###         redirects user to employees index 
    try:
        test.open(reverse("employee_approve", args=(employee_id,)))
        sleep(3)
        parts[38]['success'] = test.is_current_url(reverse(\
            "employees_index") + "?" + urlencode({'error':\
            "Permission denied"}))
            
    except Exception as e:
        print e
        parts[38]['test_message'] = str(e)
    
    ##########  Settings accessible
    try:
        test.open(reverse("store_settings"))
        sleep(3)
        parts[39]['success'] = test.is_current_url(reverse(\
            "store_settings"))
            
    except Exception as e:
        print e
        parts[39]['test_message'] = str(e)
        
    ##########  No refresh button for retailer pin
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#link_refresh_retailer_pin")
        except NoSuchElementException:
            parts[40]['success'] = True
        
    except Exception as e:
        print e
        parts[40]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Requesting refresh through url returns 
    ###         a json object with error Permission denied
    try:
        test.open(reverse("refresh_retailer_pin"))
        sleep(3)
        parts[41]['success'] = "Permission denied" in\
            test.driver.page_source
    except Exception as e:
        print e
        parts[41]['test_message'] = str(e)
        
    ##########  Punches employee is readonly
    try:
        test.open(reverse("store_settings"))
        sleep(3)
        parts[42]['success'] =\
            test.find("#id_punches_employee").get_attribute(\
                "readonly") == "true"
    except Exception as e:
        print e
        parts[42]['test_message'] = str(e)
        
    ##########  Punches facebook is readonly
    try:
        parts[43]['success'] =\
            test.find("#id_punches_facebook").get_attribute(\
                "readonly") == "true"
    except Exception as e:
        print e
        parts[43]['test_message'] = str(e)
        
    ##########  No save button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#settings-form-submit")
        except NoSuchElementException:
            parts[44]['success'] = True
        
    except Exception as e:
        print e
        parts[44]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  No cancel changes button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#settings-options a.red")
        except NoSuchElementException:
            parts[45]['success'] = True
            
    except Exception as e:
        print e
        parts[45]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)
        
    ##########  Workbench accessible
    try:
        test.open(reverse("workbench_index"))
        sleep(3)
        parts[46]['success'] = test.is_current_url(\
            reverse("workbench_index"))
    except Exception as e:
        print e
        parts[46]['test_message'] = str(e)
        
    ##########  Employee can punch
    try:
        test.find("#punch_code").send_keys("00010")
        test.find("#punch_amount").send_keys("1")
        test.find("#punch-form a.button.blue").click()
        sleep(2)
        parts[47]['success'] =\
            test.find(".notification.hide") is not None
    except Exception as e:
        print e
        parts[47]['test_message'] = str(e)
        
    ##########  Employee can reject redeem 
    try:
        request_redeem_ps("eiZa6Mzu7f")
        sleep(COMET_PULL_RATE*2+4)
        row = test.find("#tab-body-pending-redemptions div.tr")
        test.find("//div[@id='%s']/" % (row.get_attribute("id"),) +\
            "div[contains(@class, 'redemption_redeem')]/a[2]",
            type="xpath").click()
        sleep(3)
        parts[48]['success'] = row.text.__contains__("Successfully")
    except Exception as e:
        print e
        parts[48]['test_message'] = str(e)
        
    ##########  Employee can validate redeem
    try:
        request_redeem_ps("eiZa6Mzu7f")
        sleep(COMET_PULL_RATE*2+4)
        row = test.find("#tab-body-pending-redemptions div.tr")
        test.find("//div[@id='%s']/" % (row.get_attribute("id"),) +\
            "div[contains(@class, 'redemption_redeem')]/a[1]",
            type="xpath").click()
        sleep(3)
        parts[49]['success'] = row.text.__contains__("Successfully")
    except Exception as e:
        print e
        parts[49]['test_message'] = str(e)


    # END OF ALL TESTS - cleanup
    return test.tear_down() 
예제 #25
0
def test_feedbacks():
    """
    This test also tests cloud code send_feedback.
    """
    # we can clear the list locally but just re-pull from parse
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store.Subscription")
    store = account.store
    subscription = store.subscription

    account = Account.objects().get(username=TEST_PATRON['username'],
                                    include="Patron")
    patron = account.patron

    # make sure that the account is not used for these tests
    account = None

    # clear the received messages relation
    received_messages = store.get("receivedMessages", keys="")
    if received_messages:
        store.remove_relation("ReceivedMessages_",
                              [m.objectId for m in received_messages])

    store.set("receivedMessages", None)

    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Cloud code send_feedback works"},
        {'test_name': "Notification badge appears if there are" +\
            " unread feedbacks"},
        {'test_name': "A new row appears when feedback is received"},
        {'test_name': "Feedback is initially unread (dashboard)"},
        {'test_name': "Feedback is in store's ReceivedMessages " +\
            "relation and is initially unread"},
        {'test_name': "Clicking the row redirects user to the " +\
            "feedback detail page"},
        {'test_name': "Clicking back to feedback inbox redirects " +\
            "user back to messages index with feedback tab active"},
        {'test_name': "Feedback is now read (dashboard)"},
        {'test_name': "Feedback is now read (Parse)"},
        {'test_name': "Clicking reply redirects user to feedback " +\
            "reply page"},
        {'test_name': "Reply body is required."},
        {'test_name': "Replying redirects user back to feedback " +\
            "details"},
        {'test_name': "The reply is visible"},
        {'test_name': "The reply message is saved in the store's " +\
            "sent messages relation with message_type of feedback"},
        {'test_name': "The reply message is saved in the Patron's " +\
            "received messages relation wrapped in a Message Status"},
        {'test_name': "A feedback with a reply does not have a " +\
            "reply button"},
        {'test_name': "Clicking delete message prompts the user " +\
            "to confirm the deletion"},
        {'test_name': "The user is redirected to messages index " +\
            "with feedback tab active"},
        {'test_name': "Deleting the reply only removes the message" +\
            " from the store's sent messages relation"},
        {'test_name': "The deleted feedback is no longer in " +\
            "the table"},
        {'test_name': "Multiple feedbacks (testing 3 here) " +\
            "can appear at the same time"},
    ]
    section = {
        "section_name": "Receiving messages works?",
        "parts": parts,
    }
    test.results.append(section)

    ##########  User needs to be logged in to access page
    test.open(reverse("messages_index"))  # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("messages_index"))

    # login
    selectors = (("#login_username", TEST_USER['username']),
                 ("#login_password", TEST_USER['password']), ("", Keys.RETURN))
    test.action_chain(0, selectors, "send_keys")  # ACTION!
    sleep(5)

    def send_feedback(subject, body):
        """ This is a consumer action - not dashboard """
        return cloud_call(
            "send_feedback", {
                "store_id": store.objectId,
                "patron_id": patron.objectId,
                "sender_name": patron.get_fullname(),
                "subject": subject,
                "body": body,
            })

    def feedback_id(feedback_tr):
        return feedback_tr.find_element_by_css_selector(\
            "a").get_attribute("href").split("/")[-1]

    def feedback_unread(feedback_tr):
        """ check parse if the fb is unread """
        fb_id = feedback_id(feedback_tr)
        store.set("receivedMessages", None)
        msg = store.get("receivedMessages", objectId=fb_id)
        if msg and len(msg) > 0:
            return not msg[0].is_read

        return False

    ##########  Cloud code send_feedback works
    try:
        parts[1]['success'] = send_feedback(
            "feedback #1", "body #1").get("result") == "success"
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)

    ##########  Notification badge appears if there are
    ###         unread feedbacks
    try:
        sleep(COMET_PULL_RATE * 2 + 2)
        parts[2]['success'] = test.element_exists("#messages-nav " +\
            "a div.nav-item-badge")
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)

    ##########  A new row appears when feedback is received
    try:
        test.find("#tab-feedback").click()
        feedbacks =\
            test.find("#tab-body-feedback div.tr", multiple=True)
        parts[3]['success'] = len(feedbacks) > 0
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
    ##########  Feedback is initially unread (dashboard)
    try:
        parts[4]['success'] =\
            feedbacks[0].get_attribute("class").__contains__("unread")
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)

    ##########  Feedback is in store's ReceivedMessages
    ###         relation and is initially unread
    try:
        parts[5]['success'] = feedback_unread(feedbacks[0])
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
    ##########  Clicking the row redirects user to the
    ###         feedback detail page
    try:
        fb_id = feedback_id(feedbacks[0])
        feedbacks[0].find_element_by_css_selector("a").click()
        sleep(2)
        parts[6]['success'] = test.is_current_url(reverse(\
            "feedback_details", args=(fb_id,)))
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)
    ##########  Clicking back to feedback inbox redirects
    ###         user back to messages index with feedback tab active
    try:
        test.find("#back_to_feedback").click()
        sleep(1)
        parts[7]['success'] =\
            test.find("#tab-feedback").get_attribute(\
            "class").__contains__("active")
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
    ##########  Feedback is now read (dashboard)
    try:
        feedbacks =\
            test.find("#tab-body-feedback div.tr", multiple=True)
        parts[8]['success'] =  not feedbacks[0].get_attribute(\
            "class").__contains__("unread")
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)
    ##########  Feedback is now read (Parse)
    try:
        parts[9]['success'] = not feedback_unread(feedbacks[0])
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
    ##########  Clicking reply redirects user to feedback reply page
    try:
        fb_id = feedback_id(feedbacks[0])
        feedbacks[0].find_element_by_css_selector("a").click()
        sleep(2)
        test.find("#reply-button").click()
        sleep(1)
        parts[10]['success'] = test.is_current_url(reverse(\
            "feedback_reply", args=(fb_id,)))
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    ##########  Reply body is required.
    try:
        test.find("#body").send_keys("     ")
        test.find("#reply-form-submit").click()
        sleep(2)
        parts[11]['success'] = test.find("div.notification.hide " +\
            "div").text == "Please enter a message."
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
    ##########  Replying redirects user back to feedback details
    try:
        test.find("#body").send_keys("Hey")
        test.find("#reply-form-submit").click()
        parts[12]['success'] = test.is_current_url(reverse(\
            "feedback_details", args=(fb_id,)) +\
            "?%s" % urlencode({'success':\
            'Reply has been sent.'}))
        sleep(5)
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)
    ##########  The reply is visible
    try:
        parts[13]['success'] = test.find("#reply-box " +\
            "div.sect.body").text == "Hey"
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)
    ##########  The reply message is saved in the store's
    ###         sent messages relation with message_type of feedback
    try:
        test.find("#back_to_feedback").click()
        sleep(1)
        store.set("sentMessages", None)
        store.set("receivedMessages", None)
        parts[14]['success'] = len(
            store.get("sentMessages",
                      objectId=store.get("receivedMessages",
                                         objectId=fb_id)[0].Reply,
                      message_type=FEEDBACK)) > 0
    except Exception as e:
        print e
        parts[14]['test_message'] = str(e)
    ##########  The reply message is saved in the Patron's
    ###         received messages relation wrapped in a Message Status
    try:
        patron.set("receivedMessages", None)
        parts[15]['success'] = len(
            patron.get("receivedMessages", Message=fb_id)) > 0
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    ##########  A feedback with a reply does not have a reply button
    try:
        feedbacks =\
            test.find("#tab-body-feedback div.tr", multiple=True)
        feedbacks[0].find_element_by_css_selector("a").click()
        sleep(2)
        parts[16]['success'] = not test.element_exists(\
            "#reply-form-submit")
    except Exception as e:
        print e
        parts[16]['test_message'] = str(e)
    ##########  Clicking delete message prompts the user
    ###         to confirm the deletion
    try:
        test.find("#delete-button").click()
        sleep(1)
        alert = test.switch_to_alert()
        parts[17]['success'] = alert.text ==\
            "Are you sure you want to delete this feedback thread?"
    except Exception as e:
        print e
        parts[17]['test_message'] = str(e)
    ##########  The user is redirected to messages index
    ###         with feedback tab active
    try:
        alert.accept()
        sleep(4)
        parts[18]['success'] =\
            test.find("#tab-feedback").get_attribute(\
            "class").__contains__("active")
    except Exception as e:
        print e
        parts[18]['test_message'] = str(e)
    ##########  Deleting the reply only removes the message
    ###         from the store's sent messages relation
    try:
        store.set("receivedMessages", None)
        parts[19]['success'] = not store.get(
            "receivedMessages", objectId=fb_id, message_type=FEEDBACK)
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
    ##########  The deleted feedback is no longer in the table
    try:
        test.find("#tab-feedback").click()
        sleep(1)
        feedbacks =\
            test.find("#tab-body-feedback div.tr a[href='%s']" %\
                (fb_id,), multiple=True)
        parts[20]['success'] = len(feedbacks) == 0
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    ##########  Multiple feedbacks (testing 3 here)
    ###         can appear at the same time
    try:
        send_feedback("feedback #2", "body #2")
        send_feedback("feedback #3", "body #3")
        send_feedback("feedback #4", "body #4")
        sleep(COMET_PULL_RATE * 3 + 4)
        feedbacks =\
            test.find("#tab-body-feedback div.tr a", multiple=True)
        parts[21]['success'] = len(feedbacks) == 3
    except Exception as e:
        print e
        parts[21]['test_message'] = str(e)

    # END OF ALL TESTS - cleanup
    return test.tear_down()
예제 #26
0
def test_messages():
    # TODO test that patrons are getting the messages!!!
    # setup
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store.Subscription")
    store = account.store
    subscription = store.subscription

    # set subscriptionType to free
    subscription.subscriptionType = 0
    subscription.update()

    # clear the sent messages relation
    sent_messages = store.get("sentMessages", keys="")
    if sent_messages:
        store.remove_relation("SentMessages_",
                              [m.objectId for m in sent_messages])

    store.set("sentMessages", None)

    # we can clear the list locally but just re-pull from parse
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store.Subscription")
    store = account.store
    subscription = store.subscription

    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},

        # FIRST
        {'test_name': "Send message. Filter all. No offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SECOND
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # THIRD
        {'test_name': "Send message. Filter idle. No offer. " +\
            "Message limit passed (free) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Upgrading account from the dialog sends the " +\
            "message and upgrades the account to middle"},
        {'test_name': "Email is sent notifying user the upgrade"},
        #
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # FOURTH
        {'test_name': "Send message. Filter idle. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # FIFTH
        {'test_name': "Send message. Filter most_loyal. No offer. " +\
            "Message limit passed (middle) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Upgrading account from the dialog sends the" +\
            " message and upgrades the account to heavy"},
        {'test_name': "Email is sent notifying user the upgrade"},
        #
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SIXTH
        {'test_name': "Send message. Filter most_loyal. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # SEVENTH
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # EIGHTH
        {'test_name': "Send message. Filter all. With offer"},
        {'test_name': "Message is in store's sentMessages relation"},
        {'test_name': "Message is visible in page"},
        {'test_name': "Message can be view by clicking on row"},
        # NINTH
        {'test_name': "Send message. Filter all. No offer. " +\
            "Message limit passed (heavy) dialog appears"},
        # LIMIT PASSED
        {'test_name': "Account can no longer be upgraded." +\
            "Message cannot be sent. Clicking okay redirects "+\
            "user to messages index."},
        #

        {'test_name': "Subject is required"},
        {'test_name': "Body is required"},
        {'test_name': "Offer title not required if attach offer off"},
        {'test_name': "Expiration not required if attach offer off"},
        {'test_name': "Offer title is required if attach offer on"},
        {'test_name': "Expiration date required if attach offer on"},
        {'test_name': "Expiration date must be at a later date"},
        {'test_name': "Expiration date must be at most 1 year later"},
    ]
    section = {
        "section_name": "Sending messages works?",
        "parts": parts,
    }
    test.results.append(section)

    ##########  User needs to be logged in to access page
    test.open(reverse("messages_index"))  # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("messages_index"))

    # login
    selectors = (("#login_username", TEST_USER['username']),
                 ("#login_password", TEST_USER['password']), ("", Keys.RETURN))
    test.action_chain(0, selectors, "send_keys")  # ACTION!
    sleep(5)

    def send_message(
        filter,
        subject,
        body,
        attach_offer=False,
        offer_title=None,
        exp_date=None,
    ):
        """ Must be called at messages index page """
        test.find("#create_message").click()
        sleep(1)
        # set the filter
        test.find("//select[@id='filter']/option[@value='%s']" %\
            (filter,), type="xpath").click()
        # subject
        test.find("#id_subject").send_keys(subject)
        # body
        test.find("#id_body").send_keys(body)
        # attach_offer
        if attach_offer:
            test.find("#id_attach_offer").click()
            # offer title
            if offer_title:
                test.find("#id_offer_title").send_keys(offer_title)
            # exp_date
            if exp_date:
                test.find("#id_date_offer_expiration").send_keys(exp_date)

        # submit
        test.find("#send-now").click()
        sleep(5)

    def message_in_relation(message_id, test_number):
        if not message_id:
            return

        store.sentMessages = None
        parts[test_number]['success'] = store.get("sentMessages",
                                                  objectId=message_id,
                                                  count=1,
                                                  limit=0) == 1

    def message_in_page(message_id, test_number):
        if not message_id:
            return

        try:
            rows = test.find("#tab-body-sent div.tr a", multiple=True)
            for row in rows:
                if row.get_attribute("href").split("/")[5] ==\
                    message_id:
                    parts[test_number]['success'] = True
        except Exception as e:
            print e
            parts[test_number]['test_message'] = str(e)

    def message_viewable(message_id, test_number):
        if not message_id:
            return
        href = reverse("message_details", args=(message_id, ))
        try:
            test.find("#tab-body-sent div.tr a[href='%s']" %\
                (href,)).click()
            sleep(2)
            parts[test_number]['success'] = test.is_current_url(href)
        except Exception as e:
            print e
            parts[test_number]['test_message'] = str(e)
        finally:
            # must go back to messages index for the other tests
            test.open(reverse("messages_index"))

    # FIRST
    ##########  Send message. Filter all. No offer.
    message_id = None
    try:
        send_message("all", "msg #1", "body #1")
        parts[1]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))

    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 2)
    ##########  Message is visible in page.
    message_in_page(message_id, 3)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 4)

    # SECOND
    ##########  Send message. Filter all. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #2", "body #2", True, "offer#2",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[5]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 6)
    ##########  Message is visible in page.
    message_in_page(message_id, 7)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 8)

    # THIRD
    ##########  Send message. Filter idle. No offer.
    ###         Message limit passed (free) dialog appears.
    message_id = None
    try:
        send_message("idle", "msg #3", "body #3")
        parts[9]['success'] = test.find("#upgrade") is not None
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Upgrading account from the dialog sends the
    ###         message and upgrades the account to middle.
    try:
        test.find("#upgrade").click()
        sleep(2)
        test.find("#id_cc_cvv").send_keys("123")
        test.find("#id_recurring").click()
        test.find("#update-form-submit").click()
        sleep(5)
        message_id = test.driver.current_url.split("/")[5]
        subscription.subscriptionType = None
        parts[10]['success'] = test.is_current_url(\
            reverse("message_details", args=(message_id,))) and\
            subscription.get("subscriptionType") == 1
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))

    # open the mail connection
    if SeleniumTest.CHECK_SENT_MAIL:
        mail = Mail()
        ##########  Email is sent notifying user the upgrade.
        try:
            parts[11]['success'] = mail.is_mail_sent(\
                EMAIL_UPGRADE_SUBJECT)
        except Exception as e:
            print e
            parts[11]['test_message'] = str(e)
    else:
        parts[11]['success'] = parts[10]['success']

    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 12)
    ##########  Message is visible in page.
    message_in_page(message_id, 13)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 14)

    # FOURTH
    ##########  Send message. Filter idle. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("idle", "msg #4", "body #4", True, "offer#4",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[15]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 16)
    ##########  Message is visible in page.
    message_in_page(message_id, 17)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 18)

    # FIFTH
    ##########  Send message. Filter most_loyal. No offer.
    ###         Message limit passed (free) dialog appears.
    message_id = None
    try:
        send_message("most_loyal", "msg #5", "body #5")
        parts[19]['success'] = test.find("#upgrade") is not None
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Upgrading account from the dialog sends the
    ###         message and upgrades the account to heavy.
    try:
        test.find("#upgrade").click()
        sleep(2)
        test.find("#id_cc_cvv").send_keys("123")
        test.find("#id_recurring").click()
        test.find("#update-form-submit").click()
        sleep(5)
        message_id = test.driver.current_url.split("/")[5]
        subscription.subscriptionType = None
        parts[20]['success'] = test.is_current_url(\
            reverse("message_details", args=(message_id,))) and\
            subscription.get("subscriptionType") == 2
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Email is sent notifying user the upgrade.
    if SeleniumTest.CHECK_SENT_MAIL:
        try:
            parts[21]['success'] = mail.is_mail_sent(\
                EMAIL_UPGRADE_SUBJECT)
        except Exception as e:
            print e
            parts[21]['test_message'] = str(e)
    else:
        parts[21]['success'] = parts[20]['success']

    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 22)
    ##########  Message is visible in page.
    message_in_page(message_id, 23)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 24)

    # SIXTH
    ##########  Send message. Filter most_loyal. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("most_loyal", "msg #6", "body #6", True, "offer#6",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[25]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[25]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 26)
    ##########  Message is visible in page.
    message_in_page(message_id, 27)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 28)

    # SEVENTH
    ##########  Send message. Filter all. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #7", "body #7", True, "offer#7",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[29]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[29]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 30)
    ##########  Message is visible in page.
    message_in_page(message_id, 31)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 32)

    # EIGHTH
    ##########  Send message. Filter all. With offer.
    message_id = None
    try:
        exp_date = timezone.now() + relativedelta(days=1)
        send_message("all", "msg #8", "body #8", True, "offer#8",
                     exp_date.strftime(DATE_PICKER_STRFTIME))
        parts[33]['success'] = len(test.find(\
            "div.notification.success", multiple=True)) > 0
        message_id = test.driver.current_url.split("/")[5]
    except Exception as e:
        print e
        parts[33]['test_message'] = str(e)
    finally:  # must go back to messages index
        test.open(reverse("messages_index"))
    ##########  Message is in store's sentMessages relation.
    message_in_relation(message_id, 34)
    ##########  Message is visible in page.
    message_in_page(message_id, 35)
    ##########  Message can be view by clicking on row.
    message_viewable(message_id, 36)

    # NINTH
    ##########  Send message. Filter all. With offer.
    ###         Message limit passed (heavy) dialog appears.
    message_id = None
    try:
        send_message("all", "msg #9", "body #9")
        parts[37]['success'] = test.element_exists("#maxed_out")
    except Exception as e:
        print e
        parts[37]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    # LIMIT PASSED
    ##########  Account can no longer be upgraded. Msg cannot be sent.
    ###         Clicking Okay redirects user to messages index.
    try:
        test.find("#maxed_out").click()
        sleep(1)
        parts[38]['success'] =\
            test.is_current_url(reverse("messages_index"))
    except Exception as e:
        print e
        parts[38]['test_message'] = str(e)
        test.open(reverse("messages_index"))
    #

    # goto edit message page
    test.find("#create_message").click()
    sleep(2)

    selectors = (
        ("#id_subject", "   "),
        ("#id_body", "   "),
    )
    test.action_chain(0, selectors, action="send_keys")
    test.find("#send-now").click()
    sleep(1)
    ##########  Subject is required.
    try:
        parts[39]['success'] = test.find("#subject_e ul li").text ==\
            "This field is required."
    except Exception as e:
        print e
        parts[39]['test_message'] = str(e)
    ##########  Body is required.
    try:
        parts[40]['success'] = test.find("#body_e ul li").text ==\
            "This field is required."
    except Exception as e:
        print e
        parts[40]['test_message'] = str(e)
    ##########  Offer title not required if attach offer off.
    try:
        parts[41]['success'] = not test.element_exists(\
            "#offer_title_e ul li")
    except Exception as e:
        print e
        parts[41]['test_message'] = str(e)
    ##########  Expiration not required if attach offer off.
    try:
        parts[42]['success'] = not test.element_exists(\
            "#date_offer_expiration_e ul li")
    except Exception as e:
        print e
        parts[42]['test_message'] = str(e)

    test.find("#id_attach_offer").click()
    test.find("#send-now").click()
    sleep(1)
    ##########  Offer title is required if attach offer on.
    try:
        parts[43]['success'] =\
            test.find("#offer_title_e ul li").text ==\
            "Please enter a title."
    except Exception as e:
        print e
        parts[43]['test_message'] = str(e)
    ##########  Expiration date required if attach offer on.
    try:
        parts[44]['success'] =\
            test.find("#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date."
    except Exception as e:
        print e
        parts[44]['test_message'] = str(e)

    ##########  Expiration date must be at a later date.
    try:
        # don't click attach offer again!
        # test.find("#id_attach_offer").click()
        exp_date = timezone.now() + relativedelta(days=-1)
        test.find("#id_date_offer_expiration").send_keys(\
            exp_date.strftime(DATE_PICKER_STRFTIME))
        test.find("#send-now").click()
        sleep(1)
        parts[45]['success'] = test.find(\
            "#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date that is later than today."
    except Exception as e:
        print e
        parts[45]['test_message'] = str(e)

    ##########  Expiration date must be at most 1 year later.
    try:
        # don't click attach offer again!
        # test.find("#id_attach_offer").click()
        exp_date = timezone.now() + relativedelta(days=367)
        date_offer = test.find("#id_date_offer_expiration")
        date_offer.clear()
        date_offer.send_keys(\
            exp_date.strftime(DATE_PICKER_STRFTIME))
        test.find("#send-now").click()
        sleep(2)
        parts[46]['success'] = test.find(\
            "#date_offer_expiration_e ul li").text ==\
            "Please enter an expiration date that is less than a year."
    except Exception as e:
        print e
        parts[46]['test_message'] = str(e)

    # END OF ALL TESTS - cleanup
    if SeleniumTest.CHECK_SENT_MAIL:
        mail.logout()

    return test.tear_down()
예제 #27
0
def test_rewards():
    # setup
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store")
    store = account.store
    # start with no rewards
    store.rewards = []
    store.update()

    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Having no rewards shows a placeholder row"},
        {'test_name': "Adding a reward works"},
        {'test_name': "The new reward is saved to parse"},
        {'test_name': "Redemption count starts at 0"},
        {'test_name': "Reward id starts at 0"},
        {'test_name': "Updating a reward works"},
        {'test_name': "The updated reward is saved to parse"},
        {'test_name': "The updated reward retains the reward_id"},
        {'test_name': "The updated reward retains the " +\
            "redemption_count"},
        {'test_name': "Clicking delete brings up a confirmation " +\
            "dialog"},
        {'test_name': "Deleting a reward works"},
        {'test_name': "The deleted reward is deleted from parse"},
        {'test_name': "Reward name is required"},
        {'test_name': "Punches is required"},
        {'test_name': "Description is not required"},
        {'test_name': "Clicking cancel redirects user " +\
            "back to rewards index"},
        {'test_name': "Punches must be a number"},
        {'test_name': "Punches must be greater than 0"},
        {'test_name': "Rewards are initially sorted by Punches " +\
            "from least to greatest"},
        {'test_name': "Punches is sortable"},
        {'test_name': "Name is sortable"},
        {'test_name': "Updating a reward with the reset redemption" +\
            " count option resets the redemption count to 0"},
    ]
    section = {
        "section_name": "Rewards page working properly?",
        "parts": parts,
    }
    test.results.append(section)

    ##########  User needs to be logged in to access page
    test.open(reverse("rewards_index"))  # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("rewards_index"))

    # login
    selectors = (("#login_username", TEST_USER['username']),
                 ("#login_password", TEST_USER['password']), ("", Keys.RETURN))
    test.action_chain(0, selectors, "send_keys")  # ACTION!
    sleep(7)

    ##########  Having no rewards shows a placeholder row
    try:
        parts[1]['success'] =\
            test.find("//div[@id='rewards_section']/div[@class=" +\
            "'tr reward']/div[@class='td reward_summary']/span[1]",
            type="xpath").text == "No Rewards"
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)

    def add_reward(name, description, punches):
        test.find("#add_reward").click()
        sleep(1)
        selectors = (
            ("#id_reward_name", name),
            ("#id_description", description),
            ("#id_punches", str(punches)),
        )
        test.action_chain(0, selectors, action="send_keys")
        test.find("#submit-reward-form").click()
        sleep(5)

    reward1_name = "Reward #1"
    reward1_description = "First reward"
    reward1_punches = 5
    ##########  Adding a reward works
    try:
        add_reward(reward1_name, reward1_description, reward1_punches)
        parts[2]['success'] = test.find("//div[@id='0']/a/div[2]" +\
            "/span[1]", type="xpath").text == reward1_name
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
    ##########  The new reward is saved to parse
    try:
        store.rewards = None
        reward = store.get("rewards")[0]
        parts[3]['success'] = reward['reward_name'] ==\
            reward1_name and reward['description'] ==\
            reward1_description and\
            reward['punches'] == reward1_punches
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
    ##########  Redemption count starts at 0
    try:
        parts[4]['success'] = reward['redemption_count'] == 0
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)

    ##########  Redemption count starts at 0
    try:
        parts[5]['success'] = reward['reward_id'] == 0
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)

    # let's add 3 more rewards!
    reward2_name = "reward dos"
    reward2_description = "DOS"
    reward2_punches = 10
    reward3_name = "reward tres"
    reward3_description = "TRES"
    reward3_punches = 12
    reward4_name = "reward quatro"
    reward4_description = "QUATRO"
    reward4_punches = 15

    add_reward(reward2_name, reward2_description, reward2_punches)
    add_reward(reward3_name, reward3_description, reward3_punches)
    add_reward(reward4_name, reward4_description, reward4_punches)
    ################

    reward1_name = "reward uno"
    reward1_description = "UNO"
    reward1_punches = 1
    ##########  Updating a reward works
    try:
        test.find("//div[@id='0']/a", type="xpath").click()
        sleep(1)
        selectors = (
            ("#id_reward_name", reward1_name),
            ("#id_description", reward1_description),
            ("#id_punches", str(reward1_punches)),
        )
        test.action_chain(0, selectors, action="clear")
        test.action_chain(0, selectors, action="send_keys")
        test.find("#submit-reward-form").click()
        sleep(4)
        parts[6]['success'] = test.find("//div[@id='0']/a/div[2]" +\
            "/span[1]", type="xpath").text == reward1_name
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)
    ##########  The updated reward is saved to parse
    try:
        store.rewards = None
        reward = store.get("rewards")[0]  # list is sorted by punches
        parts[7]['success'] = reward['reward_name'] ==\
            reward1_name and\
            reward['description'] == reward1_description and\
            reward['punches'] == reward1_punches
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
    ##########  The updated reward retains the reward_id
    try:
        parts[8]['success'] = reward['reward_id'] == 0
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)
    ##########  The updated reward retains the redemption_count
    try:
        parts[9]['success'] = reward['redemption_count'] == 0
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
    ##########  Clicking delete brings up a confirmation dialog
    try:
        test.find("//div[@id='0']/a", type="xpath").click()
        sleep(1)
        test.find("#delete-link").click()
        alert = test.switch_to_alert()
        parts[10]['success'] = alert is not None
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    ##########  Deleting a reward works
    try:
        alert.accept()
        sleep(5)
        parts[11]['success'] = test.find("//div[@id='1']/a/div[2]" +\
            "/span[1]", type="xpath").text == reward2_name
        try:  # first reward should be gone
            test.find("//div[@id='0']/a/div[2]" +\
                "/span[1]", type="xpath").text
        except Exception:
            parts[11]['success'] = parts[11]['success']
        else:
            parts[11]['success'] = False
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
    ##########  The deleted reward is deleted from parse
    try:
        store.rewards = None
        rewards = store.get("rewards")
        parts[12]['success'] = reward1_name not in\
            [r['reward_name'] for r in rewards] and\
            0 not in [r['reward_id'] for r in rewards]
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)

    # field required
    add_reward("   ", "", "")

    ##########  Reward name is required
    try:
        parts[13]['success'] =\
            test.find("#reward_name_ic ul li").text ==\
                "This field is required."
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)
    ##########  Punches is required
    try:
        parts[14]['success'] =\
            test.find("#punches_ic ul li").text ==\
                "This field is required."
    except Exception as e:
        print e
        parts[14]['test_message'] = str(e)
    ##########  Description is not required
    try:
        parts[15]['success'] =\
            not test.element_exists("#description_ic ul li")
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    ##########  Clicking cancel redirects user back to rewards index
    try:
        test.find("//div [@id='edit-reward-options']/a[2]",
                  type="xpath").click()
        sleep(2)
        parts[16]['success'] =\
            test.is_current_url(reverse("rewards_index"))
    except Exception as e:
        print e
        parts[16]['test_message'] = str(e)
    ##########  Punches must be a number
    try:
        add_reward("", "", "ba")
        parts[17]['success'] =\
            test.find("#punches_ic ul li").text ==\
                "Enter a whole number."
        test.find("//div [@id='edit-reward-options']/a[2]",
                  type="xpath").click()
        sleep(2)
    except Exception as e:
        print e
        parts[17]['test_message'] = str(e)

    ##########  Punches must be greater than 0
    try:
        add_reward("", "", "0")
        parts[18]['success'] =\
            test.find("#punches_ic ul li").text ==\
                "Ensure this value is greater than or equal to 1."
        test.find("//div [@id='edit-reward-options']/a[2]",
                  type="xpath").click()
        sleep(2)
    except Exception as e:
        print e
        parts[18]['test_message'] = str(e)

    ##########  Rewards are initially sorted by Punchess
    ###         from least to greatest
    try:
        store.rewards = None
        rewards = store.get('rewards')
        punches_map = {r['punches']: r for r in rewards}
        ascending = [r['punches'] for r in rewards]
        descending = ascending[:]
        ascending.sort()
        descending.sort(reverse=True)
        success = True
        for i in range(3):
            if int(
                    test.find("//div[@id='%s']/a/div[1]" % (str(i + 1), ),
                              type="xpath").text) != ascending[i]:
                success = False
                break

        parts[19]['success'] = success
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
    ##########  Punches is sortable
    try:
        test.find("#header-reward_punches").click()
        rows = test.find("//div[@id='rewards_section']/" +\
            "div[contains(@class, 'reward')]",
            type="xpath", multiple=True)

        if len(rows) == len(descending):
            success = True
            for i in range(len(rows)):
                # check both the punches and id
                row = rows[i]
                if int(row.text.split("\n")[0]) !=\
                    descending[i] or int(row.get_attribute("id")) !=\
                    punches_map[descending[i]]['reward_id']:
                    success = False
                    break

            parts[20]['success'] = success

    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    ##########  Name is sortable
    try:
        name_map = {r['reward_name']: r for r in rewards}
        ascending = [r['reward_name'] for r in rewards]
        descending = ascending[:]
        ascending.sort()
        descending.sort(reverse=True)

        # ascending order
        test.find("#header-reward_summary").click()
        rows = test.find("//div[@id='rewards_section']/" +\
            "div[contains(@class, 'reward')]",
            type="xpath", multiple=True)

        if len(rows) == len(ascending):
            success1 = True
            for i in range(len(rows)):
                # check both the name and id
                row = rows[i]
                if row.text.split("\n")[1] !=\
                    ascending[i] or int(row.get_attribute("id")) !=\
                    name_map[ascending[i]]['reward_id']:
                    success1 = False
                    break

        # descending order
        test.find("#header-reward_summary").click()
        rows = test.find("//div[@id='rewards_section']/" +\
            "div[contains(@class, 'reward')]",
            type="xpath", multiple=True)

        if len(rows) == len(descending):
            success2 = True
            for i in range(len(rows)):
                # check both the name and id
                row = rows[i]
                if row.text.split("\n")[1] !=\
                    descending[i] or int(row.get_attribute("id")) !=\
                    name_map[descending[i]]['reward_id']:
                    success2 = False
                    break

            parts[21]['success'] = success1 and success2
    except Exception as e:
        print e
        parts[21]['test_message'] = str(e)

    ##########  Updating a reward with the reset redemption
    ###         count option resets the redemption count to 0
    try:
        # logout
        test.logout()
        test.dev_login()
        sleep(1)
        # modify store the rewards redemption count
        store.rewards = None
        for r in store.get("rewards"):
            r['redemption_count'] = 99
        store.update()
        # login
        test.open(reverse("rewards_index"))  # ACTION!
        sleep(1)
        selectors = (("#login_username", TEST_USER['username']),
                     ("#login_password", TEST_USER['password']), ("",
                                                                  Keys.RETURN))
        test.action_chain(0, selectors, "send_keys")  # ACTION!
        sleep(7)
        # now test
        test.find("//div[@id='2']/a", type="xpath").click()
        sleep(1)
        red_count = int(test.find("#redemption_count").text.split(" ")[1])
        test.find("#reset_red_count").click()
        test.find("#submit-reward-form").click()
        sleep(5)
        test.find("//div[@id='2']/a", type="xpath").click()
        new_red_count =\
            int(test.find("#redemption_count").text.split(" ")[1])
        parts[22]['success'] = new_red_count == 0 and red_count !=\
            new_red_count
    except Exception as e:
        print e
        parts[22]['test_message'] = str(e)

    # END OF ALL TESTS - cleanup
    return test.tear_down()
예제 #28
0
 def create_random_stores(self, amount):
     for i in range(amount):
         print "Creating store %s" % (str(i),) 
         # create the store
         street, city, state, zip, country, phone_number =\
             self.addrs[i].split(", ")
         first_name, last_name = self.owners[i].split(" ")
         neighborhood = self.neighborhoods[i]
         store_name = self.stores[i]
         store_i = STORE.copy()
         store_location_i = STORE_LOCATION.copy()
         
         # create the thumbnaiil and cover (same image different size)
         self.get_store_location_image(i)
         
         thumbnail = create_png(TMP_IMG_PATH, IMAGE_THUMBNAIL_SIZE)
         while "error" in image:
             print "Retrying create_png"
             thumbnail = create_png(TMP_IMG_PATH)
             
         cover = create_png(TMP_IMG_PATH)
         while "error" in cover:
             print "Retrying create_png"
             cover = create_png(TMP_IMG_PATH)
         
         store_i.update({
             "store_name": store_name,
             "first_name": first_name,
             "last_name": last_name,
             "thumbnail_image": thumbnail.get("name"),
             "cover_image": cover.get("name"),
         })
         store_location_i.update({
             "street": street,
             "city": city,
             "state": state,
             "zip": zip,
             "neighborhood": neighborhood,
             "country": country,
             "phone_number": phone_number,
             "coordinates": self.get_random_coordinates(),
         })
         
         # create the store
         store = Store.objects().create(**store_i)   
 
         # create the store location
         store_location = StoreLocation(**store_location_i)
         store_location.Store = store.objectId
         store_location.update()
         
         # create the settings
         settings = Settings.objects().create(Store=store.objectId)
         
         # create the subscription
         subscription =\
             Subscription.objects().create(Store=store.objectId,
                 date_last_billed=timezone.now())
         
         # create the user
         email = first_name+str(randint(0, 99))+USER_EMAIL_POSTFIX
         email = email.lower()
         acc = Account.objects().create(\
             username=email, email=email,
             password=USER_PASSWORD, Store=store.objectId)
         if not acc.objectId:
             raise Exception("Account creation failed.")
             
         # link the store
         store.Settings = settings.objectId
         store.Subscription = subscription.objectId
         store.owner_id = acc.objectId
         store.ACL[acc.objectId] = {"read": True,"write": True}
         store.store_locations = [store_location]
         store.update()
예제 #29
0
def test_settings():
    # setup
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store.Settings")
    store = account.store
    settings = store.settings

    # set punches facebook and employees to 1
    store.punches_facebook = 1
    settings.punches_employee = 1
    store.update()
    settings.update()

    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Changes to Punches employee are visible"},
        {'test_name': "Changes to Punches facebook are visible"},
        {'test_name': "Changes to Punches employee are saved to Parse"},
        {'test_name': "Changes to Punches facebook are saved to Parse"},
        {'test_name': "Punches employee is required"},
        {'test_name': "Punches facebook is required"},
        {'test_name': "Punches employee must be a number"},
        {'test_name': "Punches facebook must be a number."},
        {'test_name': "Punches employee must be greater than 0"},
        {'test_name': "Punches facebook must be greater than or = 0"},
        {'test_name': "Retailer PIN is refreshable"},
        {'test_name': "Changes to Retailer PIN is immediately " +\
            "commited to Parse without having to save settings."},
        {'test_name': "Clicking cancle redirects user back to " +\
            "settings page"},
        {'test_name': "Clicking cancel changes will not undo the " +\
            "change made to Retailer PIN"},
        {'test_name': "Clicking cancel changes will not save " +\
            "changes to punches facebook and punches employee"},
    ]
    section = {
        "section_name": "Settings page working properly?",
        "parts": parts,
    }
    test.results.append(section)

    ##########  User needs to be logged in to access page
    test.open(reverse("store_settings"))  # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("store_settings"))

    # login
    selectors = (("#login_username", TEST_USER['username']),
                 ("#login_password", TEST_USER['password']), ("", Keys.RETURN))
    test.action_chain(0, selectors, "send_keys")  # ACTION!
    sleep(5)

    try:
        selectors = (
            ("#id_punches_employee", "5"),
            ("#id_punches_facebook", "5"),
        )
        test.action_chain(0, selectors, action="clear")
        test.action_chain(0, selectors, action="send_keys")
        test.find("#settings-form-submit").click()
        sleep(5)
    except Exception as e:
        print e

    ##########  Changes to Punches employee are visible
    try:
        parts[1]['success'] = test.find(\
            "#id_punches_employee").get_attribute("value") == "5"
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)

    ##########  Changes to Punches facebook are visible
    try:
        parts[2]['success'] = test.find(\
            "#id_punches_facebook").get_attribute("value") == "5"
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
    ##########  Changes to Punches employee are saved to Parse
    try:
        settings.punches_employee = None
        parts[3]['success'] = settings.get("punches_employee") ==\
            int(test.find("#id_punches_employee").get_attribute("value"))
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
    ##########  Changes to Punches facebook are saved to Parse
    try:
        store.punches_facebook = None
        parts[4]['success'] = store.get("punches_facebook") ==\
            int(test.find("#id_punches_facebook").get_attribute("value"))
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)

    try:
        selectors = ("#id_punches_employee", "#id_punches_facebook")
        test.action_chain(0, selectors, action="clear")
        test.find("#settings-form-submit").click()
        sleep(1)
    except Exception:
        pass

    ##########  Punches employee is required
    try:
        parts[5]['success'] =\
            test.find("#punches_employee_e ul li").text ==\
                "This field is required."
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
    ##########  Punches facebook is required
    try:
        parts[6]['success'] =\
            test.find("#punches_facebook_e ul li").text ==\
                "This field is required."
    except Exception as e:
        print e
        parts[6]['test_mesage'] = str(e)

    try:
        selectors = (
            ("#id_punches_employee", "a"),
            ("#id_punches_facebook", "b"),
        )
        test.action_chain(0, selectors, action="clear")
        test.action_chain(0, selectors, action="send_keys")
        test.find("#settings-form-submit").click()
        sleep(1)
    except Exception:
        pass

    ##########  Punches employee must be a number
    try:
        parts[7]['success'] =\
            test.find("#punches_employee_e ul li").text==\
            "Enter a whole number."
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
    ##########  Punches facebook must be a number
    try:
        parts[8]['success'] =\
            test.find("#punches_facebook_e ul li").text==\
            "Enter a whole number."
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)

    try:
        selectors = (
            ("#id_punches_employee", "-1"),
            ("#id_punches_facebook", "-1"),
        )
        test.action_chain(0, selectors, action="clear")
        test.action_chain(0, selectors, action="send_keys")
        test.find("#settings-form-submit").click()
        sleep(1)
    except Exception:
        pass
    ##########  Punches employee must be greater than 0
    try:
        parts[9]['success'] =\
            test.find("#punches_employee_e ul li").text ==\
            "Ensure this value is greater than or equal to 1."
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
    ##########  Punches facebook must be greater than or equal to 0
    try:
        parts[10]['success'] =\
            test.find("#punches_facebook_e ul li").text ==\
            "Ensure this value is greater than or equal to 0."
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    ##########  Retailer PIN is refreshable
    try:
        prev_pin = test.find("#retailer_pin").text
        test.find("#link_refresh_retailer_pin").click()
        sleep(10)  # yea this takes a while
        new_pin = test.find("#retailer_pin").text
        parts[11]['success'] = prev_pin != new_pin
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
    ##########  Changes to Retailer PIN is immediately
    ###         commited to Parse without having to save settings
    try:
        settings.retailer_pin = None
        parts[12]['success'] = settings.get("retailer_pin") == new_pin
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)

    ##########  Clicking cancel redirects user back to settings page
    try:
        current_pin = test.find("#retailer_pin").text
        test.find("//div[@id='settings-options']/a[2]", type="xpath").click()
        sleep(1)
        parts[13]['success'] =\
            test.is_current_url(reverse("store_settings"))
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)

    ##########  Clicking cancel changes will not undo the
    ###         change made to Retailer PIN
    try:
        parts[14]['success'] = current_pin ==\
            test.find("#retailer_pin").text
    except Exception as e:
        print e
        parts[14]['test_message'] = str(e)

    ##########  Clicking cancel changes will not save
    ###         changes to punches facebook and punches employee
    try:
        current_ep =\
            test.find("#id_punches_employee").get_attribute("value")
        current_fbp =\
            test.find("#id_punches_facebook").get_attribute("value")
        test.find("//div[@id='settings-options']/a[2]", type="xpath").click()
        sleep(1)
        parts[15]['success'] = current_ep == test.find(\
            "#id_punches_employee").get_attribute("value") and\
            current_fbp == test.find(\
            "#id_punches_facebook").get_attribute("value")
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)

    # END OF ALL TESTS - cleanup
    return test.tear_down()
예제 #30
0
def test_update_subscription():
    # TODO test place_order
    account =  Account.objects().get(username=TEST_USER['username'],
        include="Store.Subscription")
    store = account.store
    subscription = store.subscription
    subscription.update_locally(SUBSCRIPTION_INFO, False)
    subscription.update()
    
    
    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Update account page reachable"},
        {'test_name': "Changes to first name are visible"},
        {'test_name': "Changes to first name are saved to parse"},
        {'test_name': "Changes to last name are visible"},
        {'test_name': "Changes to last name are saved to parse"},
        {'test_name': "Changes to card number are visible"},
        {'test_name': "Changes to card number are saved to parse"},
        {'test_name': "A paypal credit card id is generated & saved"},
        {'test_name': "Changes to cc expiration are visible"},
        {'test_name': "Changes to cc expiration are saved to parse"},
        {'test_name': "Changes to address are visible"},
        {'test_name': "Changes to address are saved to parse"},
        {'test_name': "Changes to city are visible"},
        {'test_name': "Changes to city are saved to parse"},
        {'test_name': "Changes to state are visible"},
        {'test_name': "Changes to state are saved to parse"},
        {'test_name': "Changes to zip are visible"},
        {'test_name': "Changes to zip are saved to parse"},
        {'test_name': "First name is required"},
        {'test_name': "Last name is required"},
        {'test_name': "Card number is required"},
        {'test_name': "Security code (cvc) is required"},
        {'test_name': "Address is required"},
        {'test_name': "City is required"},
        {'test_name': "State is required"},
        {'test_name': "Zip is required"},
        {'test_name': "ToS checked is required"},
        {'test_name': "Invalid credit card number shows error"},
        {'test_name': "Past expiration date is invalid"},
        {'test_name': "Only the last 4 digits of the card number" +\
            " are shown"},
        {'test_name': "Not changing the card number does not " +\
            "generate new paypal credit card id"},
    ]
    section = {
        "section_name": "Edit account/subscription working properly?",
        "parts": parts,
    }
    self.results.append(section)
    
    ##########  User needs to be logged in to access page
    self.open(reverse("store_index")) 
    sleep(1)
    parts[0]['success'] = self.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("store_index"))
        
    # login
    selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
    )
    self.action_chain(0, selectors, "send_keys") 
    sleep(7)  
   
    ##########  Update account page reachable
    try:
        self.find("//div[@id='account-options']/a[1]",
            type="xpath").click()
        sleep(3)
        parts[1]['success'] =\
            self.is_current_url(reverse("subscription_update"))
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
    
    ## Make changes
    # first clear all inputs
    for el in self.find("input[type='text']", multiple=True):
        el.clear()
    
    selectors = (
        ("#id_first_name", TEST_SUBSCRIPTION_INFO['first_name']), 
        ("#id_last_name", TEST_SUBSCRIPTION_INFO['last_name']), 
        ("#id_cc_number", TEST_SUBSCRIPTION_INFO['cc_number']),
        ("#id_cc_cvv", "905"), 
        ("#id_address", TEST_SUBSCRIPTION_INFO['address']), 
        ("#id_city", TEST_SUBSCRIPTION_INFO['city']), 
        ("#id_state", TEST_SUBSCRIPTION_INFO['state']), 
        ("#id_zip", TEST_SUBSCRIPTION_INFO['zip']),
    )
    self.action_chain(0, selectors, action="send_keys")
    month_el =\
        self.find("//select[@id='id_date_cc_expiration_month']/" +\
            "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\
                'date_cc_expiration'].month),), type="xpath")
    year_el =\
        self.find("//select[@id='id_date_cc_expiration_year']/" +\
            "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\
                'date_cc_expiration'].year),), type="xpath")
    month = month_el.get_attribute("value")
    year = year_el.get_attribute("value")
    month_el.click()
    year_el.click()
    
    self.find("#id_recurring").click()
    self.find("#update-form-submit").click()
    sleep(5)
    
    # back to update account page
    self.find("//div[@id='account-options']/a[1]",
        type="xpath").click()
    sleep(3)
    
    ##########  Changes to first name are visible
    parts[2]['success'] =\
        self.find("#id_first_name").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['first_name']
    ##########  Changes to first name are saved to parse
    subscription.first_name = None
    parts[3]['success'] = subscription.get("first_name") ==\
        TEST_SUBSCRIPTION_INFO['first_name']
    ##########  Changes to last name are visible
    parts[4]['success'] =\
        self.find("#id_last_name").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['last_name']
    ##########  Changes to last name are saved to parse
    subscription.last_name = None
    parts[5]['success'] = subscription.get("last_name") ==\
        TEST_SUBSCRIPTION_INFO['last_name']
    ##########  Changes to card number are visible
    parts[6]['success'] =\
        self.find("#id_cc_number").get_attribute("value")[-4:] ==\
        TEST_SUBSCRIPTION_INFO['cc_number'][-4:]
    ##########  Changes to card number are saved to parse
    subscription.cc_number = None
    parts[7]['success'] = subscription.get("cc_number") ==\
        TEST_SUBSCRIPTION_INFO['cc_number'][-4:]
    ##########  A paypal credit card id is generated & saved
    # CARD-97223025G70599255KHHCCVQ
    subscription.pp_cc_id = None
    parts[8]['success'] = subscription.get("pp_cc_id").__contains__(\
        "CARD") and len(subscription.get("pp_cc_id")) == 29
    ##########  Changes to cc expiration are visible 
    parts[9]['success'] = month == self.get_selected("//select" +\
        "[@id='id_date_cc_expiration_month']/option",
        type="xpath").get_attribute("value") and\
        year == self.get_selected(\
        "//select[@id='id_date_cc_expiration_year']/option",
        type="xpath").get_attribute("value")
    ##########  Changes to cc expiration are saved to parse
    subscription.date_cc_expiration = None
    exp = subscription.get("date_cc_expiration")
    parts[10]['success'] = exp.month == TEST_SUBSCRIPTION_INFO[\
        'date_cc_expiration'].month and exp.year ==\
        TEST_SUBSCRIPTION_INFO['date_cc_expiration'].year
    ##########  Changes to address are visible
    parts[11]['success'] =\
        self.find("#id_address").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['address']
    ##########  Changes to address are saved to parse 
    subscription.address = None
    parts[12]['success'] = subscription.get("address") ==\
        TEST_SUBSCRIPTION_INFO['address']
    ##########  Changes to city are visible
    parts[13]['success'] =\
        self.find("#id_city").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['city']
    ##########  Changes to city are saved to parse 
    subscription.city = None
    parts[14]['success'] = subscription.get("city") ==\
        TEST_SUBSCRIPTION_INFO['city']
    ##########  Changes to state are visible
    self.find("//select[@id='id_date_cc_expiration_year']/" +\
            "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\
                'date_cc_expiration'].year)), type="xpath")
    parts[15]['success'] =\
        self.find("#id_state").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['state']
    ##########  Changes to state are saved to parse 
    subscription.state = None
    parts[16]['success'] = subscription.get("state") ==\
        TEST_SUBSCRIPTION_INFO['state']
    ##########  Changes to zip are visible
    parts[17]['success'] =\
        self.find("#id_zip").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['zip']
    ##########  Changes to zip are saved to parse 
    subscription.zip = None
    parts[18]['success'] = subscription.get("zip") ==\
        TEST_SUBSCRIPTION_INFO['zip']
    
    ## Make changes
    selectors = [
        "#id_first_name", "#id_last_name", 
        "#id_cc_number", "#id_cc_cvv",  
        "#id_address", "#id_city", "#id_state", "#id_zip",
    ]
    self.action_chain(0, selectors, action="clear")
    for i in range(len(selectors)):
        selectors[i] = (selectors[i], "    ")
    self.action_chain(0, selectors, action="send_keys")
    
    self.find("#update-form-submit").click()
    sleep(3)
    
    ##########  First name is required
    ##########  Last name is required
    ##########  Card number is required
    ##########  Security code (cvc) is required 
    ##########  Address is required 
    ##########  City is required 
    ##########  State is required 
    ##########  Zip is required 
    ##########  ToS checked is required 
    def field_is_required(part, selector,
        message="This field is required."):
        try:
            parts[part]['success'] = self.find(selector).text==message
        except Exception as e:
            print e
            parts[part]['test_message'] = str(e)
    
    selectors = (
        (19, "#first_name_ic ul.errorlist li"),
        (20, "#last_name_ic ul.errorlist li"),
        (21, "#card_number_container ul.errorlist li",
            "Enter a valid credit card number."),
        (22, "#cc_cvv_ic ul.errorlist li"),
        (23, "#address_ic ul.errorlist li"),
        (24, "#city_ic ul.errorlist li"),
        (25, "#state_ic ul.errorlist li"),
        (26, "#zip_ic ul.errorlist li"),
        (27, "#recurring_charge_container ul.errorlist li",
            "You must accept the Terms & Conditions to continue."),
    )
    
    for selector in selectors:
        field_is_required(*selector)
    
    ##########  Invalid credit card number shows error
    try:
        cc_number = self.find("#id_cc_number")
        cc_number.clear()
        cc_number.send_keys("8769233313929990")
        self.find("#update-form-submit").click()
        sleep(3)
        parts[28]['success'] = self.find("#card_number_container " +\
            "ul.errorlist li").text ==\
                "Enter a valid credit card number."
    except Exception as e:
        print e
        parts[28]['test_message'] = str(e)
    
    ##########  Past expiration date is invalid
    if timezone.now().month == 1:
        # note that if this test is being run on a January, this will 
        # fail so to prevent that just skip the test if it is January
        parts[29]['test_message'] = "READ ME. This test has been " +\
            "skipped because the month is January, which means " +\
            "that this test will always fail due to limited " +\
            "select options."
    else:
        try:
            # select january of this year.
            self.find("//select[@id='id_date_cc_expiration_month']/" +\
                    "option[@value='1']", type="xpath").click()
            self.find("//select[@id='id_date_cc_expiration_year']/" +\
                    "option[@value='%s']" %\
                    (str(timezone.now().year),), type="xpath").click()
            self.find("#update-form-submit").click()
            sleep(3)
            parts[29]['success'] =\
                self.find("#date_cc_expiration_ic ul.errorlist " +\
                "li").text == "Your credit card has expired!"
        except Exception as e:
            print e
            parts[29]['test_message'] = str(e)
        
    ##########  Only the last 4 digits of the card number are shown
    try:
        self.find("//div[@class='form-options']/a[2]",
            type="xpath").click()
        sleep(1)
        self.find("//div[@id='account-options']/a[1]",
            type="xpath").click()
        sleep(3)
        masked_number =\
            self.find("#id_cc_number").get_attribute("value")
        parts[30]['success'] = masked_number[:-4] ==\
            "************" and str(masked_number[-4:]).isdigit()
    except Exception as e:
        print e
        parts[30]['test_message'] = str(e)
    
    ##########  Not changing the card number does not
    ######      generate new paypal credit card id
    try:
        subscription.pp_cc_id = None
        cc_id = subscription.get("pp_cc_id")
        self.find("#id_cc_cvv").send_keys("123")
        self.find("#id_recurring").click()
        self.find("#update-form-submit").click()
        sleep(5)
        subscription.pp_cc_id = None
        parts[31]['success'] = cc_id == subscription.get("pp_cc_id")
    except Exception as e:
        print e
        parts[31]['test_message'] = str(e)
    
    # END OF ALL TESTS - cleanup
    return self.tear_down()
예제 #31
0
def sign_up(request):
    """
    Creates User, store, subscription, and settings objects.
    """
    # renders the signup page on GET and returns a json object on POST.
    data = {'sign_up_nav': True}

    if request.method == 'POST':
        # this conversion to a regular dictionay is important
        postDict = request.POST.dict()

        from_associated_account = False
        # check if this post is from the associated account dialog
        # if it is then skip form validations
        aaf_nonce_id = postDict.get('aaf-nonce')
        aaf_account_id = postDict.get('aaf-account_id')
        if len(aaf_nonce_id) > 0 and len(aaf_account_id) > 0:
            aa_nonce = AssociatedAccountNonce.objects.filter(\
                id=aaf_nonce_id, account_id=aaf_account_id)
            if len(aa_nonce) > 0 and aa_nonce[0].verified:
                aa_nonce[0].delete()
                from_associated_account = True

        # some keys are repeated so must catch this at init
        store_form = StoreSignUpForm(request.POST)
        store_location_form = StoreLocationForm(request.POST)
        account_form = AccountSignUpForm(request.POST)

        cats = postDict.get("categories")
        category_names = None
        if cats and len(cats) > 0:
            category_names = cats.split("|")[:-1]
            # make sure that there are only up to 2 categories
            while len(category_names) > 2:
                category_names.pop()
            data["category_names"] = category_names

        if not from_associated_account:
            all_forms_valid = store_form.is_valid() and\
                store_location_form.is_valid() and account_form.is_valid()
        else:
            all_forms_valid = True

        if all_forms_valid:
            # check if email already taken here to handle the case where
            # the user already has a patron/employee account
            # but also want to sign up for a Store account
            if hasattr(account_form, "associated_account"):
                aa = account_form.associated_account
                aan = AssociatedAccountNonce.objects.create(\
                    account_id=aa.objectId)
                return HttpResponse(json.dumps({"associated_account":\
                    aa.objectId, "associated_account_nonce":aan.id,
                    "email": aa.email, "code": 0}),
                    content_type="application/json")
            #########################################################

            # create store
            store = Store(**postDict)
            # set defaults for these guys to prevent
            # ParseObjects from making parse calls repeatedly
            store.punches_facebook = 1
            store.set("rewards", [])
            store.set("categories", [])
            if category_names:
                for name in category_names:
                    alias = Category.objects.filter(name__iexact=name)
                    if len(alias) > 0:
                        store.categories.append({
                            "alias": alias[0].alias,
                            "name": name
                        })

            # create settings
            settings = Settings(Store=store.objectId)
            store.set('settings', settings)

            # create account
            if not from_associated_account:
                account = Account(**postDict)
                # username = email
                # we should be doing this in the form but ehh
                account.set("username", postDict['email'].strip().lower())
                account.set("email", postDict['email'].strip().lower())
                account.set_password(postDict.get('password'))
            else:
                account =\
                    Account.objects().get(objectId=aaf_account_id)

            account.set("store", store)

            # create subscription
            subscription = Subscription()
            subscription.subscriptionType = 0
            subscription.date_last_billed = timezone.now()
            subscription.create()

            # create settings
            settings.create()

            # create store
            store.Settings = settings.objectId
            store.Subscription = subscription.objectId
            store.create()

            # add the pointer to the created store
            settings.Store = store.objectId
            settings.update()
            subscription.Store = store.objectId
            subscription.update()

            # create the store location
            store_location = StoreLocation(**postDict)
            # format the phone number
            store_location.store_timezone =\
                rputils.get_timezone(postDict.get("zip")).zone
            store_location.set("hours", [])
            # coordinates and neighborhood
            # the call to get map data is actually also in the clean
            full_address = " ".join(\
                store_location.get_full_address().split(", "))
            map_data = rputils.get_map_data(full_address)
            store_location.set("coordinates", map_data.get("coordinates"))
            store_location.set("neighborhood",
                store_location.get_best_fit_neighborhood(\
                    map_data.get("neighborhood")))
            store_location.phone_number =\
                format_phone_number(postDict["phone_number"])
            store_location.Store = store.objectId
            store_location.create()

            # add the StoreLocation to the relation
            store.store_locations = [store_location]
            store.update()

            # create account
            account.Store = store.objectId
            if not from_associated_account:
                account.create()
            else:
                account.update()

            # create the store ACL with the account having r/w access
            store.ACL = {
                "*": {
                    "read": True,
                    "write": True
                },
                account.objectId: {
                    "read": True,
                    "write": True
                },
            }
            store.owner_id = account.objectId
            store.update()

            # note that username has been fed the email
            # this shouldn't change anything though shouldn't matter
            # need to put username and pass in request
            postDict['username'] = account.username
            postDict['password'] = account.password

            # send matt and new user a pretty email.
            send_email_signup(account)

            # auto login
            user_login = login(request, postDict, no_recaptcha=True)
            if user_login != None:
                data = {"code": -1}
                # response to signup.js - not login returns
                # 0 - Associated account already exists
                # 2 - subscription is not active
                # 3 - success (login now)
                if type(user_login) is int:  # subscription not active
                    data['code'] = 2
                else:
                    # required for datetime awareness!
                    rputils.set_timezone(request, tz)
                    data['code'] = 3
                return HttpResponse(json.dumps(data),
                                    content_type="application/json")

    else:
        store_form = StoreSignUpForm()
        store_location_form = StoreLocationForm()
        account_form = AccountSignUpForm()

    data['store_form'] = store_form
    data['store_location_form'] = store_location_form
    data['account_form'] = account_form
    return render(request, 'public/signup.djhtml', data)
예제 #32
0
    def handle(self, *args, **options):
        # for logging when ran by CRON
        print "Running detect_suspicious_activity: " + str(timezone.now())

        # first count the number of active stores
        store_count = Store.objects().count(active=True)
        # store_count = Store.objects().count(objectId="o72LmDy0YK")

        end = timezone.now()
        start = end + relativedelta(hours=-24)
        conn = mail.get_connection(fail_silently=(not DEBUG))
        conn.open()

        # to send to the admins
        admin_chunks = []

        # get 500 stores at a time
        LIMIT, skip = 500, 0
        while store_count > 0:
            for store in Store.objects().filter(active=True,
                                                include="store_locations",
                                                limit=LIMIT,
                                                skip=skip,
                                                order="createdAt"):
                # for store in Store.objects().filter(\
                #     objectId="o72LmDy0YK", include="store_locations"):

                ### CHUNK1 ####################################
                chunk1, account_patron, patron_punch = {}, {}, {}
                total_punches = []

                # check approved EMPLOYEES
                employees = store.get("employees", status=APPROVED, limit=900)
                employee_punches = []

                def add_to_patron_punch(punch, employee=None):
                    if punch.Patron not in patron_punch:
                        patron_punch[punch.Patron] =\
                            [{"punch":punch, "employee": employee}]
                    else:
                        patron_punch[punch.Patron].append({"punch":\
                            punch, "employee":employee})

                def get_location(location_id):
                    for loc in store.store_locations:
                        if loc.objectId == location_id:
                            return loc

                if employees and len(employees) > 0:
                    # check all the punches of each employee
                    for employee in employees:
                        # get all the punches for today
                        punches = employee.get("punches",
                                               limit=900,
                                               createdAt__lte=end,
                                               createdAt__gte=start)
                        if not punches:
                            continue

                        # for querying the dashboard punches
                        employee_punches.extend([p.objectId for p in\
                            punches])

                        # group the punches by patron
                        for punch in punches:
                            add_to_patron_punch(punch, employee)

                # now check DASHBOARD
                punches = store.get("punches",
                                    limit=900,
                                    createdAt__lte=end,
                                    createdAt__gte=start,
                                    objectId__nin=employee_punches)

                # group the punches by patron
                if punches:
                    for punch in punches:
                        add_to_patron_punch(punch, None)

                # check for a group with a list >= 6
                for key, val in patron_punch.iteritems():
                    suspicious_punches = []
                    if val and len(val) >= 6:
                        for punch in val:
                            suspicious_punches.append({
                                "store_location":\
                                    get_location(punch["punch"].store_location_id),
                                "punch": punch["punch"],
                                "employee": punch["employee"]
                            })

                        # cache the account and patron
                        if key not in account_patron:
                            acc = Account.objects().get(Patron=key,
                                                        include="Patron")
                            account_patron[key] = {
                                "account": acc,
                                "patron": acc.patron,
                            }

                        if key not in chunk1:
                            chunk1[key] = {
                                "account":\
                                   account_patron[key]['account'],
                                "patron":\
                                   account_patron[key]['patron'],
                                "punches": suspicious_punches
                            }
                        else:
                            chunk1[key]['punches'].extend(suspicious_punches)

                ### CHUNK2 ####################################
                # hours per location
                # punches are still grouped per patron
                chunk2 = {}
                for loc in store.store_locations:
                    if loc.hours and len(loc.hours) > 0 and\
                        loc.hours[0]['day'] != 0: # 24/7
                        # check for punches out of hours
                        tz = pytz.timezone(loc.store_timezone)
                        start = timezone.localtime(start, tz)
                        end = timezone.localtime(end, tz)
                        # isoweekday is from 1-7 monday to sunday
                        # convert to 1-7 sunday to saturday
                        day1_weekday = (start.isoweekday()) % 7 + 1
                        day2_weekday = (end.isoweekday()) % 7 + 1

                        # get the hours for day1 and day2
                        def get_hours_range(weekday, d):
                            for hr in loc.hours:
                                if hr["day"] == weekday:
                                    hr_start_hour =\
                                        int(hr["open_time"][:2])
                                    hr_start_minute =\
                                        int(hr["open_time"][2:])
                                    hr_end_hour =\
                                        int(hr["close_time"][:2])
                                    hr_end_minute =\
                                        int(hr["close_time"][2:])
                                    return d.replace(hour=hr_start_hour,
                                        minute=hr_start_minute),\
                                        d.replace(hour=hr_end_hour,
                                        minute=hr_end_minute)
                            return None, None

                        (hours1_start, hours1_end) =\
                            get_hours_range(day1_weekday, start)
                        (hours2_start, hours2_end) =\
                            get_hours_range(day2_weekday, end)

                        # now convert to utc since punch times are in utc
                        if hours1_start:
                            hours1_start =\
                                timezone.localtime(hours1_start, tzutc())
                            hours1_end =\
                                timezone.localtime(hours1_end, tzutc())
                        if hours2_start:
                            hours2_start =\
                                timezone.localtime(hours2_start, tzutc())
                            hours2_end =\
                                timezone.localtime(hours2_end, tzutc())

                        for key, val in patron_punch.iteritems():
                            if not val:
                                continue

                            suspicious_punches = []

                            # process only those punches that are in this location
                            for p in [
                                    x for x in val
                                    if x["punch"].store_location_id ==
                                    loc.objectId
                            ]:
                                punch = p["punch"]
                                # suspicious if not in hours1 and 2
                                if not (hours1_start and\
                                    punch.createdAt>hours1_start and\
                                    punch.createdAt<hours1_end) and\
                                    not (hours2_start and\
                                    punch.createdAt>hours2_start and\
                                    punch.createdAt<hours2_end):
                                    # not in hours1 or 2 so suspicious!
                                    suspicious_punches.append({
                                        "store_location":
                                        loc,
                                        "punch":
                                        punch,
                                        "employee":
                                        p["employee"],
                                    })

                            if len(suspicious_punches) == 0:
                                continue

                            # cache the account and patron
                            if key not in account_patron:
                                acc = Account.objects().get(Patron=key,
                                                            include="Patron")
                                account_patron[key] = {
                                    "account": acc,
                                    "patron": acc.patron,
                                }

                            if key not in chunk2:
                                chunk2[key] = {
                                    "account":\
                                       account_patron[key]['account'],
                                    "patron":\
                                       account_patron[key]['patron'],
                                    "punches": suspicious_punches
                                }
                            else:
                                chunk2[key]['punches'].extend(
                                    suspicious_punches)

                # all tasks are done for this store - send email
                if len(chunk1) > 0 or len(chunk2) > 0:
                    store_acc = Account.objects().get(Store=store.objectId)
                    admin_chunks.append({
                        "store_acc": store_acc,
                        "store": store,
                        "data": (chunk1, chunk2),
                    })

                    try:
                        send_email_suspicious_activity(store_acc, store,
                                                       chunk1, chunk2, conn)
                    except SMTPServerDisconnected:
                        conn = mail.get_connection(fail_silently=(not DEBUG))
                        conn.open()
                        send_email_suspicious_activity(store_acc, store,
                                                       chunk1, chunk2, conn)

            # end of while loop
            store_count -= LIMIT
            skip += LIMIT

        if len(admin_chunks) > 0:
            send_email_suspicious_activity_admin(admin_chunks, start, end,
                                                 conn)

        # everything is done. close the connection
        try:
            conn.close()
        except Exception:
            pass
예제 #33
0
def test_employees():
    """
    Tests for employee approve, deny, remove, details. etc.
    """
    # TODO test employee graph
    # TODO test employee punches history

    # delete the employees and associated User objects in the relation
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store.Settings")
    store = account.store
    settings = store.settings

    emps = store.get("employees")
    if emps:
        for emp in emps:
            Account.objects().get(Employee=emp.objectId).delete()
            emp.delete()

    store.set("employees", None)

    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Cloud code register_employee works"},
        {'test_name': "Employee is saved in store's Employees " +\
            "relation"},
        {'test_name': "Employee is initially pending (Parse)"},
        {'test_name': "Employee is initially pending (Dashboard)"},
        {'test_name': "Email must be valid (cloud code)"},
        {'test_name': "Email must be unique (cloud code)"},
        {'test_name': "Username must be unique (cloud code)"},
        {'test_name': "Retailer PIN must exist (cloud code)"},
        {'test_name': "Clicking deny prompts the user to confirm"},
        {'test_name': "The user is redirected to employee index"},
        {'test_name': "The denied employee is removed from the " +\
            "pending table"},
        {'test_name': "The employee is deleted from parse"},
        {'test_name': "The account/user is deleted from parse"},
        {'test_name': "Approving the employee moves it from " +\
            "pending to approved"},
        {'test_name': "Employee status is set to approved in Parse"},
        {'test_name': "Employee initially has 0 punches."},
        {'test_name': "Clicking on the approved employee row " +\
            " redirects user to employee edit page"},
        {'test_name': "Clicking delete prompts the user to confirm"},
        {'test_name': "The user is redirected to employee index"},
        {'test_name': "The deleted employee is removed from the " +\
            "pending table"},
        {'test_name': "The employee is deleted from parse"},
        {'test_name': "The account/user is deleted from parse"},
        {'test_name': "Multiple employees (3) registering at once" +\
            " shows up in dashboard"},
    ]
    section = {
        "section_name": "Employees page working properly?",
        "parts": parts,
    }
    test.results.append(section)

    ##########  User needs to be logged in to access page"
    test.open(reverse("employees_index"))  # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("employees_index"))

    # login
    selectors = (("#login_username", TEST_USER['username']),
                 ("#login_password", TEST_USER['password']), ("", Keys.RETURN))
    test.action_chain(0, selectors, "send_keys")  # ACTION!
    sleep(7)

    def register_employee(first_name,
                          last_name,
                          username=None,
                          password=None,
                          email=None,
                          retailer_pin=None):

        if username is None:
            username = first_name
        if password is None:
            password = first_name
        if email is None:
            email = first_name + "@" + last_name + ".com"
        if retailer_pin is None:
            retailer_pin = settings.retailer_pin

        return cloud_call(
            "register_employee", {
                "first_name": first_name,
                "last_name": last_name,
                "username": username,
                "password": password,
                "email": email,
                "retailer_pin": retailer_pin,
            })

    first_name, last_name, username, email =\
    "vandolf1", "estrellado", "*****@*****.**", "*****@*****.**"

    ##########  Cloud code register_employee works"
    try:
        res = register_employee(first_name, last_name, username, email=email)
        parts[1]['success'] = "error" not in res
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
    ##########  Employee is saved in store's Employees relation"
    try:
        emp = store.get("employees")[0]
        parts[2]['success'] = emp is not None
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
    ##########  Employee is initially pending (Parse)"
    try:
        parts[3]['success'] = emp.status == PENDING
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
    ##########  Employee is initially pending (Dashboard)"
    try:
        sleep(COMET_PULL_RATE * 2 + 1)  # wait for dashboard to receive
        test.find("#tab-pending-employees").click()
        parts[4]['success'] = test.element_exists(\
            "#tab-body-pending-employees div.tr div.td.approve")
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)
    ##########  Email must be valid (cloud code)"
    try:
        res = register_employee("vman", "vman", email="vmahs@vman")
        parts[5]['success'] = res['error'] == 'EMAIL_INVALID'
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
    ##########  Email must be unique (cloud code) "
    try:
        res = register_employee("vman", "vman", email=email)
        parts[6]['success'] = res['error'] == 'EMAIL_TAKEN'
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)
    ##########  Username must be unique (cloud code) "
    try:
        res = register_employee("vman", "vman", username=username)
        parts[7]['success'] = res['error'] == 'USERNAME_TAKEN'
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
    ##########  Retailer PIN must exist (cloud code) "
    try:
        res = register_employee("vman", "vman", retailer_pin="sdgdgs")
        parts[8]['success'] = res['error'] == "RETAILER_PIN_INVALID"
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)
    ##########  Clicking deny prompts the user to confirm"
    try:
        test.find("#tab-pending-employees").click()
        test.find("#tab-body-pending-employees div.tr " +\
            "div.td.approve a.deny").click()
        alert = test.switch_to_alert()
        parts[9]['success'] = alert.text == "Deny employee?"
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
    ##########  The user is redirected to employee index"
    try:
        sleep(1)
        alert.accept()
        sleep(2)
        parts[10]['success'] = test.is_current_url(reverse(\
            "employees_index") +\
            "?show_pending&success=Employee+has+been+denied.")
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    ##########  The denied employee is removed from the pending table"
    try:
        parts[11]['success'] = not test.element_exists(\
        "#tab-body-pending-employees div.tr " +\
            "div.td.approve a.approve")
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
    ##########  The employee is deleted from parse"
    try:
        store.set("employees", None)
        parts[12]['success'] = store.get("employees",\
            first_name=first_name, last_name=last_name, count=1) == 0
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)
    ##########  The account/user is deleted from parse"
    try:
        parts[13]['success'] = Account.objects().count(\
            username=username, email=email) == 0
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)
    ##########  Approving the employee moves it from pending to approved"
    try:
        register_employee(first_name, last_name, username, email=email)
        sleep(COMET_PULL_RATE * 2 + 1)  # wait for dashboard to receive
        test.find("#tab-pending-employees").click()
        approveRow = test.find("#tab-body-pending-employees " +\
            "div.tr")
        approveId = approveRow.get_attribute("id")
        approveRow.find_element_by_css_selector(\
            "div.td.approve a.approve").click()
        sleep(1)
        test.switch_to_alert().accept()
        sleep(2)
        test.find("#tab-approved-employees").click()
        parts[14]['success'] = test.element_exists(\
            "#tab-body-approved-employees " +\
            "div.tr div.td.remove a")
    except Exception as e:
        print e
        parts[14]['test_message'] = str(e)
    ##########  Employee status is set to approved in Parse"
    try:
        store.set("employees", None)
        emp = store.get("employees",
                        first_name=first_name,
                        last_name=last_name)[0]
        parts[15]['success'] = emp.status == APPROVED
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    ##########  Employee initially has 0 punches"
    try:
        parts[16]['success'] = emp.lifetime_punches == 0
    except Exception as e:
        print e
        parts[16]['test_message'] = str(e)
    ##########  Clicking on the approved employee row
    ###         redirects user to employee edit page
    try:
        test.find("#tab-approved-employees").click()
        test.find("#tab-body-approved-employees div#%s a" %\
            (emp.objectId,)).click()
        sleep(1)
        parts[17]['success'] = test.is_current_url(reverse(\
            "employee_edit", args=(emp.objectId,)))
    except Exception as e:
        print e
        parts[17]['test_message'] = str(e)
    ##########  Clicking delete prompts the user to confirm"
    try:
        test.find("#delete-button").click()
        alert = test.switch_to_alert()
        parts[18]['success'] = alert.text ==\
            "Are you sure you want to delete this employee?"
    except Exception as e:
        print e
        parts[18]['test_message'] = str(e)
    ##########  The user is redirected to employee index"
    try:
        sleep(1)
        alert.accept()
        sleep(2)
        parts[19]['success'] = test.is_current_url(reverse(\
            "employees_index") +\
            "?success=Employee+has+been+deleted.")
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
    ##########  The deleted employee is removed from the pending table"
    try:
        parts[20]['success'] = not test.element_exists(\
            "#tab-body-approved-employees div#%s a" %(emp.objectId,))
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    ##########  The employee is deleted from parse"
    try:
        store.set("employees", None)
        parts[21]['success'] = store.get("employees",
                                         objectId=emp.objectId,
                                         count=1) == 0
    except Exception as e:
        print e
        parts[21]['test_message'] = str(e)
    ##########  The account/user is deleted from parse"
    try:
        parts[22]['success'] = Account.objects().count(\
            username=username, email=email) == 0
    except Exception as e:
        print e
        parts[22]['test_message'] = str(e)
    ##########  Multiple employees (4) registering at once
    ###         shows up in dashboard"
    try:
        for i in range(3):
            register_employee(first_name + str(i), last_name + str(i))
        sleep(COMET_PULL_RATE * 2 + 3)
        test.find("#tab-pending-employees").click()
        parts[23]['success'] = len(test.find(\
            "#tab-body-pending-employees div.tr " +\
            "div.td.approve a.approve", multiple=True)) == 3
    except Exception as e:
        print e
        parts[23]['test_message'] = str(e)

    # END OF ALL TESTS - cleanup
    return test.tear_down()
예제 #34
0
def sign_up(request):
    """
    Creates User, store, subscription, and settings objects.
    """
    # renders the signup page on GET and returns a json object on POST.
    data = {'sign_up_nav': True}
            
    if request.method == 'POST':
        # this conversion to a regular dictionay is important
        postDict = request.POST.dict()
    
        from_associated_account = False
        # check if this post is from the associated account dialog
        # if it is then skip form validations
        aaf_nonce_id = postDict.get('aaf-nonce')
        aaf_account_id = postDict.get('aaf-account_id')
        if len(aaf_nonce_id) > 0 and len(aaf_account_id) > 0:
            aa_nonce = AssociatedAccountNonce.objects.filter(\
                id=aaf_nonce_id, account_id=aaf_account_id)
            if len(aa_nonce) > 0 and aa_nonce[0].verified:
                aa_nonce[0].delete()
                from_associated_account = True
    
        # some keys are repeated so must catch this at init
        store_form = StoreSignUpForm(request.POST)
        store_location_form = StoreLocationForm(request.POST)
        account_form = AccountSignUpForm(request.POST)
        
        cats = postDict.get("categories")
        category_names = None
        if cats and len(cats) > 0:
            category_names = cats.split("|")[:-1]
            # make sure that there are only up to 2 categories
            while len(category_names) > 2:
                category_names.pop()
            data["category_names"] = category_names
        
        if not from_associated_account:
            all_forms_valid = store_form.is_valid() and\
                store_location_form.is_valid() and account_form.is_valid()
        else:
            all_forms_valid = True
            
        if all_forms_valid:
            # check if email already taken here to handle the case where 
            # the user already has a patron/employee account 
            # but also want to sign up for a Store account
            if hasattr(account_form, "associated_account"):
                aa = account_form.associated_account
                aan = AssociatedAccountNonce.objects.create(\
                    account_id=aa.objectId)
                return HttpResponse(json.dumps({"associated_account":\
                    aa.objectId, "associated_account_nonce":aan.id,
                    "email": aa.email, "code": 0}), 
                    content_type="application/json")
            #########################################################

            # create store
            store = Store(**postDict)
            # set defaults for these guys to prevent 
            # ParseObjects from making parse calls repeatedly
            store.punches_facebook = 1
            store.set("rewards", [])
            store.set("categories", [])
            if category_names:
                for name in category_names:
                    alias = Category.objects.filter(name__iexact=name)
                    if len(alias) > 0:
                        store.categories.append({
                            "alias":alias[0].alias,
                            "name":name })
                            
            # create settings
            settings = Settings(Store=store.objectId)
            store.set('settings', settings)

            # create account
            if not from_associated_account:
                account = Account(**postDict)
                # username = email
                # we should be doing this in the form but ehh
                account.set("username", 
                    postDict['email'].strip().lower())
                account.set("email", 
                    postDict['email'].strip().lower())
                account.set_password(postDict.get('password'))
            else:
                account =\
                    Account.objects().get(objectId=aaf_account_id)
                
            account.set("store", store)

            # create subscription
            subscription = Subscription() 
            subscription.subscriptionType = 0
            subscription.date_last_billed = timezone.now()
            subscription.create()
            
            # create settings
            settings.create()
            
            # create store
            store.Settings = settings.objectId
            store.Subscription = subscription.objectId
            store.create()
            
            # add the pointer to the created store
            settings.Store = store.objectId
            settings.update()
            subscription.Store = store.objectId
            subscription.update()
            
            # create the store location
            store_location = StoreLocation(**postDict)
            # format the phone number
            store_location.store_timezone =\
                rputils.get_timezone(postDict.get("zip")).zone
            store_location.set("hours", [])
            # coordinates and neighborhood
            # the call to get map data is actually also in the clean 
            full_address = " ".join(\
                store_location.get_full_address().split(", "))
            map_data = rputils.get_map_data(full_address)
            store_location.set("coordinates", map_data.get("coordinates"))
            store_location.set("neighborhood", 
                store_location.get_best_fit_neighborhood(\
                    map_data.get("neighborhood")))
            store_location.phone_number =\
                format_phone_number(postDict["phone_number"])
            store_location.Store = store.objectId
            store_location.create()
            
            # add the StoreLocation to the relation
            store.store_locations = [store_location] 
            store.update()
            
            # create account
            account.Store = store.objectId
            if not from_associated_account:
                account.create()
            else:
                account.update()
            
            # create the store ACL with the account having r/w access
            store.ACL = {
                "*": {"read": True, "write": True},
                account.objectId: {"read": True, "write": True},
            }
            store.owner_id = account.objectId
            store.update()
            
            # note that username has been fed the email
            # this shouldn't change anything though shouldn't matter
            # need to put username and pass in request
            postDict['username'] = account.username
            postDict['password'] = account.password
            
            # send matt and new user a pretty email.
            send_email_signup(account)

            # auto login
            user_login = login(request, postDict, no_recaptcha=True)
            if user_login != None:
                data = {"code":-1}
                # response to signup.js - not login returns
                # 0 - Associated account already exists
                # 2 - subscription is not active
                # 3 - success (login now)
                if type(user_login) is int: # subscription not active
                    data['code'] = 2
                else:
                    # required for datetime awareness!
                    rputils.set_timezone(request, tz)
                    data['code'] = 3
                return HttpResponse(json.dumps(data), 
                            content_type="application/json")
           
    else:
        store_form = StoreSignUpForm()
        store_location_form = StoreLocationForm()
        account_form = AccountSignUpForm()
        
    data['store_form'] = store_form
    data['store_location_form'] = store_location_form
    data['account_form'] = account_form
    return render(request, 'public/signup.djhtml', data)
예제 #35
0
def test_punch():
    """
    Tests for punch customers section of the workbench.

    Assumes that at least 1 PatronStore exists for the above Store.
    """
    account = Account.objects().get(username=TEST_USER['username'],
        include="Store.Settings")
    store = account.store
    settings = store.settings
    ps = store.get("patronStores", include="Patron", limit=1)[0]
    patron = ps.patron
    
    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Punching works"},
        {'test_name': "PatronStore punch_count is updated"},
        {'test_name': "PatronStore all_time_punches is updated"},
        {'test_name': "Punch Code is required"},
        {'test_name': "Punch Codes consist of only numbers"},
        {'test_name': "Punch Codes are 5 characters long"},
        {'test_name': "Amount of punches is required"},
        {'test_name': "Amount should not exceed maximum employee punches allowed"},
        {'test_name': "Amount must be greater than 0"},
        {'test_name': "Non-existent Punch Code shows approprirate message"},
    ]
    section = {
        "section_name": "Punch working properly?",
        "parts": parts,
    }
    test.results.append(section)
    
    ##########  User needs to be logged in to access page
    test.open(reverse("workbench_index")) # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("workbench_index"))
        
    # login
    selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
    )
    test.action_chain(0, selectors, "send_keys") # ACTION!
    sleep(5) 
    
    def punch(punch_code="", punch_amount="", sleep_prior=0,
        sleep_after=0):
        if sleep_prior > 0:
            sleep(sleep_prior)
        test.find("#punch_code").clear()
        test.find("#punch_amount").clear()
        test.find("#punch_code").send_keys(punch_code)
        test.find("#punch_amount").send_keys(punch_amount)
        test.find("#punch-form a.button.blue").click()
        if sleep_after > 0:
            sleep(sleep_after)
        
    ##########  Punching works
    try:
        punch_count, all_time_punches =\
            ps.punch_count, ps.all_time_punches
        
        punch(patron.punch_code, "1", sleep_after=3)
        parts[1]['success'] =\
            test.find("#punch-notification") is not None
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
        
    ##########  PatronStore punch_count is updated
    try:
        ps.punch_count = None
        parts[2]['success'] = punch_count+1 == ps.get("punch_count")
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
        
    ##########  PatronStore all_time_punches is updated
    try:
        ps.all_time_punches = None
        parts[3]['success'] =\
            all_time_punches+1 == ps.get("all_time_punches")
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
        
    ##########  Punch Code is required
    try:
        punch(sleep_prior=5, sleep_after=1)
        parts[4]['success'] =\
            test.find("#punch-notification").text ==\
            "Please enter the customer's punch code."
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)
        
    ##########  Punch Codes consist of only numbers
    try:
        punch("123ab", sleep_prior=5, sleep_after=1)
        parts[5]['success'] =\
            test.find("#punch-notification").text ==\
            "Punch Codes consist of only numbers."
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
        
    ##########  Punch Codes are 5 characters long
    try:
        punch("123", sleep_prior=5, sleep_after=1)
        parts[6]['success'] =\
            test.find("#punch-notification").text ==\
            "Punch Codes are 5 characters long."
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)
        
    ##########  Amount of punches is required
    try:
        punch(patron.punch_code, sleep_prior=5, sleep_after=1)
        parts[7]['success'] =\
            test.find("#punch-notification").text ==\
            "Please enter the number of punches to give."
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
        
    ##########  Amount should not exceed maximum employee punches allowed
    try:
        punch(patron.punch_code, str(settings.punches_employee+1),
            sleep_prior=5, sleep_after=1)
        parts[8]['success'] =\
            test.find("#punch-notification").text ==\
            "Maximum amount of punches is %s." % (str(settings.punches_employee),)
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)
        
    ##########  Amount must be greater than 0
    try:
        punch(patron.punch_code, "-1", sleep_prior=5, sleep_after=1)
        parts[9]['success'] =\
            test.find("#punch-notification").text ==\
            "Amount of punches must be greater than 0."
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
        
    ##########  Non-existent Punch Code shows approprirate message
    try:
        punch("39393", "1", sleep_prior=5, sleep_after=1)
        parts[10]['success'] =\
            test.find("#punch-notification").text ==\
            "A customer with that Punch Code was not found."
        pass 
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    
    
    # END OF ALL TESTS - cleanup
    return test.tear_down() 
예제 #36
0
def test_employee_access():
    """
    Tests for employee dashboard access.
    This tests any user with ACL of ACCESS_PUNCHREDEEM and NO_ACCESS.
    Tests for ACCESS_ADMIN are not necessary since all other tests
    involving the store owner covers it.
    """

    # delete the employees and associated User objects in the relation
    account = Account.objects().get(email=TEST_USER['username'],
                                    include="Store.Settings")
    store = account.store
    settings = store.settings

    emps = store.get("employees")
    if emps:
        for emp in emps:
            Account.objects().get(Employee=emp.objectId).delete()
            emp.delete()
    store.set("employees", None)

    test = SeleniumTest()
    parts = [
        {"test_name" : "Pending employee has no access"},
        {"test_name" : "Approved employee initially not in store ACL"},
        {"test_name" : "Employee with ACCESS_NONE cannot login " +\
            "using  the login dialog"},
        {"test_name" : "Employee with ACCESS_NONE cannot login " +\
            "using the dedicated login page"},
        {"test_name" : "Employee with ACCESS_PUNCHREDEEM can " +\
            "login to the dashboard through the login dialog"},
        {"test_name" : "Employee with ACCESS_PUNCHREDEEM can " +\
            "login to the dashboard through the dedicated dialog pg"},

        {"test_name" : "Account settings accessible"},
        {"test_name" : "No store edit button"},
        {"test_name" : "Requesting edit store detail through url " +\
            "redirects user to store index"},
        {"test_name" : "No update subscription button"},
        {"test_name" : "Requesting update subscription through url " +\
            "redirects user to store index"},
        {"test_name" : "No deactivate my store button"},
        {"test_name" : "Requesting store deactivation through url " +\
            "redirects user to store index"},

        {"test_name" : "Rewards accessible"},
        {"test_name" : "No create new reward button"},
        {"test_name" : "Requesting create new reward through url " +\
            "redirects user to rewards index"},
        {"test_name" : "Rewards are not clickable"},
        {"test_name" : "Requesting edit reward through url " +\
            "redirects user to rewards index"},

        {"test_name" : "Messages accessible"},
        {"test_name" : "No create new message button"},
        {"test_name" : "Requesting create new message through url " +\
            "redirects user to messages index"},
        {"test_name" : "Sent messages are viewable"},
        {"test_name" : "Feedbacks are viewable"},
        {"test_name" : "No reply button"},
        {"test_name" : "Requesting reply through url " +\
            "redirects user to messages index"},
        {"test_name" : "No delete message button"},
        {"test_name" : "Requesting delete message through url " +\
            "redirects user to messages index"},

        {"test_name" : "Analysis accessible"},

        {"test_name" : "Employees accessible"},
        {"test_name" : "No register new employee button"},
        {"test_name" : "Requesting new employee registration"+\
            "redirects user to employees_index"},
        {"test_name" : "Approved employees are not clickable"},
        {"test_name" : "Requesting edit employee through url " +\
            "redirects user to employees index"},
        {"test_name" : "No remove button in approved employees"},
        {"test_name" : "Requesting remove employee through url " +\
            "redirects user to employees index"},
        {"test_name" : "No deny button in pending employees"},
        {"test_name" : "Requesting deny employee through url " +\
            "redirects user to employees index"},
        {"test_name" : "No approve button in pending employees"},
        {"test_name" : "Requesting approve employee through url " +\
            "redirects user to employees index"},

        {"test_name" : "Settings accessible"},
        {"test_name" : "No refresh button for retailer pin"},
        {"test_name" : "Requesting refresh through url returns " +\
            "a json object with error Permission denied"},
        {"test_name" : "Punches employee is readonly"},
        {"test_name" : "Punches facebook is readonly"},
        {"test_name" : "No save button"},
        {"test_name" : "No cancel changes button"},

        {"test_name" : "Workbench accessible"},
        {"test_name" : "Employee can punch"},
        {"test_name" : "Employee can reject redeem"},
        {"test_name" : "Employee can validate redeem"},

    ]
    section = {
        "section_name":\
            "Employee dashboard access working as expected?",
        "parts": parts,
    }
    test.results.append(section)

    try:
        # register the test employee
        register_employee("employee", "ex", TEST_EMPLOYEE['username'],
                          TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'],
                          settings.retailer_pin)
        sleep(3)
        employee_acc = Account.objects().get(username=TEST_EMPLOYEE[\
            'username'], include="Employee")
        employee = employee_acc.employee
    except Exception as e:
        print e

    ##########  Pending employee has no access
    try:
        test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'],
                   reverse("employees_index"))
        parts[0]['success'] =\
            test.find("#dialog-login-message").text ==\
            "You are not yet approved."
    except Exception as e:
        print e
        parts[0]['test_message'] = str(e)

    try:
        # login to approve
        test.login(TEST_USER['username'], TEST_USER['password'],
                   reverse("employees_index"))
        # approve
        test.find("#tab-pending-employees").click()
        approveRow = test.find("#tab-body-pending-employees " +\
            "div.tr")
        approveRow.find_element_by_css_selector(\
            "div.td.approve a.approve").click()
        sleep(1)
        test.switch_to_alert().accept()
        sleep(2)
        test.logout()
    except Exception as e:
        print e

    ##########  Approved employee initially not in store ACL
    try:
        # store.ACL = None cannot retrieve Parse built-ins!
        account = Account.objects().get(email=TEST_USER['username'],
                                        include="Store.Settings")
        store = account.store
        parts[1]['success'] = employee_acc.objectId not in store.ACL
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)

    ##########  Employee with ACCESS_NONE cannot login
    ###         using the login dialog
    try:
        test.dev_login()
        test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'])
        parts[2]['success'] =\
            test.find("#dialog-login-message").text ==\
            "You do not have permission to access the dashboard."
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)

    ##########  Employee with ACCESS_NONE cannot login
    ###         using the dedicated login page
    try:
        test.login(TEST_EMPLOYEE['username'], TEST_EMPLOYEE['password'],
                   reverse("employees_index"))
        parts[3]['success'] =\
            test.find("#dialog-login-message").text ==\
            "You do not have permission to access the dashboard."
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)

    ### Update the store's ACL
    store.ACL = {"*": {"read": True, "write": True}}
    store.set_access_level(employee_acc, ACCESS_PUNCHREDEEM[0])
    store.update()

    test.new_driver(False)

    ##########  Employee with ACCESS_PUNCHREDEEM can
    ###         login to the dashboard through the login dialog
    try:
        test.login(TEST_EMPLOYEE['username'],
                   TEST_EMPLOYEE['password'],
                   final_sleep=6)
        parts[4]['success'] = test.is_current_url(reverse("store_index"))
        test.logout()
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)

    ##########  Employee with ACCESS_PUNCHREDEEM can
    ###         login to the dashboard through the dedicated dialog page
    try:
        test.dev_login()
        test.login(TEST_EMPLOYEE['username'],
                   TEST_EMPLOYEE['password'],
                   reverse("employees_index"),
                   final_sleep=6)
        parts[5]['success'] = test.is_current_url(reverse("employees_index"))
        sleep(4)
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)

    ##########  Account settings accessible
    try:
        test.find("#header-right a").click()
        sleep(2)
        parts[6]['success'] = test.is_current_url(reverse("account_edit"))
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)

    ##########  No edit store detail button
    try:
        test.open(reverse("store_index"))
        sleep(2)
        test.set_to_implicit_wait(False)
        try:
            test.find("#store-details a[href='%s']" %
                      (reverse("store_edit"), ))
        except NoSuchElementException:
            parts[7]['success'] = True

    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting edit store detail through url
    ###         redirects user to store details
    try:
        test.open(reverse("store_edit"))
        sleep(2)
        parts[8]['success'] = test.is_current_url(reverse("store_index")+\
            "?" + urlencode({'error': "Permission denied"}))
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)

    ##########  No update subscription button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#account-options a[href='%s']" %\
                (reverse("subscription_update"),))
        except NoSuchElementException:
            parts[9]['success'] = True
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting update subscription through url
    ###         redirects user to store index
    try:
        test.open(reverse("subscription_update"))
        sleep(2)
        parts[10]['success'] = test.is_current_url(reverse(\
            "store_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)

    ##########  No deactivate my store button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#deactivate_account")
        except NoSuchElementException:
            parts[11]['success'] = True
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting store deactivation through url
    ###         redirects user to store index
    try:
        test.open(reverse("store_deactivate"))
        sleep(2)
        parts[12]['success'] = test.is_current_url(reverse(\
            "store_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)

    ##########  Rewards accessible
    try:
        test.open(reverse("rewards_index"))
        sleep(2)
        parts[13]['success'] = test.is_current_url(reverse("rewards_index"))
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)

    ##########  No create new reward button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#add_reward")
        except NoSuchElementException:
            parts[14]['success'] = True

    except Exception as e:
        print e
        parts[14]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting create new reward through url
    ###         redirects user to rewards index
    try:
        test.open(reverse("reward_edit", args=(-1, )))
        sleep(2)
        parts[15]['success'] = test.is_current_url(reverse(\
            "rewards_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)

    ##########  Rewards are not clickable
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("div.tr.reward a")
        except NoSuchElementException:
            parts[16]['success'] = True

    except Exception as e:
        print e
        parts[16]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting edit reward through url
    ###         redirects user to rewards index
    try:
        test.open(reverse("reward_edit", args=\
            (int(test.find("div.tr.reward").get_attribute("id")),)))
        sleep(3)
        parts[17]['success'] = test.is_current_url(reverse(\
            "rewards_index")+ "?" + urlencode({'error':\
            "Permission denied"}))
    except Exception as e:
        print e
        parts[17]['test_message'] = str(e)

    ##########  Messages accessible
    try:
        test.open(reverse("messages_index"))
        sleep(3)
        parts[18]['success'] = test.is_current_url(reverse(\
            "messages_index"))
    except Exception as e:
        print e
        parts[18]['test_message'] = str(e)

    ##########  No create new message button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#create_message")
        except NoSuchElementException:
            parts[19]['success'] = True

    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting create new message through url
    ###         redirects user to messages index
    try:
        test.open(reverse("message_edit", args=("0", )))
        sleep(3)
        parts[20]['success'] = test.is_current_url(reverse(\
            "messages_index")+ "?" + urlencode({'error':\
            "Permission denied"}))

    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)

    ##########  Sent messages are viewable
    try:
        row = test.find("#tab-body-sent div.tr a")
        # get id from /manage/messages/H1llFritVJ/details
        message_id = MESSAGE_DETAIL_RE.search(\
            row.get_attribute("href")).group(1)
        row.click()
        sleep(3)
        parts[21]['success'] = test.is_current_url(reverse(\
            "message_details", args=(message_id,)))

    except Exception as e:
        print e
        parts[21]['test_message'] = str(e)

    ##########  Feedbacks are viewable
    try:
        test.open(reverse("messages_index"))
        sleep(2)
        test.find("#tab-feedback").click()
        sleep(1)
        row = test.find("#tab-body-feedback div.tr a")
        # get id from /manage/messages/feedback/H1llFritVJ
        feedback_id = row.get_attribute("href").split("/")[-1]
        row.click()
        sleep(3)
        parts[22]['success'] = test.is_current_url(reverse(\
            "feedback_details", args=(feedback_id,)))

    except Exception as e:
        print e
        parts[22]['test_message'] = str(e)

    ##########  No reply button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#reply-button")
        except NoSuchElementException:
            parts[23]['success'] = True

    except Exception as e:
        print e
        parts[23]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting reply through url
    ###         redirects user to messages index
    try:
        test.open(reverse("feedback_reply", args=(feedback_id, )))
        sleep(3)
        parts[24]['success'] = test.is_current_url(reverse(\
            "messages_index")+ "?" + urlencode({'error':\
            "Permission denied"}) + "&tab_feedback=1")

    except Exception as e:
        print e
        parts[24]['test_message'] = str(e)

    ##########  No delete message button
    try:
        test.open(reverse("feedback_details", args=(feedback_id, )))
        sleep(3)
        test.set_to_implicit_wait(False)
        try:
            test.find("#delete-button")
        except NoSuchElementException:
            parts[25]['success'] = True

    except Exception as e:
        print e
        parts[25]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting delete message through url
    ###         redirects user to messages index
    try:
        test.open(reverse("feedback_delete", args=(feedback_id, )))
        sleep(2)
        parts[26]['success'] = test.is_current_url(reverse(\
            "messages_index")+ "?" + urlencode({'error':\
            "Permission denied"}) + "&tab_feedback=1")

    except Exception as e:
        print e
        parts[26]['test_message'] = str(e)

    ##########  Analysis accessible
    try:
        test.open(reverse("analysis_index"))
        sleep(4)
        parts[27]['success'] = test.is_current_url(reverse(\
            "analysis_index"))

    except Exception as e:
        print e
        parts[27]['test_message'] = str(e)

    ##########  Employees accessible
    try:
        test.open(reverse("employees_index"))
        sleep(4)
        parts[28]['success'] = test.is_current_url(reverse(\
            "employees_index"))

    except Exception as e:
        print e
        parts[28]['test_message'] = str(e)

    ##########  No register new employee button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#register_employee")
        except NoSuchElementException:
            parts[29]['success'] = True

    except Exception as e:
        print e
        parts[29]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting new employee registration
    ###         redirects user to employees_index
    try:
        test.open(reverse("employee_register"))
        sleep(3)
        parts[30]['success'] = test.is_current_url(reverse(\
            "employees_index")+ "?" + urlencode({'error':\
            "Permission denied"}))

    except Exception as e:
        print e
        parts[30]['test_message'] = str(e)

    ##########  Approved employees are not clickable
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#tab-body-approved-employees div.tr a")
        except NoSuchElementException:
            parts[31]['success'] = True

    except Exception as e:
        print e
        parts[31]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting edit employee through url
    ###         redirects user to employees index
    try:
        row = test.find("#tab-body-approved-employees div.tr")
        employee_id = row.get_attribute("id")
        test.open(reverse("employee_edit", args=(employee_id, )))
        sleep(3)
        parts[32]['success'] = test.is_current_url(reverse(\
            "employees_index")+ "?" + urlencode({'error':\
            "Permission denied"}))

    except Exception as e:
        print e
        parts[32]['test_message'] = str(e)

    ##########  No remove button in approved employees
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#tab-body-approved-employees div.tr "+\
                "div.remove a")
        except NoSuchElementException:
            parts[33]['success'] = True

    except Exception as e:
        print e
        parts[33]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting remove employee through url
    ###         redirects user to employees index
    try:
        test.open(reverse("employee_delete", args=(employee_id, )))
        sleep(3)
        parts[34]['success'] = test.is_current_url(reverse(\
            "employees_index")+ "?" + urlencode({'error':\
            "Permission denied"}))

    except Exception as e:
        print e
        parts[34]['test_message'] = str(e)

    # create a pending
    register_rand_employee(store.objectId)
    test.new_driver(False)
    test.login(TEST_EMPLOYEE['username'],
               TEST_EMPLOYEE['password'],
               reverse("employees_index"),
               final_sleep=6)

    ##########  No deny button in pending employees
    try:
        test.find("#tab-pending-employees").click()
        sleep(1)
        test.set_to_implicit_wait(False)
        try:
            test.find("#tab-body-pending-employees div.tr "+\
                "div.deny a")
        except NoSuchElementException:
            parts[35]['success'] = True

    except Exception as e:
        print e
        parts[35]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting deny employee through url
    ###         redirects user to employees index
    try:
        test.find("#tab-pending-employees").click()
        row = test.find("#tab-body-pending-employees div.tr")
        employee_id = row.get_attribute("id")
        test.open(reverse("employee_deny", args=(employee_id, )))
        sleep(3)
        parts[36]['success'] = test.is_current_url(reverse(\
            "employees_index") + "?" + urlencode({'error':\
            "Permission denied"}))

    except Exception as e:
        print e
        parts[36]['test_message'] = str(e)

    ##########  No approve button in pending employees
    try:
        test.find("#tab-pending-employees").click()
        sleep(1)
        test.set_to_implicit_wait(False)
        try:
            test.find("#tab-body-pending-employees div.tr "+\
                "div.approve a")
        except NoSuchElementException:
            parts[37]['success'] = True

    except Exception as e:
        print e
        parts[37]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting approve employee through url
    ###         redirects user to employees index
    try:
        test.open(reverse("employee_approve", args=(employee_id, )))
        sleep(3)
        parts[38]['success'] = test.is_current_url(reverse(\
            "employees_index") + "?" + urlencode({'error':\
            "Permission denied"}))

    except Exception as e:
        print e
        parts[38]['test_message'] = str(e)

    ##########  Settings accessible
    try:
        test.open(reverse("store_settings"))
        sleep(3)
        parts[39]['success'] = test.is_current_url(reverse(\
            "store_settings"))

    except Exception as e:
        print e
        parts[39]['test_message'] = str(e)

    ##########  No refresh button for retailer pin
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#link_refresh_retailer_pin")
        except NoSuchElementException:
            parts[40]['success'] = True

    except Exception as e:
        print e
        parts[40]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Requesting refresh through url returns
    ###         a json object with error Permission denied
    try:
        test.open(reverse("refresh_retailer_pin"))
        sleep(3)
        parts[41]['success'] = "Permission denied" in\
            test.driver.page_source
    except Exception as e:
        print e
        parts[41]['test_message'] = str(e)

    ##########  Punches employee is readonly
    try:
        test.open(reverse("store_settings"))
        sleep(3)
        parts[42]['success'] =\
            test.find("#id_punches_employee").get_attribute(\
                "readonly") == "true"
    except Exception as e:
        print e
        parts[42]['test_message'] = str(e)

    ##########  Punches facebook is readonly
    try:
        parts[43]['success'] =\
            test.find("#id_punches_facebook").get_attribute(\
                "readonly") == "true"
    except Exception as e:
        print e
        parts[43]['test_message'] = str(e)

    ##########  No save button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#settings-form-submit")
        except NoSuchElementException:
            parts[44]['success'] = True

    except Exception as e:
        print e
        parts[44]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  No cancel changes button
    try:
        test.set_to_implicit_wait(False)
        try:
            test.find("#settings-options a.red")
        except NoSuchElementException:
            parts[45]['success'] = True

    except Exception as e:
        print e
        parts[45]['test_message'] = str(e)
    finally:
        test.set_to_implicit_wait(True)

    ##########  Workbench accessible
    try:
        test.open(reverse("workbench_index"))
        sleep(3)
        parts[46]['success'] = test.is_current_url(\
            reverse("workbench_index"))
    except Exception as e:
        print e
        parts[46]['test_message'] = str(e)

    ##########  Employee can punch
    try:
        test.find("#punch_code").send_keys("00010")
        test.find("#punch_amount").send_keys("1")
        test.find("#punch-form a.button.blue").click()
        sleep(2)
        parts[47]['success'] =\
            test.find(".notification.hide") is not None
    except Exception as e:
        print e
        parts[47]['test_message'] = str(e)

    ##########  Employee can reject redeem
    try:
        request_redeem_ps("eiZa6Mzu7f")
        sleep(COMET_PULL_RATE * 2 + 4)
        row = test.find("#tab-body-pending-redemptions div.tr")
        test.find("//div[@id='%s']/" % (row.get_attribute("id"),) +\
            "div[contains(@class, 'redemption_redeem')]/a[2]",
            type="xpath").click()
        sleep(3)
        parts[48]['success'] = row.text.__contains__("Successfully")
    except Exception as e:
        print e
        parts[48]['test_message'] = str(e)

    ##########  Employee can validate redeem
    try:
        request_redeem_ps("eiZa6Mzu7f")
        sleep(COMET_PULL_RATE * 2 + 4)
        row = test.find("#tab-body-pending-redemptions div.tr")
        test.find("//div[@id='%s']/" % (row.get_attribute("id"),) +\
            "div[contains(@class, 'redemption_redeem')]/a[1]",
            type="xpath").click()
        sleep(3)
        parts[49]['success'] = row.text.__contains__("Successfully")
    except Exception as e:
        print e
        parts[49]['test_message'] = str(e)

    # END OF ALL TESTS - cleanup
    return test.tear_down()
예제 #37
0
def test_redemptions():
    """
    Tests for redemptions section of the workbench.
    Does not test offers/gifts.
    
    Assumes that at least 1 PatronStore exists for the above Store.
    Assumes that at least 1 reward exists for the above Store.
    """
    account = Account.objects().get(username=TEST_USER['username'],
        include="Store.Settings")
    store = account.store
    settings = store.settings
    ps = store.get("patronStores", include="Patron", limit=1)[0]
    patron = ps.patron
    
    reward = store.rewards[0]
    reward_id = reward["reward_id"]
    
    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Approving redeem works"},
        {'test_name': "PatronStore's punch_count is updated"},
        {'test_name': "PatronStore's pending_reward is set to false"},
        {'test_name': "The reward's redemption_count is updated"},
        {'test_name': "Rejecting redeem works"},
        {'test_name': "PatronStore's punch_count remains the same"},
        {'test_name': "PatronStore's pending_reward is set to false"},
        {'test_name': "Approved redeem is in the history tab"},
        {'test_name': "Rejected redeem is not in the history tab"},
        {'test_name': "Approving a redeem when the PatronStore does" +\
            " not have enough punches shows error"},
        {'test_name': "PatronStore's punch_count remains the same"},
        {'test_name': "PatronStore's pending_reward is set to false"},
        {'test_name': "Approving redeem from a PatronStore that does" +\
            " not exist shows error"},
    ]
    section = {
        "section_name": "Redeems working properly?",
        "parts": parts,
    }
    test.results.append(section)
    
    ##########  User needs to be logged in to access page
    test.open(reverse("workbench_index")) # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("workbench_index"))
        
    # login
    selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
    )
    test.action_chain(0, selectors, "send_keys") # ACTION!
    sleep(5) 
        
    ##########  Approving redeem works
    try:
        punch_count = ps.punch_count
        red_count = reward["redemption_count"]
    
        request_redeem_ps(ps.objectId, reward_id=reward_id, num_punches=1)
        sleep(COMET_PULL_RATE*2+4)
        row_id = test.find("#tab-body-pending-redemptions div.tr").get_attribute("id")
        test.find("//div[@id='tab-body-pending-redemptions']/"+\
            "div[contains(@class, 'tr')]/"+\
            "div[contains(@class, 'redemption_redeem')]/a[1]", type="xpath").click()
        sleep(4)
        parts[1]['success'] = test.find("#"+row_id).text.__contains__("Successfully")
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
        
    ##########  PatronStore's punch_count is updated
    try:
        ps.punch_count = None
        parts[2]['success'] = punch_count-1 == ps.get("punch_count")
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
        
    ##########  PatronStore's pending_reward is set to false
    try:
        ps.pending_reward = None
        parts[3]['success'] = not ps.get("pending_reward")
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
        
    ##########  The reward's redemption_count is updated
    try:
        store.rewards = None
        parts[4]['success'] = red_count+1 ==\
            store.get("rewards")[0]["redemption_count"]
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)
        
    ##########  Rejecting redeem works TODO
    try:
        pass 
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
        
    ##########  PatronStore's punch_count remains the same TODO
    try:
        pass 
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)
        
    ##########  PatronStore's pending_reward is set to false TODO
    try:
        pass 
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
        
    ##########  Approved redeem is in the history tab TODO
    try:
        pass 
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)
        
    ##########  Rejected redeem is not in the history tab TODO
    try:
        pass 
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
        
    ##########  Approving a redeem when the PatronStore does
    ###         not have enough punches shows error TODO
    try:
        pass 
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
        
    ##########  PatronStore's punch_count remains the same TODO
    try:
        pass 
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
        
    ##########  PatronStore's pending_reward is set to false TODO
    try:
        pass 
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)
        
        
    ##########  Approving redeem from a PatronStore that does
    ###         not exist shows error TODO
    try:
        pass 
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)
        
    
    # END OF ALL TESTS - cleanup
    return test.tear_down() 
예제 #38
0
def test_update_subscription():
    # TODO test place_order
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store.Subscription")
    store = account.store
    subscription = store.subscription
    subscription.update_locally(SUBSCRIPTION_INFO, False)
    subscription.update()

    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Update account page reachable"},
        {'test_name': "Changes to first name are visible"},
        {'test_name': "Changes to first name are saved to parse"},
        {'test_name': "Changes to last name are visible"},
        {'test_name': "Changes to last name are saved to parse"},
        {'test_name': "Changes to card number are visible"},
        {'test_name': "Changes to card number are saved to parse"},
        {'test_name': "A paypal credit card id is generated & saved"},
        {'test_name': "Changes to cc expiration are visible"},
        {'test_name': "Changes to cc expiration are saved to parse"},
        {'test_name': "Changes to address are visible"},
        {'test_name': "Changes to address are saved to parse"},
        {'test_name': "Changes to city are visible"},
        {'test_name': "Changes to city are saved to parse"},
        {'test_name': "Changes to state are visible"},
        {'test_name': "Changes to state are saved to parse"},
        {'test_name': "Changes to zip are visible"},
        {'test_name': "Changes to zip are saved to parse"},
        {'test_name': "First name is required"},
        {'test_name': "Last name is required"},
        {'test_name': "Card number is required"},
        {'test_name': "Security code (cvc) is required"},
        {'test_name': "Address is required"},
        {'test_name': "City is required"},
        {'test_name': "State is required"},
        {'test_name': "Zip is required"},
        {'test_name': "ToS checked is required"},
        {'test_name': "Invalid credit card number shows error"},
        {'test_name': "Past expiration date is invalid"},
        {'test_name': "Only the last 4 digits of the card number" +\
            " are shown"},
        {'test_name': "Not changing the card number does not " +\
            "generate new paypal credit card id"},
    ]
    section = {
        "section_name": "Edit account/subscription working properly?",
        "parts": parts,
    }
    self.results.append(section)

    ##########  User needs to be logged in to access page
    self.open(reverse("store_index"))
    sleep(1)
    parts[0]['success'] = self.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("store_index"))

    # login
    selectors = (("#login_username", TEST_USER['username']),
                 ("#login_password", TEST_USER['password']), ("", Keys.RETURN))
    self.action_chain(0, selectors, "send_keys")
    sleep(7)

    ##########  Update account page reachable
    try:
        self.find("//div[@id='account-options']/a[1]", type="xpath").click()
        sleep(3)
        parts[1]['success'] =\
            self.is_current_url(reverse("subscription_update"))
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)

    ## Make changes
    # first clear all inputs
    for el in self.find("input[type='text']", multiple=True):
        el.clear()

    selectors = (
        ("#id_first_name", TEST_SUBSCRIPTION_INFO['first_name']),
        ("#id_last_name", TEST_SUBSCRIPTION_INFO['last_name']),
        ("#id_cc_number", TEST_SUBSCRIPTION_INFO['cc_number']),
        ("#id_cc_cvv", "905"),
        ("#id_address", TEST_SUBSCRIPTION_INFO['address']),
        ("#id_city", TEST_SUBSCRIPTION_INFO['city']),
        ("#id_state", TEST_SUBSCRIPTION_INFO['state']),
        ("#id_zip", TEST_SUBSCRIPTION_INFO['zip']),
    )
    self.action_chain(0, selectors, action="send_keys")
    month_el =\
        self.find("//select[@id='id_date_cc_expiration_month']/" +\
            "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\
                'date_cc_expiration'].month),), type="xpath")
    year_el =\
        self.find("//select[@id='id_date_cc_expiration_year']/" +\
            "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\
                'date_cc_expiration'].year),), type="xpath")
    month = month_el.get_attribute("value")
    year = year_el.get_attribute("value")
    month_el.click()
    year_el.click()

    self.find("#id_recurring").click()
    self.find("#update-form-submit").click()
    sleep(5)

    # back to update account page
    self.find("//div[@id='account-options']/a[1]", type="xpath").click()
    sleep(3)

    ##########  Changes to first name are visible
    parts[2]['success'] =\
        self.find("#id_first_name").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['first_name']
    ##########  Changes to first name are saved to parse
    subscription.first_name = None
    parts[3]['success'] = subscription.get("first_name") ==\
        TEST_SUBSCRIPTION_INFO['first_name']
    ##########  Changes to last name are visible
    parts[4]['success'] =\
        self.find("#id_last_name").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['last_name']
    ##########  Changes to last name are saved to parse
    subscription.last_name = None
    parts[5]['success'] = subscription.get("last_name") ==\
        TEST_SUBSCRIPTION_INFO['last_name']
    ##########  Changes to card number are visible
    parts[6]['success'] =\
        self.find("#id_cc_number").get_attribute("value")[-4:] ==\
        TEST_SUBSCRIPTION_INFO['cc_number'][-4:]
    ##########  Changes to card number are saved to parse
    subscription.cc_number = None
    parts[7]['success'] = subscription.get("cc_number") ==\
        TEST_SUBSCRIPTION_INFO['cc_number'][-4:]
    ##########  A paypal credit card id is generated & saved
    # CARD-97223025G70599255KHHCCVQ
    subscription.pp_cc_id = None
    parts[8]['success'] = subscription.get("pp_cc_id").__contains__(\
        "CARD") and len(subscription.get("pp_cc_id")) == 29
    ##########  Changes to cc expiration are visible
    parts[9]['success'] = month == self.get_selected("//select" +\
        "[@id='id_date_cc_expiration_month']/option",
        type="xpath").get_attribute("value") and\
        year == self.get_selected(\
        "//select[@id='id_date_cc_expiration_year']/option",
        type="xpath").get_attribute("value")
    ##########  Changes to cc expiration are saved to parse
    subscription.date_cc_expiration = None
    exp = subscription.get("date_cc_expiration")
    parts[10]['success'] = exp.month == TEST_SUBSCRIPTION_INFO[\
        'date_cc_expiration'].month and exp.year ==\
        TEST_SUBSCRIPTION_INFO['date_cc_expiration'].year
    ##########  Changes to address are visible
    parts[11]['success'] =\
        self.find("#id_address").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['address']
    ##########  Changes to address are saved to parse
    subscription.address = None
    parts[12]['success'] = subscription.get("address") ==\
        TEST_SUBSCRIPTION_INFO['address']
    ##########  Changes to city are visible
    parts[13]['success'] =\
        self.find("#id_city").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['city']
    ##########  Changes to city are saved to parse
    subscription.city = None
    parts[14]['success'] = subscription.get("city") ==\
        TEST_SUBSCRIPTION_INFO['city']
    ##########  Changes to state are visible
    self.find("//select[@id='id_date_cc_expiration_year']/" +\
            "option[@value='%s']" % (str(TEST_SUBSCRIPTION_INFO[\
                'date_cc_expiration'].year)), type="xpath")
    parts[15]['success'] =\
        self.find("#id_state").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['state']
    ##########  Changes to state are saved to parse
    subscription.state = None
    parts[16]['success'] = subscription.get("state") ==\
        TEST_SUBSCRIPTION_INFO['state']
    ##########  Changes to zip are visible
    parts[17]['success'] =\
        self.find("#id_zip").get_attribute("value") ==\
        TEST_SUBSCRIPTION_INFO['zip']
    ##########  Changes to zip are saved to parse
    subscription.zip = None
    parts[18]['success'] = subscription.get("zip") ==\
        TEST_SUBSCRIPTION_INFO['zip']

    ## Make changes
    selectors = [
        "#id_first_name",
        "#id_last_name",
        "#id_cc_number",
        "#id_cc_cvv",
        "#id_address",
        "#id_city",
        "#id_state",
        "#id_zip",
    ]
    self.action_chain(0, selectors, action="clear")
    for i in range(len(selectors)):
        selectors[i] = (selectors[i], "    ")
    self.action_chain(0, selectors, action="send_keys")

    self.find("#update-form-submit").click()
    sleep(3)

    ##########  First name is required
    ##########  Last name is required
    ##########  Card number is required
    ##########  Security code (cvc) is required
    ##########  Address is required
    ##########  City is required
    ##########  State is required
    ##########  Zip is required
    ##########  ToS checked is required
    def field_is_required(part, selector, message="This field is required."):
        try:
            parts[part]['success'] = self.find(selector).text == message
        except Exception as e:
            print e
            parts[part]['test_message'] = str(e)

    selectors = (
        (19, "#first_name_ic ul.errorlist li"),
        (20, "#last_name_ic ul.errorlist li"),
        (21, "#card_number_container ul.errorlist li",
         "Enter a valid credit card number."),
        (22, "#cc_cvv_ic ul.errorlist li"),
        (23, "#address_ic ul.errorlist li"),
        (24, "#city_ic ul.errorlist li"),
        (25, "#state_ic ul.errorlist li"),
        (26, "#zip_ic ul.errorlist li"),
        (27, "#recurring_charge_container ul.errorlist li",
         "You must accept the Terms & Conditions to continue."),
    )

    for selector in selectors:
        field_is_required(*selector)

    ##########  Invalid credit card number shows error
    try:
        cc_number = self.find("#id_cc_number")
        cc_number.clear()
        cc_number.send_keys("8769233313929990")
        self.find("#update-form-submit").click()
        sleep(3)
        parts[28]['success'] = self.find("#card_number_container " +\
            "ul.errorlist li").text ==\
                "Enter a valid credit card number."
    except Exception as e:
        print e
        parts[28]['test_message'] = str(e)

    ##########  Past expiration date is invalid
    if timezone.now().month == 1:
        # note that if this test is being run on a January, this will
        # fail so to prevent that just skip the test if it is January
        parts[29]['test_message'] = "READ ME. This test has been " +\
            "skipped because the month is January, which means " +\
            "that this test will always fail due to limited " +\
            "select options."
    else:
        try:
            # select january of this year.
            self.find("//select[@id='id_date_cc_expiration_month']/" +\
                    "option[@value='1']", type="xpath").click()
            self.find("//select[@id='id_date_cc_expiration_year']/" +\
                    "option[@value='%s']" %\
                    (str(timezone.now().year),), type="xpath").click()
            self.find("#update-form-submit").click()
            sleep(3)
            parts[29]['success'] =\
                self.find("#date_cc_expiration_ic ul.errorlist " +\
                "li").text == "Your credit card has expired!"
        except Exception as e:
            print e
            parts[29]['test_message'] = str(e)

    ##########  Only the last 4 digits of the card number are shown
    try:
        self.find("//div[@class='form-options']/a[2]", type="xpath").click()
        sleep(1)
        self.find("//div[@id='account-options']/a[1]", type="xpath").click()
        sleep(3)
        masked_number =\
            self.find("#id_cc_number").get_attribute("value")
        parts[30]['success'] = masked_number[:-4] ==\
            "************" and str(masked_number[-4:]).isdigit()
    except Exception as e:
        print e
        parts[30]['test_message'] = str(e)

    ##########  Not changing the card number does not
    ######      generate new paypal credit card id
    try:
        subscription.pp_cc_id = None
        cc_id = subscription.get("pp_cc_id")
        self.find("#id_cc_cvv").send_keys("123")
        self.find("#id_recurring").click()
        self.find("#update-form-submit").click()
        sleep(5)
        subscription.pp_cc_id = None
        parts[31]['success'] = cc_id == subscription.get("pp_cc_id")
    except Exception as e:
        print e
        parts[31]['test_message'] = str(e)

    # END OF ALL TESTS - cleanup
    return self.tear_down()
예제 #39
0
def test_cancel_account():
    """
    A test just for the cancel account link.
    """
    account = Account.objects().get(username=TEST_USER['username'],
                                    include="Store")
    store = account.store

    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Clicking the cancel button brings up a " +\
            "confirmation dialog"},
        {'test_name': "Clicking cancel on the dialog dimisses the " +\
            "dialog and the account remains active"},
        {'test_name': "Clicking OK logs the user out"},
        {'test_name': "Clicking OK sets the store's active field " +\
            "to false on Parse"},
    ]
    section = {
        "section_name": "Deactivate store link functional?",
        "parts": parts,
    }
    self.results.append(section)

    ##########  User needs to be logged in to access page
    self.open(reverse("store_index"))
    sleep(1)
    parts[0]['success'] = self.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("store_index"))

    # login
    selectors = (("#login_username", TEST_USER['username']),
                 ("#login_password", TEST_USER['password']), ("", Keys.RETURN))
    self.action_chain(0, selectors, "send_keys")
    sleep(7)

    ##########  Clicking the cancel button brings up a confrmtn dialog
    try:
        self.find("#deactivate_account").click()
        sleep(1)
        alert = self.switch_to_alert()
        parts[1]['success'] = alert is not None
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)

    ##########  Clicking cancel on the dialog dimisses the
    ###         dialog and the account remains active
    try:
        alert.dismiss()
        try:
            alert.text
        except NoAlertPresentException:
            store.active = None
            parts[2]['success'] = store.get("active")
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)

    ##########  Clicking OK logs the user out
    try:
        self.find("#deactivate_account").click()
        sleep(1)
        alert = self.switch_to_alert()
        alert.accept()
        sleep(4)
        if SeleniumTest.DEV_LOGIN:
            parts[3]["success"] =\
                self.is_current_url(reverse("manage_dev_login")+"?next=/")
        else:
            parts[3]["success"] =\
                self.is_current_url(reverse("public_home"))
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)

    ##########  Clicking OK sets the store's active
    ###         field to false on Parse
    store.active = None
    parts[4]['success'] = not store.get("active")

    # undo
    store.active = True
    store.update()

    # END OF ALL TESTS - cleanup
    return self.tear_down()
예제 #40
0
def test_feedbacks():
    """
    This test also tests cloud code send_feedback.
    """
    # we can clear the list locally but just re-pull from parse
    account = Account.objects().get(username=TEST_USER['username'],
        include="Store.Subscription")
    store = account.store
    subscription = store.subscription
    
    
    account = Account.objects().get(username=TEST_PATRON['username'],
        include="Patron")
    patron = account.patron
        
    # make sure that the account is not used for these tests
    account = None
    
    # clear the received messages relation
    received_messages = store.get("receivedMessages", keys="")
    if received_messages:
        store.remove_relation("ReceivedMessages_",
            [m.objectId for m in received_messages])
            
    store.set("receivedMessages", None)
 
    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Cloud code send_feedback works"},
        {'test_name': "Notification badge appears if there are" +\
            " unread feedbacks"},
        {'test_name': "A new row appears when feedback is received"},
        {'test_name': "Feedback is initially unread (dashboard)"},
        {'test_name': "Feedback is in store's ReceivedMessages " +\
            "relation and is initially unread"},
        {'test_name': "Clicking the row redirects user to the " +\
            "feedback detail page"},
        {'test_name': "Clicking back to feedback inbox redirects " +\
            "user back to messages index with feedback tab active"},
        {'test_name': "Feedback is now read (dashboard)"},
        {'test_name': "Feedback is now read (Parse)"},
        {'test_name': "Clicking reply redirects user to feedback " +\
            "reply page"},
        {'test_name': "Reply body is required."},
        {'test_name': "Replying redirects user back to feedback " +\
            "details"},
        {'test_name': "The reply is visible"},
        {'test_name': "The reply message is saved in the store's " +\
            "sent messages relation with message_type of feedback"},
        {'test_name': "The reply message is saved in the Patron's " +\
            "received messages relation wrapped in a Message Status"},
        {'test_name': "A feedback with a reply does not have a " +\
            "reply button"},
        {'test_name': "Clicking delete message prompts the user " +\
            "to confirm the deletion"},
        {'test_name': "The user is redirected to messages index " +\
            "with feedback tab active"},
        {'test_name': "Deleting the reply only removes the message" +\
            " from the store's sent messages relation"},
        {'test_name': "The deleted feedback is no longer in " +\
            "the table"},
        {'test_name': "Multiple feedbacks (testing 3 here) " +\
            "can appear at the same time"},
    ]
    section = {
        "section_name": "Receiving messages works?",
        "parts": parts,
    }
    test.results.append(section)
    
    ##########  User needs to be logged in to access page
    test.open(reverse("messages_index")) # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("messages_index"))
        
    # login
    selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
    )
    test.action_chain(0, selectors, "send_keys") # ACTION!
    sleep(5) 
    
    def send_feedback(subject, body):
        """ This is a consumer action - not dashboard """
        return cloud_call("send_feedback", {
            "store_id": store.objectId,
            "patron_id": patron.objectId,
            "sender_name": patron.get_fullname(),
            "subject": subject,
            "body": body,
        })
    
    def feedback_id(feedback_tr):
        return feedback_tr.find_element_by_css_selector(\
            "a").get_attribute("href").split("/")[-1]
        
    def feedback_unread(feedback_tr):
        """ check parse if the fb is unread """
        fb_id = feedback_id(feedback_tr)
        store.set("receivedMessages", None)
        msg = store.get("receivedMessages", objectId=fb_id)
        if msg and len(msg) > 0:
           return not msg[0].is_read
        
        return False
        
    ##########  Cloud code send_feedback works
    try:
        parts[1]['success'] = send_feedback("feedback #1",
            "body #1").get("result") == "success"
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
        
    ##########  Notification badge appears if there are
    ###         unread feedbacks
    try:
        sleep(COMET_PULL_RATE*2 + 2)
        parts[2]['success'] = test.element_exists("#messages-nav " +\
            "a div.nav-item-badge")
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
    
    ##########  A new row appears when feedback is received 
    try:
        test.find("#tab-feedback").click()
        feedbacks =\
            test.find("#tab-body-feedback div.tr", multiple=True)
        parts[3]['success'] = len(feedbacks) > 0
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
    ##########  Feedback is initially unread (dashboard)
    try:
        parts[4]['success'] =\
            feedbacks[0].get_attribute("class").__contains__("unread")
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)
    
    ##########  Feedback is in store's ReceivedMessages
    ###         relation and is initially unread 
    try:
        parts[5]['success'] = feedback_unread(feedbacks[0])
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
    ##########  Clicking the row redirects user to the 
    ###         feedback detail page
    try:
        fb_id = feedback_id(feedbacks[0])
        feedbacks[0].find_element_by_css_selector("a").click()
        sleep(2)
        parts[6]['success'] = test.is_current_url(reverse(\
            "feedback_details", args=(fb_id,)))
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)
    ##########  Clicking back to feedback inbox redirects 
    ###         user back to messages index with feedback tab active 
    try:
        test.find("#back_to_feedback").click()
        sleep(1)
        parts[7]['success'] =\
            test.find("#tab-feedback").get_attribute(\
            "class").__contains__("active")
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
    ##########  Feedback is now read (dashboard) 
    try:
        feedbacks =\
            test.find("#tab-body-feedback div.tr", multiple=True)
        parts[8]['success'] =  not feedbacks[0].get_attribute(\
            "class").__contains__("unread")
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)
    ##########  Feedback is now read (Parse)
    try:
        parts[9]['success'] = not feedback_unread(feedbacks[0])
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
    ##########  Clicking reply redirects user to feedback reply page
    try:
        fb_id = feedback_id(feedbacks[0])
        feedbacks[0].find_element_by_css_selector("a").click()
        sleep(2)
        test.find("#reply-button").click()
        sleep(1)
        parts[10]['success'] = test.is_current_url(reverse(\
            "feedback_reply", args=(fb_id,)))
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    ##########  Reply body is required. 
    try:
        test.find("#body").send_keys("     ")
        test.find("#reply-form-submit").click()
        sleep(2)
        parts[11]['success'] = test.find("div.notification.hide " +\
            "div").text == "Please enter a message."
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
    ##########  Replying redirects user back to feedback details
    try:
        test.find("#body").send_keys("Hey")
        test.find("#reply-form-submit").click()
        parts[12]['success'] = test.is_current_url(reverse(\
            "feedback_details", args=(fb_id,)) +\
            "?%s" % urlencode({'success':\
            'Reply has been sent.'}))
        sleep(5)
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)
    ##########  The reply is visible
    try:
        parts[13]['success'] = test.find("#reply-box " +\
            "div.sect.body").text == "Hey"
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)
    ##########  The reply message is saved in the store's 
    ###         sent messages relation with message_type of feedback
    try:
        test.find("#back_to_feedback").click()
        sleep(1)
        store.set("sentMessages", None)
        store.set("receivedMessages", None)
        parts[14]['success'] = len(store.get("sentMessages",
            objectId=store.get("receivedMessages", 
            objectId=fb_id)[0].Reply, message_type=FEEDBACK)) > 0
    except Exception as e:
        print e
        parts[14]['test_message'] = str(e)
    ##########  The reply message is saved in the Patron's 
    ###         received messages relation wrapped in a Message Status 
    try:
        patron.set("receivedMessages", None)
        parts[15]['success'] = len(patron.get("receivedMessages",
            Message=fb_id)) > 0
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    ##########  A feedback with a reply does not have a reply button
    try:
        feedbacks =\
            test.find("#tab-body-feedback div.tr", multiple=True)
        feedbacks[0].find_element_by_css_selector("a").click()
        sleep(2)
        parts[16]['success'] = not test.element_exists(\
            "#reply-form-submit")
    except Exception as e:
        print e
        parts[16]['test_message'] = str(e)
    ##########  Clicking delete message prompts the user 
    ###         to confirm the deletion
    try:
        test.find("#delete-button").click()
        sleep(1)
        alert = test.switch_to_alert()
        parts[17]['success'] = alert.text ==\
            "Are you sure you want to delete this feedback thread?"
    except Exception as e:
        print e
        parts[17]['test_message'] = str(e)
    ##########  The user is redirected to messages index 
    ###         with feedback tab active
    try:
        alert.accept()
        sleep(4)
        parts[18]['success'] =\
            test.find("#tab-feedback").get_attribute(\
            "class").__contains__("active")
    except Exception as e:
        print e
        parts[18]['test_message'] = str(e)
    ##########  Deleting the reply only removes the message
    ###         from the store's sent messages relation 
    try:
        store.set("receivedMessages", None)
        parts[19]['success'] = not store.get("receivedMessages",
            objectId=fb_id, message_type=FEEDBACK)
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
    ##########  The deleted feedback is no longer in the table 
    try:
        test.find("#tab-feedback").click()
        sleep(1)
        feedbacks =\
            test.find("#tab-body-feedback div.tr a[href='%s']" %\
                (fb_id,), multiple=True)
        parts[20]['success'] = len(feedbacks) == 0
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    ##########  Multiple feedbacks (testing 3 here) 
    ###         can appear at the same time 
    try:
        send_feedback("feedback #2", "body #2")
        send_feedback("feedback #3", "body #3")
        send_feedback("feedback #4", "body #4")
        sleep(COMET_PULL_RATE*3 + 4)
        feedbacks =\
            test.find("#tab-body-feedback div.tr a", multiple=True)
        parts[21]['success'] = len(feedbacks) == 3
    except Exception as e:
        print e
        parts[21]['test_message'] = str(e)
    
    
    # END OF ALL TESTS - cleanup
    return test.tear_down() 
예제 #41
0
def test_employee_registration():
    """
    Tests for employee registrain via dashboard.
    """
    # delete the employees and associated User objects in the relation
    account = Account.objects().get(email=TEST_USER['username'],
        include="Store.Settings")
    store = account.store
    settings = store.settings
    
    emps = store.get("employees")
    if emps:
        for emp in emps:
            Account.objects().get(Employee=emp.objectId).delete()
            emp.delete()
    store.set("employees", None) 
        
    test = SeleniumTest()
    parts = [
        {"test_name" : "Clicking register new employee button "+\
            " redirects user to employee register page."},
        {"test_name" : "New registered employee is immediately placed"+\
            " in the approved group."},
        {"test_name" : "Access level of new employee is the same as"+\
            " the one chosen in the registration form."},
            
        {"test_name" : "A valid email is required."},
        {"test_name" : "Email must be unique."},
        
        {"test_name" : "Email is required."},
        {"test_name" : "First name is required."},
        {"test_name" : "Last name is required."},
        {"test_name" : "Password is required."},
        {"test_name" : "Password confirm is required."},
        
        {"test_name" : "Passwords must match."},
        {"test_name" : "Password must be at least 6 characters long."},
        
    ]
    section = {
        "section_name":\
            "Employee registration functional?",
        "parts": parts,
    }
    test.results.append(section)

    test.login(TEST_USER['username'], TEST_USER['password'],
        reverse("employees_index"))
    
    ##########  Clicking register new employee button 
    ###         redirects user to employee register page.
    try:
        test.find("#register_employee").click()
        sleep(3)
        parts[0]['success'] = test.is_current_url(reverse("employee_register"))
    except Exception as e:
        print e
        parts[0]['test_message'] = str(e)
    
    ##########  New registered employee is immediately placed
    ###         in the approved group.
    try:
        acl = test.find("#id_acl option[selected]").get_attribute("value")
        
        selectors = (
            ("#id_email", TEST_EMPLOYEE['username']),
            ("#id_password", TEST_EMPLOYEE['password']),
            ("#id_confirm_password", TEST_EMPLOYEE['password']),
            ("#id_first_name", TEST_EMPLOYEE['first_name']),
            ("#id_last_name", TEST_EMPLOYEE['last_name']),
        )
        test.action_chain(0, selectors, action="send_keys")
        test.find("#register-employee-submit").click()
        sleep(7)
        test.open(reverse("employees_index"))
        sleep(3)
        parts[1]['success'] = test.find("#tab-body-approved-employees"+\
            " div.tr a div.td.first_name_approved").text ==\
            TEST_EMPLOYEE['first_name']
        
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
    
    ##########  Access level of new employee is the same as
    ###         the one chosen in the registration form.
    try:
        test.find("#tab-body-approved-employees div.tr a").click()
        sleep(2)
        parts[2]['success'] = acl ==\
            test.find("#ACL option[selected]").get_attribute("value")
    
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
        
    ##########  A valid email is required.
    try:
        test.open(reverse("employee_register"))
        sleep(2)
        test.find("#id_email").send_keys("jhfghjdfg@jfgh")
        test.find("#register-employee-submit").click()
        sleep(3)
        parts[3]['success'] = test.find("#email_ic > ul.errorlist > li").text ==\
            "Enter a valid email address."
        
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)    
    
    ##########  Email must be unique.
    try:
        selectors = (
            ("#id_email", TEST_EMPLOYEE['username']),
            ("#id_password", "123456123"),
            ("#id_confirm_password", "123456123"),
            ("#id_first_name", "YOLO"),
            ("#id_last_name", "BOLO"),
        )
        test.action_chain(0, selectors, action="clear")
        test.action_chain(0, selectors, action="send_keys")
        test.find("#register-employee-submit").click()
        sleep(5)
        parts[4]['success'] = test.find("#email_ic > ul.errorlist > li").text ==\
            "Email is already being used."
            
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)
    
    ##########  Email is required.              5
    ##########  First name is required.         6
    ##########  Last name is required.          7
    ##########  Password is required.           8
    ##########  Password confirm is required.   9
    try:
        selectors = (
            "#id_email", 
            "#id_password",
            "#id_confirm_password",
            "#id_first_name",
            "#id_last_name",
        )
        test.action_chain(0, selectors, action="clear")
        test.find("#register-employee-submit").click()
        sleep(3)
        
        for i, sel in enumerate(selectors):
            id = sel.replace("#id_", "") + "_ic"
            parts[i+5]['success'] =\
                test.find("#%s > ul.errorlist > li" % (id,)).text ==\
                "This field is required."
        
    except Exception as e:
        print e
        for i, sel in enumerate(selectors):
            parts[i+5]['test_message'] = str(e)
    
    ##########  Passwords must match.
    try:
        selectors = (
            ("#id_password", "123456"),
            ("#id_confirm_password", "abcdefg"),
        )
        test.action_chain(0, selectors, action="clear")
        test.action_chain(0, selectors, action="send_keys")
        test.find("#register-employee-submit").click()
        sleep(3)
        parts[10]['success'] = test.find("#password_ic > ul.errorlist > li").text ==\
            "Passwords don't match."
        
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    
    ##########  Password must be at least 6 characters long.
    try:
        test.find("#id_password").clear()
        test.find("#id_password").send_keys("123")
        test.find("#register-employee-submit").click()
        sleep(3)
        parts[11]['success'] =\
            test.find("#password_ic > ul.errorlist > li").text ==\
            "Ensure this value has at least 6 characters (it has 3)."
        
    except Exception as e:
        print e
        parts[11]['success'] = str(e)


    # END OF ALL TESTS - cleanup
    return test.tear_down() 
예제 #42
0
def register(request):
    """ 
    Adds a new employee to the currently logged in Store.
    This automatically sets this employee to approved.
    """
    data = {'employees_nav': True}
    
    settings = SESSION.get_settings(request.session)
    store = SESSION.get_store(request.session)
    
    if request.method == "POST":
        from_associated_account = False
        # check if this post is from the associated account dialog
        # if it is then skip form validations
        aaf_nonce_id = request.POST.get('aaf-nonce')
        aaf_account_id = request.POST.get('aaf-account_id')
        if len(aaf_nonce_id) > 0 and len(aaf_account_id) > 0:
            aa_nonce = AssociatedAccountNonce.objects.filter(\
                id=aaf_nonce_id, account_id=aaf_account_id)
            if len(aa_nonce) > 0 and aa_nonce[0].verified:
                aa_nonce[0].delete()
                from_associated_account = True
        
        account_form = EmployeeAccountSignUpForm(request.POST)
        employee_form = EmployeeForm(request.POST)
        
        if not from_associated_account:
            all_forms_valid = account_form.is_valid() and\
                employee_form.is_valid()
        else:
            all_forms_valid = True
            
        if all_forms_valid:
            postDict = request.POST.dict()
            
            # make the cloud call
            # see cloud param for possible access level values
            acl = postDict['acl']
            if acl == ACCESS_ADMIN[0]:
                access_level = "admin"
            elif acl == ACCESS_PUNCHREDEEM[0]:
                access_level = "punch_redeem"
            else:
                access_level = None
            
            params = {
                "retailer_pin": settings.get("retailer_pin"),
                "username": postDict['email'].strip().lower(),
                "first_name": postDict['first_name'].capitalize(),
                "last_name": postDict['last_name'].capitalize(),
                "email": postDict['email'].strip().lower(),
                "status": APPROVED,
                "access_level": access_level,
            }
            
            if from_associated_account:
                res = cloud_call("link_employee", params)
            else:
                params["password"] = postDict['password']
                res = cloud_call("register_employee", params)
                
            # don't forget to retrieve the latest session
            request.session.clear()
            request.session.update(SessionStore(request.session.session_key))
            
            # check if email already taken here to handle the case where 
            # the user already has a patron/employee account 
            # but also want to sign up for a Store account
            if "error" in res and res['error'] in ("EMAIL_TAKEN_AVAILABLE",
                "USERNAME_TAKEN_AVAILABLE"):
                aa = Account.objects().get(email=postDict['email'].strip().lower())
                aan = AssociatedAccountNonce.objects.create(\
                    account_id=aa.objectId)
                return HttpResponse(json.dumps({"associated_account":\
                    aa.objectId, "associated_account_nonce":aan.id,
                    "email": aa.email, "code": 0}), 
                    content_type="application/json")
            elif "error" in res and res['error'] in ("EMAIL_TAKEN",
                "USERNAME_TAKEN"):
                account_form._errors.setdefault("email",
                    ErrorList()).append(u"Email is already being used.")
            elif "error" not in res:
                # add the employee to the approved list
                employees_approved_list =\
                    SESSION.get_employees_approved_list(request.session)
                employees_approved_ids =\
                    [ emp.objectId for emp in employees_approved_list ]
                    
                new_employee = Employee(**res["result"])
                if new_employee.objectId not in employees_approved_ids:
                    employees_approved_list.insert(0, new_employee)
                    request.session['employees_approved_list'] =\
                        employees_approved_list
                    
                # update our local store's acl - don't wait for 
                # the cloud post
                store = SESSION.get_store(request.session)
                store.set_access_level(Account.objects().get(\
                    email=postDict['email'].strip().lower()), acl)
                request.session['store'] = store
                
                # notify other dashboards of this change
                payload = {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "updatedStore":store.jsonify()
                }
                comet_receive(store.objectId, payload)
                        
                return HttpResponse(json.dumps({"code": 2}), 
                        content_type="application/json")
            else:
                return HttpResponse(json.dumps({"code": 3}), 
                        content_type="application/json") 
                    
    else:
        employee_form = EmployeeForm(initial={"acl":\
            ACCESS_PUNCHREDEEM[0]})
        account_form = EmployeeAccountSignUpForm()
        
    data["employee_form"] = employee_form
    data["account_form"] = account_form
        
    return render(request, 'manage/employee_register.djhtml', data)    
예제 #43
0
def test_rewards():
    # setup
    account = Account.objects().get(username=TEST_USER['username'],
        include="Store")
    store = account.store
    # start with no rewards
    store.rewards = []
    store.update()
    
    test = SeleniumTest()
    parts = [
        {'test_name': "User needs to be logged in to access page"},
        {'test_name': "Having no rewards shows a placeholder row"},
        {'test_name': "Adding a reward works"},
        {'test_name': "The new reward is saved to parse"},
        {'test_name': "Redemption count starts at 0"},
        {'test_name': "Reward id starts at 0"},
        {'test_name': "Updating a reward works"},
        {'test_name': "The updated reward is saved to parse"},
        {'test_name': "The updated reward retains the reward_id"},
        {'test_name': "The updated reward retains the " +\
            "redemption_count"},
        {'test_name': "Clicking delete brings up a confirmation " +\
            "dialog"},
        {'test_name': "Deleting a reward works"},
        {'test_name': "The deleted reward is deleted from parse"},
        {'test_name': "Reward name is required"},
        {'test_name': "Punches is required"},
        {'test_name': "Description is not required"},
        {'test_name': "Clicking cancel redirects user " +\
            "back to rewards index"},
        {'test_name': "Punches must be a number"},
        {'test_name': "Punches must be greater than 0"},
        {'test_name': "Rewards are initially sorted by Punches " +\
            "from least to greatest"},
        {'test_name': "Punches is sortable"},
        {'test_name': "Name is sortable"},
        {'test_name': "Updating a reward with the reset redemption" +\
            " count option resets the redemption count to 0"},
    ]
    section = {
        "section_name": "Rewards page working properly?",
        "parts": parts,
    }
    test.results.append(section)
    
    ##########  User needs to be logged in to access page
    test.open(reverse("rewards_index")) # ACTION!
    sleep(1)
    parts[0]['success'] = test.is_current_url(reverse(\
        'manage_login') + "?next=" + reverse("rewards_index"))
        
    # login
    selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
    )
    test.action_chain(0, selectors, "send_keys") # ACTION!
    sleep(7)  
    
    ##########  Having no rewards shows a placeholder row 
    try:
        parts[1]['success'] =\
            test.find("//div[@id='rewards_section']/div[@class=" +\
            "'tr reward']/div[@class='td reward_summary']/span[1]",
            type="xpath").text == "No Rewards"
    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)
        
    def add_reward(name, description, punches):
        test.find("#add_reward").click()
        sleep(1)
        selectors = (
            ("#id_reward_name", name),
            ("#id_description", description),
            ("#id_punches", str(punches)),
        )
        test.action_chain(0, selectors, action="send_keys")
        test.find("#submit-reward-form").click()
        sleep(5)
        
    reward1_name = "Reward #1"
    reward1_description = "First reward"
    reward1_punches = 5
    ##########  Adding a reward works 
    try:
        add_reward(reward1_name, reward1_description, reward1_punches)
        parts[2]['success'] = test.find("//div[@id='0']/a/div[2]" +\
            "/span[1]", type="xpath").text == reward1_name
    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)
    ##########  The new reward is saved to parse
    try:
        store.rewards = None
        reward = store.get("rewards")[0]
        parts[3]['success'] = reward['reward_name'] ==\
            reward1_name and reward['description'] ==\
            reward1_description and\
            reward['punches'] == reward1_punches
    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)
    ##########  Redemption count starts at 0
    try:
        parts[4]['success'] = reward['redemption_count'] == 0
    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)
    
    ##########  Redemption count starts at 0
    try:
        parts[5]['success'] = reward['reward_id'] == 0
    except Exception as e:
        print e
        parts[5]['test_message'] = str(e)
        
    # let's add 3 more rewards!
    reward2_name = "reward dos"
    reward2_description = "DOS"
    reward2_punches = 10
    reward3_name = "reward tres"
    reward3_description = "TRES"
    reward3_punches = 12
    reward4_name = "reward quatro"
    reward4_description = "QUATRO"
    reward4_punches = 15
    
    add_reward(reward2_name, reward2_description, reward2_punches)
    add_reward(reward3_name, reward3_description, reward3_punches)
    add_reward(reward4_name, reward4_description, reward4_punches)
    ################
    
    reward1_name = "reward uno"
    reward1_description = "UNO"
    reward1_punches = 1
    ##########  Updating a reward works
    try:
        test.find("//div[@id='0']/a", type="xpath").click()
        sleep(1)
        selectors = (
            ("#id_reward_name", reward1_name),
            ("#id_description", reward1_description),
            ("#id_punches", str(reward1_punches)),
        )
        test.action_chain(0, selectors, action="clear")
        test.action_chain(0, selectors, action="send_keys")
        test.find("#submit-reward-form").click()
        sleep(4)
        parts[6]['success'] = test.find("//div[@id='0']/a/div[2]" +\
            "/span[1]", type="xpath").text == reward1_name
    except Exception as e:
        print e
        parts[6]['test_message'] = str(e)
    ##########  The updated reward is saved to parse
    try:
        store.rewards = None
        reward = store.get("rewards")[0] # list is sorted by punches
        parts[7]['success'] = reward['reward_name'] ==\
            reward1_name and\
            reward['description'] == reward1_description and\
            reward['punches'] == reward1_punches
    except Exception as e:
        print e
        parts[7]['test_message'] = str(e)
    ##########  The updated reward retains the reward_id 
    try:
        parts[8]['success'] = reward['reward_id'] == 0
    except Exception as e:
        print e
        parts[8]['test_message'] = str(e)
    ##########  The updated reward retains the redemption_count 
    try:
        parts[9]['success'] = reward['redemption_count'] == 0
    except Exception as e:
        print e
        parts[9]['test_message'] = str(e)
    ##########  Clicking delete brings up a confirmation dialog 
    try:
        test.find("//div[@id='0']/a", type="xpath").click()
        sleep(1)
        test.find("#delete-link").click()
        alert = test.switch_to_alert()
        parts[10]['success'] = alert is not None
    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)
    ##########  Deleting a reward works
    try:
        alert.accept()
        sleep(5)
        parts[11]['success'] = test.find("//div[@id='1']/a/div[2]" +\
            "/span[1]", type="xpath").text == reward2_name
        try: # first reward should be gone
            test.find("//div[@id='0']/a/div[2]" +\
                "/span[1]", type="xpath").text
        except Exception:
            parts[11]['success'] = parts[11]['success']
        else:
            parts[11]['success'] = False
    except Exception as e:
        print e
        parts[11]['test_message'] = str(e)
    ##########  The deleted reward is deleted from parse 
    try:
        store.rewards = None
        rewards = store.get("rewards")
        parts[12]['success'] = reward1_name not in\
            [r['reward_name'] for r in rewards] and\
            0 not in [r['reward_id'] for r in rewards]
    except Exception as e:
        print e
        parts[12]['test_message'] = str(e)
        
    # field required
    add_reward("   ", "", "")
        
    ##########  Reward name is required
    try:
        parts[13]['success'] =\
            test.find("#reward_name_ic ul li").text ==\
                "This field is required."
    except Exception as e:
        print e
        parts[13]['test_message'] = str(e)
    ##########  Punches is required
    try:
        parts[14]['success'] =\
            test.find("#punches_ic ul li").text ==\
                "This field is required."
    except Exception as e:
        print e
        parts[14]['test_message'] = str(e)
    ##########  Description is not required 
    try:
        parts[15]['success'] =\
            not test.element_exists("#description_ic ul li")
    except Exception as e:
        print e
        parts[15]['test_message'] = str(e)
    ##########  Clicking cancel redirects user back to rewards index
    try:
        test.find("//div [@id='edit-reward-options']/a[2]", 
            type="xpath").click()
        sleep(2)
        parts[16]['success'] =\
            test.is_current_url(reverse("rewards_index"))
    except Exception as e:
        print e
        parts[16]['test_message'] = str(e)
    ##########  Punches must be a number
    try:
        add_reward("", "", "ba")
        parts[17]['success'] =\
            test.find("#punches_ic ul li").text ==\
                "Enter a whole number."
        test.find("//div [@id='edit-reward-options']/a[2]", 
            type="xpath").click()
        sleep(2)
    except Exception as e:
        print e
        parts[17]['test_message'] = str(e)
        
    ##########  Punches must be greater than 0 
    try:
        add_reward("", "", "0")
        parts[18]['success'] =\
            test.find("#punches_ic ul li").text ==\
                "Ensure this value is greater than or equal to 1."
        test.find("//div [@id='edit-reward-options']/a[2]", 
            type="xpath").click()
        sleep(2)
    except Exception as e:
        print e
        parts[18]['test_message'] = str(e)
    
    
    ##########  Rewards are initially sorted by Punchess
    ###         from least to greatest
    try:
        store.rewards = None
        rewards = store.get('rewards')
        punches_map = {r['punches']:r for r in rewards}
        ascending = [r['punches'] for r in rewards]
        descending = ascending[:]
        ascending.sort()
        descending.sort(reverse=True)
        success = True
        for i in range(3):
            if int(test.find("//div[@id='%s']/a/div[1]" %(str(i+1),),
                type="xpath").text) != ascending[i]:
                success = False
                break
                
        parts[19]['success'] = success
    except Exception as e:
        print e
        parts[19]['test_message'] = str(e)
    ##########  Punches is sortable
    try:
        test.find("#header-reward_punches").click()
        rows = test.find("//div[@id='rewards_section']/" +\
            "div[contains(@class, 'reward')]",
            type="xpath", multiple=True)
            
        if len(rows) == len(descending):
            success = True
            for i in range(len(rows)):
                # check both the punches and id
                row = rows[i]
                if int(row.text.split("\n")[0]) !=\
                    descending[i] or int(row.get_attribute("id")) !=\
                    punches_map[descending[i]]['reward_id']:
                    success = False
                    break
                    
            parts[20]['success'] = success
            
    except Exception as e:
        print e
        parts[20]['test_message'] = str(e)
    ##########  Name is sortable
    try:
        name_map = {r['reward_name']:r for r in rewards}
        ascending = [r['reward_name'] for r in rewards]
        descending = ascending[:]
        ascending.sort()
        descending.sort(reverse=True)
        
        # ascending order
        test.find("#header-reward_summary").click()
        rows = test.find("//div[@id='rewards_section']/" +\
            "div[contains(@class, 'reward')]",
            type="xpath", multiple=True)
            
        if len(rows) == len(ascending):
            success1 = True
            for i in range(len(rows)):
                # check both the name and id
                row = rows[i]
                if row.text.split("\n")[1] !=\
                    ascending[i] or int(row.get_attribute("id")) !=\
                    name_map[ascending[i]]['reward_id']:
                    success1 = False
                    break
                    
        # descending order
        test.find("#header-reward_summary").click()
        rows = test.find("//div[@id='rewards_section']/" +\
            "div[contains(@class, 'reward')]",
            type="xpath", multiple=True)
            
        if len(rows) == len(descending):
            success2 = True
            for i in range(len(rows)):
                # check both the name and id
                row = rows[i]
                if row.text.split("\n")[1] !=\
                    descending[i] or int(row.get_attribute("id")) !=\
                    name_map[descending[i]]['reward_id']:
                    success2 = False
                    break
                    
            parts[21]['success'] = success1 and success2
    except Exception as e:
        print e
        parts[21]['test_message'] = str(e)
        
    ##########  Updating a reward with the reset redemption
    ###         count option resets the redemption count to 0
    try:
        # logout
        test.logout()
        test.dev_login()
        sleep(1)
        # modify store the rewards redemption count
        store.rewards = None
        for r in store.get("rewards"):
            r['redemption_count'] = 99
        store.update()
        # login
        test.open(reverse("rewards_index")) # ACTION!
        sleep(1)
        selectors = (
        ("#login_username", TEST_USER['username']),
        ("#login_password", TEST_USER['password']),
        ("", Keys.RETURN)
        )
        test.action_chain(0, selectors, "send_keys") # ACTION!
        sleep(7)
        # now test
        test.find("//div[@id='2']/a", type="xpath").click()
        sleep(1)
        red_count = int(test.find("#redemption_count").text.split(" ")[1])
        test.find("#reset_red_count").click()
        test.find("#submit-reward-form").click()
        sleep(5)
        test.find("//div[@id='2']/a", type="xpath").click()
        new_red_count =\
            int(test.find("#redemption_count").text.split(" ")[1])
        parts[22]['success'] = new_red_count == 0 and red_count !=\
            new_red_count
    except Exception as e:
        print e
        parts[22]['test_message'] = str(e)
        
    
    # END OF ALL TESTS - cleanup
    return test.tear_down()
예제 #44
0
def employee_is_owner(session, employee_id):
    account = Account.objects().get(Employee=employee_id)
    return SESSION.get_store(session).is_owner(account)
예제 #45
0
def test_employee_registration():
    """
    Tests for employee registrain via dashboard.
    """
    # delete the employees and associated User objects in the relation
    account = Account.objects().get(email=TEST_USER['username'],
                                    include="Store.Settings")
    store = account.store
    settings = store.settings

    emps = store.get("employees")
    if emps:
        for emp in emps:
            Account.objects().get(Employee=emp.objectId).delete()
            emp.delete()
    store.set("employees", None)

    test = SeleniumTest()
    parts = [
        {"test_name" : "Clicking register new employee button "+\
            " redirects user to employee register page."},
        {"test_name" : "New registered employee is immediately placed"+\
            " in the approved group."},
        {"test_name" : "Access level of new employee is the same as"+\
            " the one chosen in the registration form."},

        {"test_name" : "A valid email is required."},
        {"test_name" : "Email must be unique."},

        {"test_name" : "Email is required."},
        {"test_name" : "First name is required."},
        {"test_name" : "Last name is required."},
        {"test_name" : "Password is required."},
        {"test_name" : "Password confirm is required."},

        {"test_name" : "Passwords must match."},
        {"test_name" : "Password must be at least 6 characters long."},

    ]
    section = {
        "section_name":\
            "Employee registration functional?",
        "parts": parts,
    }
    test.results.append(section)

    test.login(TEST_USER['username'], TEST_USER['password'],
               reverse("employees_index"))

    ##########  Clicking register new employee button
    ###         redirects user to employee register page.
    try:
        test.find("#register_employee").click()
        sleep(3)
        parts[0]['success'] = test.is_current_url(reverse("employee_register"))
    except Exception as e:
        print e
        parts[0]['test_message'] = str(e)

    ##########  New registered employee is immediately placed
    ###         in the approved group.
    try:
        acl = test.find("#id_acl option[selected]").get_attribute("value")

        selectors = (
            ("#id_email", TEST_EMPLOYEE['username']),
            ("#id_password", TEST_EMPLOYEE['password']),
            ("#id_confirm_password", TEST_EMPLOYEE['password']),
            ("#id_first_name", TEST_EMPLOYEE['first_name']),
            ("#id_last_name", TEST_EMPLOYEE['last_name']),
        )
        test.action_chain(0, selectors, action="send_keys")
        test.find("#register-employee-submit").click()
        sleep(7)
        test.open(reverse("employees_index"))
        sleep(3)
        parts[1]['success'] = test.find("#tab-body-approved-employees"+\
            " div.tr a div.td.first_name_approved").text ==\
            TEST_EMPLOYEE['first_name']

    except Exception as e:
        print e
        parts[1]['test_message'] = str(e)

    ##########  Access level of new employee is the same as
    ###         the one chosen in the registration form.
    try:
        test.find("#tab-body-approved-employees div.tr a").click()
        sleep(2)
        parts[2]['success'] = acl ==\
            test.find("#ACL option[selected]").get_attribute("value")

    except Exception as e:
        print e
        parts[2]['test_message'] = str(e)

    ##########  A valid email is required.
    try:
        test.open(reverse("employee_register"))
        sleep(2)
        test.find("#id_email").send_keys("jhfghjdfg@jfgh")
        test.find("#register-employee-submit").click()
        sleep(3)
        parts[3]['success'] = test.find("#email_ic > ul.errorlist > li").text ==\
            "Enter a valid email address."

    except Exception as e:
        print e
        parts[3]['test_message'] = str(e)

    ##########  Email must be unique.
    try:
        selectors = (
            ("#id_email", TEST_EMPLOYEE['username']),
            ("#id_password", "123456123"),
            ("#id_confirm_password", "123456123"),
            ("#id_first_name", "YOLO"),
            ("#id_last_name", "BOLO"),
        )
        test.action_chain(0, selectors, action="clear")
        test.action_chain(0, selectors, action="send_keys")
        test.find("#register-employee-submit").click()
        sleep(5)
        parts[4]['success'] = test.find("#email_ic > ul.errorlist > li").text ==\
            "Email is already being used."

    except Exception as e:
        print e
        parts[4]['test_message'] = str(e)

    ##########  Email is required.              5
    ##########  First name is required.         6
    ##########  Last name is required.          7
    ##########  Password is required.           8
    ##########  Password confirm is required.   9
    try:
        selectors = (
            "#id_email",
            "#id_password",
            "#id_confirm_password",
            "#id_first_name",
            "#id_last_name",
        )
        test.action_chain(0, selectors, action="clear")
        test.find("#register-employee-submit").click()
        sleep(3)

        for i, sel in enumerate(selectors):
            id = sel.replace("#id_", "") + "_ic"
            parts[i+5]['success'] =\
                test.find("#%s > ul.errorlist > li" % (id,)).text ==\
                "This field is required."

    except Exception as e:
        print e
        for i, sel in enumerate(selectors):
            parts[i + 5]['test_message'] = str(e)

    ##########  Passwords must match.
    try:
        selectors = (
            ("#id_password", "123456"),
            ("#id_confirm_password", "abcdefg"),
        )
        test.action_chain(0, selectors, action="clear")
        test.action_chain(0, selectors, action="send_keys")
        test.find("#register-employee-submit").click()
        sleep(3)
        parts[10]['success'] = test.find("#password_ic > ul.errorlist > li").text ==\
            "Passwords don't match."

    except Exception as e:
        print e
        parts[10]['test_message'] = str(e)

    ##########  Password must be at least 6 characters long.
    try:
        test.find("#id_password").clear()
        test.find("#id_password").send_keys("123")
        test.find("#register-employee-submit").click()
        sleep(3)
        parts[11]['success'] =\
            test.find("#password_ic > ul.errorlist > li").text ==\
            "Ensure this value has at least 6 characters (it has 3)."

    except Exception as e:
        print e
        parts[11]['success'] = str(e)

    # END OF ALL TESTS - cleanup
    return test.tear_down()