Exemple #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
Exemple #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
Exemple #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
Exemple #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.'}))
Exemple #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.'}))
Exemple #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.'}))
Exemple #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.'}))
Exemple #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")
Exemple #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
Exemple #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
Exemple #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")
Exemple #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)
Exemple #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)
Exemple #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
Exemple #15
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()
Exemple #16
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() 
Exemple #17
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()
 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)
Exemple #19
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)
Exemple #20
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()
Exemple #21
0
def employee_is_owner(session, employee_id):
    account = Account.objects().get(Employee=employee_id)
    return SESSION.get_store(session).is_owner(account)
    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
Exemple #23
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()
Exemple #24
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()
Exemple #25
0
def login(request, requestDict, no_recaptcha=False):
    """ 
    This combines Django's authenticate and login functions.
    The request.POST must contain a username and password.

    If authentication is successful, account is updated_locally
    and adds the appropriate data to the request so that the user/
    account is recognized to be logged in.
    
    This will also cache some of the store's info in the session.
    Also checks if the store is active or not.
    
    Returns an Account object if the account subscription is active 
    and username and passwords are good. Otherwise, 0 if bad login 
    credentials (wrong pass or pointer to store does not exist) 
    and 1 if subscription is not active,
    2 if employee but no access, 3 if employee is still pending,
    4 if RECAPTCHA_TOKEN in session and recaptcha response fails.
    """
    # first check if the request is already logged in
    if request.session.get('account'):
        return request.session.get('account')

    # now check for recaptcha
    if not no_recaptcha and RECAPTCHA_TOKEN in request.session and\
        request.session[RECAPTCHA_TOKEN] >= RECAPTCHA_ATTEMPTS:
        is_valid = recaptcha.submit(
            request, requestDict['recaptcha_challenge_field'],
            requestDict['recaptcha_response_field']).is_valid
        if not is_valid:
            return 4

    # note that email is the same as username
    # email needs to be stripped and lowered
    res = account_login(requestDict['username'].strip().lower(),
                        requestDict['password'])

    if res and "error" not in res:
        # correct login credentials - remove recaptcha token if exist
        if not no_recaptcha:
            recaptcha.login_success(request.session, requestDict['username'])

        account = Account(**res)
        account.fetch_all()

        # If the Account has both a Store and Employee object,
        # log the user in as the Store owner - not employee
        store = None
        if account.Store:
            store = account.store
            account_type = "store"
        elif account.Employee:
            store = account.employee.get("store")
            employee = account.employee
            account_type = "employee"

        # if the User object has a store then we are good to go
        if store:
            store.fetch_all()

            # check if employee with no access level or still pending
            if account_type == "employee":
                if employee.status == PENDING:
                    return 3
                elif not store.has_access(account):
                    return 2

            settings = store.get("settings")
            subscription = store.get("subscription")

            if store.get('active'):
                request.session[SESSION_KEY] = res.get('sessionToken')

                # load all cache data!
                # IMPORTANT for parse.comet.receive to work properly
                # reason is that if user stays in 1 page, not all
                # cache data is loaded and things go wrong-
                # e.g. sending message from window 1 does not update
                # the message count in window 2
                request.session['subscription'] = subscription
                request.session['settings'] = settings
                request.session['store'] = store
                request.session['account'] = account

                if account_type == "employee":
                    request.session['employee'] = employee

                SESSION.load_all(request.session)

                # If value is None, the session reverts to using
                # the global session expiry policy.
                if "stay_in" in requestDict and PRODUCTION_SERVER:
                    request.session.set_expiry(None)
                # If value is 0, the user's session cookie will
                # expire when the user's Web browser is closed.
                else:
                    request.session.set_expiry(0)

                return account
            else:
                return 1
        else:
            if not no_recaptcha:
                recaptcha.login_fail(request.session, requestDict['username'])
            return 0
    else:
        if not no_recaptcha:
            recaptcha.login_fail(request.session, requestDict['username'])
        return 0
Exemple #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()
Exemple #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()
Exemple #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()
Exemple #29
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() 
Exemple #30
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
Exemple #31
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() 
 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
Exemple #33
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()
Exemple #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)
Exemple #35
0
def login(request, requestDict, no_recaptcha=False):
    """ 
    This combines Django's authenticate and login functions.
    The request.POST must contain a username and password.

    If authentication is successful, account is updated_locally
    and adds the appropriate data to the request so that the user/
    account is recognized to be logged in.
    
    This will also cache some of the store's info in the session.
    Also checks if the store is active or not.
    
    Returns an Account object if the account subscription is active 
    and username and passwords are good. Otherwise, 0 if bad login 
    credentials (wrong pass or pointer to store does not exist) 
    and 1 if subscription is not active,
    2 if employee but no access, 3 if employee is still pending,
    4 if RECAPTCHA_TOKEN in session and recaptcha response fails.
    """
    # first check if the request is already logged in 
    if request.session.get('account'):
        return request.session.get('account')
        
    # now check for recaptcha
    if not no_recaptcha and RECAPTCHA_TOKEN in request.session and\
        request.session[RECAPTCHA_TOKEN] >= RECAPTCHA_ATTEMPTS:
        is_valid = recaptcha.submit(request,
            requestDict['recaptcha_challenge_field'],
            requestDict['recaptcha_response_field']).is_valid
        if not is_valid:
            return 4
    
    # note that email is the same as username
    # email needs to be stripped and lowered
    res = account_login(requestDict['username'].strip().lower(),
        requestDict['password'])
                    
    if res and "error" not in res:
        # correct login credentials - remove recaptcha token if exist
        if not no_recaptcha:
            recaptcha.login_success(request.session,
                requestDict['username'])
    
        account = Account(**res)
        account.fetch_all()
        
        # If the Account has both a Store and Employee object,
        # log the user in as the Store owner - not employee
        store = None
        if account.Store:
            store = account.store
            account_type = "store"
        elif account.Employee:
            store = account.employee.get("store")
            employee = account.employee
            account_type = "employee"
        
        # if the User object has a store then we are good to go
        if store: 
            store.fetch_all()
        
            # check if employee with no access level or still pending
            if account_type == "employee":
                if employee.status == PENDING:
                    return 3
                elif not store.has_access(account):
                    return 2
            
            settings = store.get("settings")
            subscription = store.get("subscription")
        
            if store.get('active'):
                request.session[SESSION_KEY] = res.get('sessionToken')
                
                # load all cache data!
                # IMPORTANT for parse.comet.receive to work properly
                # reason is that if user stays in 1 page, not all
                # cache data is loaded and things go wrong-
                # e.g. sending message from window 1 does not update
                # the message count in window 2
                request.session['subscription'] = subscription
                request.session['settings'] = settings
                request.session['store'] = store
                request.session['account'] = account
                
                if account_type == "employee":
                    request.session['employee'] = employee
                
                SESSION.load_all(request.session)
                        
                # If value is None, the session reverts to using 
                # the global session expiry policy.
                if "stay_in" in requestDict and PRODUCTION_SERVER:
                    request.session.set_expiry(None)
                # If value is 0, the user's session cookie will 
                # expire when the user's Web browser is closed.
                else:
                    request.session.set_expiry(0)
                
                return account
            else:
                return 1
        else:
            if not no_recaptcha:
                recaptcha.login_fail(request.session,
                    requestDict['username'])
            return 0
    else:
        if not no_recaptcha:
            recaptcha.login_fail(request.session,
                requestDict['username'])
        return 0
Exemple #36
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()
Exemple #37
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)
Exemple #38
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() 
Exemple #39
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()
Exemple #40
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() 
Exemple #41
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()
Exemple #42
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()
Exemple #43
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() 
Exemple #44
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() 
Exemple #45
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)    
Exemple #46
0
    def processCometReceivedDict(session, postDict):
        employees_pending_list =\
            SESSION.get_employees_pending_list(session)
        employees_approved_list =\
            SESSION.get_employees_approved_list(session)
        messages_received_list =\
            SESSION.get_messages_received_list(session)
        redemptions_pending =\
            SESSION.get_redemptions_pending(session)
        redemptions_past =\
            SESSION.get_redemptions_past(session)

        #############################################################
        # FEEDBACKS_UNREAD ##################################
        newFeedback = postDict.get('newFeedback')
        if newFeedback:
            messages_received_ids =\
                [ fb.objectId for fb in messages_received_list ]
            m = Message(**newFeedback)
            if m.objectId not in messages_received_ids:
                messages_received_list.insert(0, m)

            session['messages_received_list'] =\
                messages_received_list

        #############################################################
        # FEEDBACK DELETED ##################################
        deletedFeedback = postDict.get("deletedFeedback")
        if deletedFeedback:
            fb = Message(**deletedFeedback)
            for i, mro in enumerate(messages_received_list):
                if fb.objectId == mro.objectId:
                    messages_received_list.pop(i)
                    break
            session['messages_received_list'] =\
                messages_received_list

        #############################################################
        # MESSAGE SENT ##################################
        # need to check if this new message is an original message
        # or a reply to a feedback (the message sent by the patron)!
        # also may increment the message count!
        newMessage = postDict.get("newMessage")
        if newMessage:
            messages_received_ids =\
                    [ fb.objectId for fb in messages_received_list ]
            messages_sent_list =\
                SESSION.get_messages_sent_list(session)
            messages_sent_ids =\
                [ msg.objectId for msg in messages_sent_list ]
            m = Message(**newMessage)
            if m.objectId not in messages_sent_ids and\
                m.message_type != FEEDBACK:
                messages_sent_list.insert(0, m)
                if 'message_count' in session:
                    session['message_count'] =\
                        int(session['message_count']) + 1
            # update an existing feedback
            if m.objectId in messages_received_ids and\
                m.message_type == FEEDBACK:
                for i, mrl in enumerate(messages_received_list):
                    if mrl.objectId == m.objectId:
                        messages_received_list.pop(i)
                        messages_received_list.insert(i, m)
                        break
            session['messages_received_list'] =\
                messages_received_list
            session['messages_sent_list'] = messages_sent_list

        #############################################################
        # EMPLOYEES_PENDING ##################################
        # must also check if employee is already approved!
        pendingEmployee = postDict.get("pendingEmployee")
        if pendingEmployee:
            employees_approved_ids =\
                [ emp.objectId for emp in employees_approved_list ]
            employees_pending_ids =\
                [ emp.objectId for emp in employees_pending_list ]
            e = Employee(**pendingEmployee)
            if e.objectId not in employees_pending_ids and\
                e.objectId not in employees_approved_ids:
                employees_pending_list.insert(0, e)

            session['employees_pending_list'] =\
                employees_pending_list

        #############################################################
        # EMPLOYEES APPROVED (pending to approved) #################
        approvedEmployee = postDict.get("approvedEmployee")
        if approvedEmployee:
            emp = Employee(**approvedEmployee)
            # first check if the employee is in the pending list
            # if not then check if it is already approved
            for i, emp_pending in\
                enumerate(employees_pending_list):
                if emp.objectId == emp_pending.objectId:
                    emp = employees_pending_list.pop(i)
                    emp.status = APPROVED
                    employees_approved_list.insert(0, emp)
                    break

            session['employees_pending_list'] =\
                employees_pending_list
            session['employees_approved_list'] =\
                employees_approved_list

        #############################################################
        # EMPLOYEES NEW (straight to approved) #################
        newEmployee = postDict.get("newEmployee")
        if newEmployee:
            employees_approved_ids =\
                [ emp.objectId for emp in employees_approved_list ]
            emp = Employee(**newEmployee)
            if emp.objectId not in employees_approved_ids:
                employees_approved_list.insert(0, emp)
                session['employees_approved_list'] =\
                    employees_approved_list

        #############################################################
        # EMPLOYEES DELETED/DENIED/REJECTED (pending/approved to pop)!
        deletedEmployee = postDict.get("deletedEmployee")
        if deletedEmployee:
            emp = Employee(**deletedEmployee)
            # check in approved emps
            for i, cop in enumerate(employees_approved_list):
                if cop.objectId == emp.objectId:
                    employees_approved_list.pop(i)
                    break

            # check in pending emps
            for i, cop in enumerate(employees_pending_list):
                if cop.objectId == emp.objectId:
                    employees_pending_list.pop(i)
                    break

            session['employees_approved_list'] =\
                employees_approved_list
            session['employees_pending_list'] =\
                employees_pending_list

        #############################################################
        # EMPLOYEE UPDATED PUNCHES
        updatedEmployeePunch = postDict.get("updatedEmployeePunch")
        if updatedEmployeePunch:
            u_emp = Employee(**updatedEmployeePunch)
            for emp in employees_approved_list:
                if u_emp.objectId == emp.objectId:
                    emp.set("lifetime_punches", u_emp.lifetime_punches)
                    break
            session['employees_approved_list'] =\
                employees_approved_list

        #############################################################
        # REDEMPTIONS PENDING
        ### Only added to cache if it has the store_location_id as
        ### active_store_location_id
        pendingRedemption = postDict.get("pendingRedemption")
        if pendingRedemption:
            rr = RedeemReward(**pendingRedemption)

            # store_location_id can be null for backwards compat
            if not rr.store_location_id or rr.store_location_id ==\
                session.get('active_store_location_id'):
                redemptions_pending_ids =\
                    [ red.objectId for red in redemptions_pending ]
                redemptions_past_ids =\
                    [ red.objectId for red in redemptions_past ]
                # need to check here if the redemption is new because
                # the dashboard that validated it will also receive
                # the validated redemption back.
                if rr.objectId not in redemptions_past_ids and\
                    rr.objectId not in redemptions_pending_ids:
                    redemptions_pending.insert(0, rr)

                session['redemptions_pending'] =\
                    redemptions_pending

        #############################################################
        # REDEMPTIONS APPROVED (pending to history)
        # Save cpu by skipping those that do not have the same
        # store_location_id as active_store_location_id
        approvedRedemption = postDict.get("approvedRedemption")
        if approvedRedemption:
            redemp = RedeemReward(**approvedRedemption)

            # store_location_id can be null for backwards compat
            if not redemp.store_location_id or redemp.store_location_id ==\
                session.get('active_store_location_id'):
                # check if redemp is still in pending
                for i, redem in enumerate(redemptions_pending):
                    if redem.objectId == redemp.objectId:
                        r = redemptions_pending.pop(i)
                        r.is_redeemed = True
                        r.updatedAt = redemp.updatedAt
                        redemptions_past.insert(0, r)
                        break
                # if not then check if it is in the history already
                # the above shouldn't happen!

                session['redemptions_pending'] =\
                    redemptions_pending
                session['redemptions_past'] =\
                    redemptions_past

        #############################################################
        # REDEMPTIONS DELETED ##############################
        # remove from pending (should not be in history!)
        # Save cpu by skipping those that do not have the same
        # store_location_id as active_store_location_id
        deletedRedemption = postDict.get("deletedRedemption")
        if deletedRedemption:
            redemp = RedeemReward(**deletedRedemption)

            # store_location_id can be null for backwards compat
            if not redemp.store_location_id or redemp.store_location_id ==\
                session.get('active_store_location_id'):
                # check if redemp is still in pending
                for i, redem in enumerate(redemptions_pending):
                    if redem.objectId == redemp.objectId:
                        redemptions_pending.pop(i)
                        break

                session['redemptions_pending'] =\
                    redemptions_pending

        #############################################################
        # STORE UPDATED ##############################
        updatedStore = postDict.get("updatedStore")
        if updatedStore:
            store = Store(**updatedStore)
            # have to add the image url manually
            store.thumbnail_image_url = updatedStore.get("thumbnail_image_url")
            store.cover_image_url = updatedStore.get("cover_image_url")
            # below here for backwards compat
            store.store_avatar_url = store.thumbnail_image_url
            session['store'] = store

        updatedStoreThumbnailName = postDict.get("updatedStoreThumbnailName")
        if updatedStoreThumbnailName:
            store = session['store']
            store.thumbnail_image = updatedStoreThumbnailName
            store.thumbnail_image_url = postDict.get(
                "updatedStoreThumbnailUrl")
            # below here for backwards compat
            store.store_avatar = store.thumbnail_image
            store.store_avatar_url = store.thumbnail_image_url
            session['store'] = store

        updatedStoreCoverName = postDict.get("updatedStoreCoverName")
        if updatedStoreCoverName:
            store = session['store']
            store.cover_image = updatedStoreCoverName
            store.cover_image_url = postDict.get("updatedStoreCoverUrl")
            session['store'] = store

        # this is in the settings tab in the dashboard but the field
        # is in the Store class
        updatedPunchesFacebook_int =\
            postDict.get("updatedPunchesFacebook_int")
        if updatedPunchesFacebook_int:
            store = session['store']
            store.punches_facebook = int(updatedPunchesFacebook_int)
            session['store'] = store

        #############################################################
        # STORE LOCATION UPDATED ##############################
        ### Note that this is also being used to insert new StoreLocations
        updatedStoreLocation = postDict.get("updatedStoreLocation")
        if updatedStoreLocation:
            store_location = StoreLocation(**updatedStoreLocation)
            session['store_locations'][store_location.objectId] =\
                store_location

            try:  # also update the store_timezone
                session['store_timezone'] =\
                    pytz.timezone(store_location.get('store_timezone'))
            except Exception:  # assign a default timezone
                session['store_timezone'] =\
                    pytz.timezone(TIME_ZONE)

        #############################################################
        # ACCOUNT UPDATED ##############################
        updatedAccount = postDict.get("updatedAccount")
        if updatedAccount:
            updatedAccountObject = Account(**updatedAccount)
            # need to make sure that these are the same accounts!
            if session['account'].objectId ==\
                updatedAccountObject.objectId:
                session['account'] = updatedAccountObject

        #############################################################
        # SUBSCRIPTION UPDATED ##############################
        updatedSubscription =\
            postDict.get("updatedSubscription")
        if updatedSubscription:
            subscription = Subscription(**updatedSubscription)
            store = session["store"]
            store.set('subscription', subscription)
            store.set('Subscription', subscription.objectId)
            session['subscription'] = subscription
            session['store'] = store

        #############################################################
        # SETTINGS UPDATED ##############################
        updatedSettings = postDict.get("updatedSettings")
        if updatedSettings:
            settings = Settings(**updatedSettings)
            store = session["store"]
            store.set('settings', settings)
            store.set("Settings", settings.objectId)
            session['settings'] = settings
            session['store'] = store

        #############################################################
        # REWARDS NEW ##############################
        newReward = postDict.get("newReward")
        if newReward:
            store = session['store']
            rewards = store.get("rewards")
            rewards_ids = [r['reward_id'] for r in rewards]
            if newReward['reward_id'] not in rewards_ids:
                rewards.append(newReward)
            store.rewards = rewards
            session['store'] = store

        #############################################################
        # REWARDS UPDATED ##############################
        updatedReward = postDict.get('updatedReward')
        if updatedReward:
            store = session['store']
            mod_rewards = store.get("rewards")
            for i, mreward in enumerate(mod_rewards):
                # [{"reward_name":"Free bottle of wine",
                # "description":"Must be under $25 in value",
                # "punches":10,"redemption_count":0,reward_id:0},]
                if updatedReward['reward_id'] == mreward['reward_id']:
                    if updatedReward.has_key("redemption_count"):
                        mod_rewards[i]['redemption_count'] =\
                            updatedReward['redemption_count']
                    if updatedReward.has_key("reward_name"):
                        mod_rewards[i]['reward_name'] =\
                            updatedReward['reward_name']
                    if updatedReward.has_key("punches"):
                        mod_rewards[i]['punches'] =\
                            updatedReward['punches']
                    if updatedReward.has_key("description"):
                        mod_rewards[i]['description'] =\
                            updatedReward['description']
                    break

            store.rewards = mod_rewards
            session['store'] = store

        #############################################################
        # REWARDS DELETED ##############################
        deletedReward = postDict.get("deletedReward")
        if deletedReward:
            store = session['store']
            rewards = store.get("rewards")
            rewards_ids = [r['reward_id'] for r in rewards]
            if deletedReward['reward_id'] in rewards_ids:
                for i, r in enumerate(rewards):
                    if r['reward_id'] == deletedReward['reward_id']:
                        rewards.pop(i)
                        break
            store.rewards = rewards
            session['store'] = store

        #############################################################
        # PATRONSTORE_COUNT ##################################
        patronStore_int = postDict.get('patronStore_int')
        if patronStore_int:
            patronStore_int = int(patronStore_int)
            session['patronStore_count'] = patronStore_int
Exemple #47
0
def employee_is_owner(session, employee_id):
    account = Account.objects().get(Employee=employee_id)
    return SESSION.get_store(session).is_owner(account)
Exemple #48
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()