Example #1
0
def refresh(request):
    """
    Returns a json response containing a new retailer_pin for the store.
    """

    if request.session.get('account') and\
            request.session.get(SESSION_KEY):
        data = {'success': False}
        settings = SESSION.get_settings(request.session)

        if settings == None:
            raise Http404
        else:
            settings.set('retailer_pin', Settings.generate_id())
            settings.update()

            # update the session cache
            request.session['settings'] = settings

            # notify other dashboards of these changes
            store = SESSION.get_store(request.session)
            payload = {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedSettings": settings.jsonify()
            }
            comet_receive(store.objectId, payload)

            data['success'] = True
            data['retailer_pin'] = settings.retailer_pin

        return HttpResponse(json.dumps(data), content_type="application/json")
    else:
        return HttpResponse(json.dumps({'success': False}),
                            content_type="application/json")
Example #2
0
def refresh(request):
    """
    Returns a json response containing a new retailer_pin for the store.
    """
    
    if request.session.get('account') and\
            request.session.get(SESSION_KEY):
        data = {'success': False}
        settings = SESSION.get_settings(request.session)
        
        if settings == None:
            raise Http404
        else:
            settings.set('retailer_pin', Settings.generate_id())
            settings.update()
            
            # update the session cache
            request.session['settings'] = settings
            
            # notify other dashboards of these changes
            store = SESSION.get_store(request.session)
            payload = {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedSettings":settings.jsonify()
            }
            comet_receive(store.objectId, payload)
            
            data['success'] = True
            data['retailer_pin'] = settings.retailer_pin
        
        return HttpResponse(json.dumps(data), content_type="application/json")
    else:
        return HttpResponse(json.dumps({'success': False}), content_type="application/json")
Example #3
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.'}))
Example #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.'}))
Example #5
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.'}))
Example #6
0
def punch(request):
    if request.method == "POST":
        try:
            nump = int(request.POST['num_punches'])
        except ValueError:
            return HttpResponse(json.dumps({'error': 'float'}),
                                content_type="application/json")

        settings = SESSION.get_settings(request.session)
        if nump > settings.get("punches_employee"):
            return HttpResponse(json.dumps({
                'error': 'over',
                'limit': nump
            }),
                                content_type="application/json")

        store = SESSION.get_store(request.session)
        data = {
            "store_location_id":\
                SESSION.get_active_store_location_id(request.session),
            "store_id":store.objectId,
            "store_name":str(store.get('store_name')),
            "punch_code":str(request.POST['punch_code']),
            "num_punches":nump,
        }

        # Check if the user is an employee
        employee = request.session.get("employee")
        if employee:
            data['employee_id'] = employee.objectId

        res = cloud_call("punch", data)
        if 'error' not in res:
            res['patron_name'] = res['result']
            # always make sure to get the latest session since the session
            # will be saved on return!!!
            request.session.clear()
            request.session.update(SessionStore(request.session.session_key))
            return HttpResponse(json.dumps(res),
                                content_type="application/json")
        else:
            if res['error'] == "PATRON_NOT_FOUND":
                request.session.clear()
                request.session.update(
                    SessionStore(request.session.session_key))
                return HttpResponse(json.dumps({"error":\
                    "PATRON_NOT_FOUND"}),
                    content_type="application/json")

    # always make sure to get the latest session since the session
    # will be saved on return!!!
    request.session.clear()
    request.session.update(SessionStore(request.session.session_key))
    return HttpResponse(json.dumps({'error': 'error'}),
                        content_type="application/json")
Example #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.'}))
Example #8
0
def settings(request):
    """
    Renders the settings page or handles changes to it.
    """
    data = {'settings_nav': True}
    store = SESSION.get_store(request.session)
    settings = SESSION.get_settings(request.session)

    # user made changes
    if request.method == 'POST':
        form = SettingsForm(request.POST)
        if form.is_valid():
            # expect numbers so cast to int
            dct = request.POST.dict().copy()
            dct['punches_employee'] = int(dct['punches_employee'])
            settings.update_locally(dct, False)
            settings.update()
            # Shin chose to move punches_facebook to Store...
            store.set("punches_facebook",
                      int(request.POST["punches_facebook"]))
            store.Settings = settings.objectId
            store.settings = settings
            store.update()

            # notify other dashboards of this changes
            payload = {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedSettings":settings.jsonify(),
                "updatedPunchesFacebook_int":\
                    store.punches_facebook,
            }
            comet_receive(store.objectId, payload)

            data['success'] = "Settings have been saved."
        else:
            data['error'] = 'Error saving settings.'

    # user navigated to this page so just render the settings template
    # with a filled settings form
    else:
        form = SettingsForm()
        form.initial = settings.__dict__.copy()
        # shin chose to move punches_facebook to Store...
        form.initial['punches_facebook'] =\
            store.get('punches_facebook')

    # update the session cache since we may have made changes above
    request.session['store'] = store
    request.session['settings'] = settings

    data['form'] = form
    data['settings'] = settings
    return render(request, 'manage/settings.djhtml', data)
Example #9
0
def settings(request):
    """
    Renders the settings page or handles changes to it.
    """
    data = {'settings_nav': True}
    store = SESSION.get_store(request.session)
    settings = SESSION.get_settings(request.session)
    
    # user made changes
    if request.method == 'POST':
        form = SettingsForm(request.POST)
        if form.is_valid(): 
            # expect numbers so cast to int
            dct = request.POST.dict().copy()
            dct['punches_employee'] = int(dct['punches_employee'])
            settings.update_locally(dct, False)
            settings.update()
            # Shin chose to move punches_facebook to Store...
            store.set("punches_facebook", 
                        int(request.POST["punches_facebook"]))
            store.Settings = settings.objectId
            store.settings = settings
            store.update()
            
            # notify other dashboards of this changes
            payload = {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedSettings":settings.jsonify(),
                "updatedPunchesFacebook_int":\
                    store.punches_facebook,
            }
            comet_receive(store.objectId, payload)

            data['success'] = "Settings have been saved."
        else:
            data['error'] = 'Error saving settings.'
            
    # user navigated to this page so just render the settings template
    # with a filled settings form
    else:
        form = SettingsForm()
        form.initial = settings.__dict__.copy()
        # shin chose to move punches_facebook to Store...
        form.initial['punches_facebook'] =\
            store.get('punches_facebook')
    
    # update the session cache since we may have made changes above
    request.session['store'] = store
    request.session['settings'] = settings
    
    data['form'] = form
    data['settings'] = settings
    return render(request, 'manage/settings.djhtml', data)
Example #10
0
 def _wrapped_view(request, *args, **kwargs):
     if SESSION.get_store(request.session).has_access(\
         request.session['account']):
         return view_func(request, *args, **kwargs)
     else:
         if http_response:
             resp = http_response
             if content_type == "application/json":
                 resp = json.dumps(http_response)
             return HttpResponse(resp, content_type=content_type)
         else:
             return redirect(reverse("manage_logout"))
Example #11
0
def index(request):
    """
    Render the analysis page.
    """
    # sort the rewards by redemption count in descending order
    rewards = SESSION.get_store(request.session).get("rewards")
    rewards.sort(key=lambda k: k['redemption_count'], reverse=True)

    return render(request, 'manage/analysis.djhtml', {
        'analysis_nav': True,
        'rewards': rewards,
    })
Example #12
0
 def _wrapped_view(request, *args, **kwargs):
     if SESSION.get_store(request.session).has_access(\
         request.session['account']):
         return view_func(request, *args, **kwargs)
     else:
         if http_response:
             resp = http_response
             if content_type == "application/json":
                 resp = json.dumps(http_response)
             return HttpResponse(resp, content_type=content_type)
         else:
             return redirect(reverse("manage_logout"))
Example #13
0
def index(request):
    """
    Render the analysis page.
    """
    # sort the rewards by redemption count in descending order
    rewards = SESSION.get_store(request.session).get("rewards")
    rewards.sort(key=lambda k: k['redemption_count'], reverse=True)
            
    return render(request, 'manage/analysis.djhtml', {
        'analysis_nav': True,
        'rewards': rewards,
    })
Example #14
0
def punch(request):
    if request.method == "POST":
        try:
            nump = int(request.POST['num_punches'])
        except ValueError:
            return HttpResponse(json.dumps({'error': 'float'}),
                content_type="application/json")
                
        settings = SESSION.get_settings(request.session)
        if nump > settings.get("punches_employee"):
            return HttpResponse(json.dumps({'error': 'over',
                'limit': nump}), content_type="application/json")
    
        store = SESSION.get_store(request.session)
        data = {
            "store_location_id":\
                SESSION.get_active_store_location_id(request.session),
            "store_id":store.objectId,
            "store_name":str(store.get('store_name')),
            "punch_code":str(request.POST['punch_code']),
            "num_punches":nump,
        }
        
        # Check if the user is an employee
        employee = request.session.get("employee")
        if employee:
            data['employee_id'] = employee.objectId
        
        res = cloud_call("punch", data)
        if 'error' not in res:
            res['patron_name'] = res['result']
            # always make sure to get the latest session since the session 
            # will be saved on return!!!            
            request.session.clear()        
            request.session.update(SessionStore(request.session.session_key))
            return HttpResponse(json.dumps(res), 
                    content_type="application/json")
        else:
            if res['error'] == "PATRON_NOT_FOUND":
                request.session.clear()        
                request.session.update(SessionStore(request.session.session_key))
                return HttpResponse(json.dumps({"error":\
                    "PATRON_NOT_FOUND"}), 
                    content_type="application/json")
            

    # always make sure to get the latest session since the session 
    # will be saved on return!!!     
    request.session.clear()                           
    request.session.update(SessionStore(request.session.session_key))
    return HttpResponse(json.dumps({'error': 'error'}),
        content_type="application/json")
Example #15
0
 def _wrapped_view(request, *args, **kwargs):
     if test_func(request):
         if SESSION.get_store(request.session) and\
             SESSION.get_store(request.session).active:
             # may not want to import parse.session here due
             # to cyclic imports
             timezone.activate(SESSION.get_store_timezone(\
                 request.session))
             try:
                 return view_func(request, *args, **kwargs)
             except KeyError:
                 return logout(request, "manage_login")
         else:
             return logout(request, "manage_login")
         
     # if http_response is provided and content_type is json
     # and request.is_ajax then this request if from comet.js
     if request.is_ajax() and http_response and\
         content_type == "application/json":
         # no need to update session- if it got here then the session is empty
         #request.session.clear()
         #request.session.update(SessionStore(request.session.session_key))
         return HttpResponse(json.dumps(http_response),
             content_type=content_type)
         
     path = request.build_absolute_uri()
     # If the login url is the same scheme and net location then just
     # use the path as the "next" url.
     login_scheme, login_netloc = urlparse.urlparse(login_url or
                                                 settings.LOGIN_URL)[:2]
     current_scheme, current_netloc = urlparse.urlparse(path)[:2]
     if ((not login_scheme or login_scheme == current_scheme) and
         (not login_netloc or login_netloc == current_netloc)):
         path = request.get_full_path()
     from django.contrib.auth.views import redirect_to_login
     # no need to update session- if it got here then the session is empty
     #request.session.clear()
     #request.session.update(SessionStore(request.session.session_key))
     return redirect_to_login(path, login_url, redirect_field_name)
Example #16
0
def image_get(request):
    """
    Returns a json response containing the cover and thumbnail url
    for the store.
    """
    if request.method == "GET":
        store = SESSION.get_store(request.session)
        return HttpResponse(json.dumps({
            "src_cover": store.cover_image_url,
            "src_thumbnail": store.thumbnail_image_url,
        }), content_type="application/json")
        
    raise Http404
Example #17
0
        def _wrapped_view(request, *args, **kwargs):
            if test_func(request):
                if SESSION.get_store(request.session) and\
                    SESSION.get_store(request.session).active:
                    # may not want to import parse.session here due
                    # to cyclic imports
                    timezone.activate(SESSION.get_store_timezone(\
                        request.session))
                    try:
                        return view_func(request, *args, **kwargs)
                    except KeyError:
                        return logout(request, "manage_login")
                else:
                    return logout(request, "manage_login")

            # if http_response is provided and content_type is json
            # and request.is_ajax then this request if from comet.js
            if request.is_ajax() and http_response and\
                content_type == "application/json":
                # no need to update session- if it got here then the session is empty
                #request.session.clear()
                #request.session.update(SessionStore(request.session.session_key))
                return HttpResponse(json.dumps(http_response),
                                    content_type=content_type)

            path = request.build_absolute_uri()
            # If the login url is the same scheme and net location then just
            # use the path as the "next" url.
            login_scheme, login_netloc = urlparse.urlparse(
                login_url or settings.LOGIN_URL)[:2]
            current_scheme, current_netloc = urlparse.urlparse(path)[:2]
            if ((not login_scheme or login_scheme == current_scheme)
                    and (not login_netloc or login_netloc == current_netloc)):
                path = request.get_full_path()
            from django.contrib.auth.views import redirect_to_login
            # no need to update session- if it got here then the session is empty
            #request.session.clear()
            #request.session.update(SessionStore(request.session.session_key))
            return redirect_to_login(path, login_url, redirect_field_name)
Example #18
0
def feedback(request, feedback_id):
    """
    Renders the feedback template with the stores feedbacks.
    """
    data = {
        'messages_nav': True,
        'feedback_id':feedback_id,
         "store_name":\
            SESSION.get_store(request.session).get("store_name"),
    }

    # get from the messages_received_list in session cache
    messages_received_list = SESSION.get_messages_received_list(\
        request.session)
    i_remove, feedback = 0, None
    for ind, m in enumerate(messages_received_list):
        if m.objectId == feedback_id:
            feedback = m
            i_remove = ind
            break

    if not feedback:
        # feedack not found - redirect to messages page with error message
        return redirect(reverse('messages_index')+ "?%s" %\
             urllib.urlencode({'error': 'Feedback not found.',
                "tab_feedback":1}))

    if not feedback.is_read:
        # update the feedback's read if not yet read
        feedback.is_read = True
        feedback.update()

    # make sure that the message stored in the list is the updated 1
    messages_received_list.pop(i_remove)
    messages_received_list.insert(i_remove, feedback)
    request.session['messages_received_list'] = messages_received_list

    # inserting this success and error message into the template
    # should be done in a cleaner way - this was done by the
    # first guy. I just didn't bother changing it.
    if request.GET.get("success"):
        data['success'] = request.GET.get("success")
    if request.GET.get("error"):
        data['error'] = request.GET.get("error")

    # there should only be at most 1 reply
    data['reply'] = feedback.get('reply')
    data['feedback'] = feedback

    return render(request, 'manage/feedback.djhtml', data)
Example #19
0
def edit(request):
    account = request.session['account']
    store = SESSION.get_store(request.session)
    email_form, pass_form, data = None, None, {}

    if request.method == "POST":
        action, success = request.POST['action'], None
        if action == "email":
            email_form = EmailForm(account, request.POST)
            if email_form.is_valid():
                success = "Successfully updated email."

                # Need to make sure that the account is the latest -
                # User in dashboard then signs up for a mobile account
                # and then edits store details = bug!
                account.fetch_all(clear_first=True, with_cache=False)
                # update the account - email = username!
                postEmail = email_form.cleaned_data['email']
                if account.email != postEmail:
                    account.email = postEmail
                    account.username = postEmail
                    account.update()

        elif action == "password":
            pass_form = PasswordForm(account, request.POST)
            if pass_form.is_valid():
                success = "Successfully updated password."
                account.set_password(pass_form.cleaned_data['new'])
                account.update(save_password=True)

        if success:
            data['success'] = success
            # notify other dashboards of these changes
            payload = {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedAccount": account.jsonify()
            }
            comet_receive(store.objectId, payload)
            request.session["account"] = account

    if not email_form:
        email_form = EmailForm(None)
        email_form.initial = request.session['account'].__dict__.copy()
    if not pass_form:
        pass_form = PasswordForm(None)

    data["email_form"] = email_form
    data["password_form"] = pass_form

    return render(request, 'manage/account_edit.html', data)
Example #20
0
def image_get(request):
    """
    Returns a json response containing the cover and thumbnail url
    for the store.
    """
    if request.method == "GET":
        store = SESSION.get_store(request.session)
        return HttpResponse(json.dumps({
            "src_cover":
            store.cover_image_url,
            "src_thumbnail":
            store.thumbnail_image_url,
        }),
                            content_type="application/json")

    raise Http404
Example #21
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)
Example #22
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)
Example #23
0
def index(request):
    """
    Render the rewards template with the store's rewards.
    """
    data = {'rewards_nav': True}
    store = SESSION.get_store(request.session)
    lst, rewards = [], store.get('rewards')

    if rewards:
        # record the pre-sorted reward
        presorted = [(reward['reward_id'], int(reward['punches']))
                     for reward in rewards]
        # cannot just use punches as the map since it is not unique
        reward_map = {(reward['reward_id'], int(reward['punches'])): reward
                      for reward in rewards}
        # get a sorted list of punches in descending order
        sorted_ = presorted[:]
        sorted_.sort(key=lambda r: r[1])

        sorted_rewards = [reward_map[p] for p in sorted_]
        store.rewards = sorted_rewards

        # do not just update needlessly check if order has changed.
        for i, pre in enumerate(presorted):
            if pre[0] != sorted_[i][0]:
                store.update()

        data['rewards'] = sorted_rewards

    # store has no rewards =(
    else:
        data['rewards'] = []

    # inserting this success and error message into the template
    # should be done in a cleaner way - this was done by the first guy
    # I just didn't bother changing it.
    if request.GET.get("success"):
        data['success'] = request.GET.get("success")
    if request.GET.get("error"):
        data['error'] = request.GET.get("error")

    # update session cache
    request.session['store'] = store

    return render(request, 'manage/rewards.djhtml', data)
Example #24
0
def delete(request, reward_id):
    """
    Deletes a reward with the given reward_id.
    """

    # check if the reward_id passed in is invalid and raise a 404 if so.
    # reward ids are integers
    try:
        reward_id = int(str(reward_id))
    except ValueError:
        raise Http404

    account = request.session['account']
    store = SESSION.get_store(request.session)
    rewards = store.get('rewards')
    rewards_map = {reward['reward_id']: reward for reward in rewards}

    # reward cannot be found for deletion. Redirect user to the rewards
    # page with a success message (maybe this should be an error message instead?).
    try:
        reward = rewards_map[reward_id]
    except KeyError:
        return redirect(reverse('rewards_index')+\
                "?%s" % urllib.urlencode({'success':\
                'Reward has been removed.'}))

    # notify other dashboards of this change
    payload = {
        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
        "deletedReward": {
            "reward_id": reward["reward_id"]
        }
    }
    comet_receive(store.objectId, payload)

    # update session cache
    store.array_remove('rewards', [reward])
    store.rewards = None
    store.get('rewards')
    request.session['store'] = store

    return redirect(reverse('rewards_index')+\
                "?%s" % urllib.urlencode({'success':\
                'Reward has been removed.'}))
Example #25
0
        def _wrapped_view(request, *args, **kwargs):
            if SESSION.get_store(request.session).is_admin(\
                request.session['account']) or (except_method and\
                request.method in except_method):
                return view_func(request, *args, **kwargs)
            else:
                if reverse_url:
                    reversed_url = reverse(reverse_url) + "?%s" %\
                        urlencode({'error': "Permission denied"})

                    if reverse_postfix:
                        reversed_url =\
                            reversed_url + "&" + reverse_postfix
                    return redirect(reversed_url)
                elif http_response:
                    resp = http_response
                    if content_type == "application/json":
                        resp = json.dumps(http_response)
                    return HttpResponse(resp, content_type=content_type)
                else:
                    raise Http404
Example #26
0
 def _wrapped_view(request, *args, **kwargs):
     if SESSION.get_store(request.session).is_admin(\
         request.session['account']) or (except_method and\
         request.method in except_method):
         return view_func(request, *args, **kwargs)
     else:
         if reverse_url:
             reversed_url = reverse(reverse_url) + "?%s" %\
                 urlencode({'error': "Permission denied"})
             
             if reverse_postfix:
                 reversed_url =\
                     reversed_url + "&" + reverse_postfix
             return redirect(reversed_url)
         elif http_response:
             resp = http_response
             if content_type == "application/json":
                 resp = json.dumps(http_response)
             return HttpResponse(resp, content_type=content_type)
         else:
             raise Http404
Example #27
0
def edit_store(request):
    """
    Render the edit store template or handle a form submission from it.
    """
    data = {'account_nav': True}
    store = SESSION.get_store(request.session)

    # validate form submission and redirect to store details if
    # success or re-render the store edit template with previous form
    # input and errors.
    if request.method == "POST":
        store_form = StoreForm(request.POST)

        if store_form.is_valid():
            store.update_locally(request.POST.dict(), False)
            store.update()

            # notify other dashboards
            comet_receive(
                store.objectId, {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "updatedStore": store.jsonify(),
                })

            # make sure that we have the latest session
            request.session.clear()
            request.session.update(SessionStore(request.session.session_key))

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

    # user navigates to this page so just render the store edit template
    # with a blank form.
    else:
        store_form = StoreForm()
        store_form.initial = store.__dict__.copy()

    data['store_form'] = store_form

    return render(request, 'manage/store_edit.html', data)
Example #28
0
def feedback_delete(request, feedback_id):
    """
    Handles requests to delete the feedback with the given feedback_id.
    """
    store = SESSION.get_store(request.session)

    # get the feedback from the messages_received_list in session cache
    messages_received_list = SESSION.get_messages_received_list(\
        request.session)
    i_remove, feedback = 0, None
    for ind, m in enumerate(messages_received_list):
        if m.objectId == feedback_id:
            feedback = m
            i_remove = ind
            break

    if not feedback:
        # feedback not found - it may have been deleted
        return redirect(reverse('messages_index')+ "?%s" %\
             urllib.urlencode({'error': 'Feedback not found.'}))

    # we don't actually delete the feedback object,
    # we just remove from the store's relation
    store.remove_relation("ReceivedMessages_", [feedback.objectId])

    # remove it from the messages_received_list in session cache
    messages_received_list.pop(i_remove)
    request.session['messages_received_list'] =\
        messages_received_list

    # notify other dashboards logged into the same store of this change
    comet_receive(
        store.objectId, {
            COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
            "deletedFeedback": Message(objectId=feedback.objectId).jsonify(),
        })

    return redirect(reverse('messages_index')+ "?%s" %\
        urllib.urlencode({'success':'Feedback has been deleted.',
            'tab_feedback':1}))
Example #29
0
def approve(request, employee_id):
    # 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.'}))
    
    employee.set('status', APPROVED)
    employee.update()
            
    employees_pending_list.pop(i_remove)
    request.session['employees_pending_list'] =\
        employees_pending_list
    
    # update session cache for employees_approved_list
    employees_approved_list = SESSION.get_employees_approved_list(\
        request.session)
    employees_approved_list.insert(0, employee)
    request.session['employees_approved_list'] =\
        employees_approved_list
        
    # notify other dashboards of this change
    store_id = SESSION.get_store(request.session).objectId
    approved_employee = Employee(objectId=employee.objectId)
    payload = {
        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
        "approvedEmployee":approved_employee.jsonify()
    }
    comet_receive(store_id, payload)
        
    return redirect(reverse('employees_index')+ "?show_pending&%s" %\
        urllib.urlencode({'success': 'Employee has been approved.'}))
Example #30
0
def approve(request, employee_id):
    # 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.'}))

    employee.set('status', APPROVED)
    employee.update()

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

    # update session cache for employees_approved_list
    employees_approved_list = SESSION.get_employees_approved_list(\
        request.session)
    employees_approved_list.insert(0, employee)
    request.session['employees_approved_list'] =\
        employees_approved_list

    # notify other dashboards of this change
    store_id = SESSION.get_store(request.session).objectId
    approved_employee = Employee(objectId=employee.objectId)
    payload = {
        COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
        "approvedEmployee": approved_employee.jsonify()
    }
    comet_receive(store_id, payload)

    return redirect(reverse('employees_index')+ "?show_pending&%s" %\
        urllib.urlencode({'success': 'Employee has been approved.'}))
Example #31
0
def edit_store(request):
    """
    Render the edit store template or handle a form submission from it.
    """
    data = {'account_nav': True}
    store = SESSION.get_store(request.session)
    
    # validate form submission and redirect to store details if
    # success or re-render the store edit template with previous form
    # input and errors.
    if request.method == "POST":
        store_form = StoreForm(request.POST)
        
        if store_form.is_valid():
            store.update_locally(request.POST.dict(), False)
            store.update()
            
            # notify other dashboards
            comet_receive(store.objectId, {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedStore": store.jsonify(),
            })

            # make sure that we have the latest session
            request.session.clear()
            request.session.update(SessionStore(request.session.session_key))
            
            return redirect(reverse('store_index')+ "?%s" %\
                urllib.urlencode({'success': 'Store details has been updated.'}))
        
    # user navigates to this page so just render the store edit template
    # with a blank form.
    else:
        store_form = StoreForm()
        store_form.initial = store.__dict__.copy()
        
    data['store_form'] = store_form 
    
    return render(request, 'manage/store_edit.html', data)
Example #32
0
def account_is_admin(session):
    return SESSION.get_store(session).is_admin(session['account'])
Example #33
0
def trends_graph(request, data_type=None, start=None, end=None):
    """
    Handles requests for the trends graph.
    """
    store = SESSION.get_store(request.session)

    # We need the store's timezone to convert everything to UTC
    # because the time we get from start and end are local times
    # and in order to convert to UTC we must first make start and end
    # timezone aware. We use parse.utils.make_aware_to_utc to do
    # this in 1 step. We convert everything to UTC for use in queries.
    store_timezone = SESSION.get_store_timezone(request.session)
    start = datetime.strptime(start, "%Y-%m-%d")
    end = datetime.strptime(end, "%Y-%m-%d")
    start = start.replace(hour=0, minute=0, second=0, microsecond=0)
    end = end.replace(hour=23, minute=59, second=59, microsecond=0)
    start_aware = make_aware_to_utc(start, store_timezone)
    end_aware = make_aware_to_utc(end, store_timezone)

    rows, columns = [], []

    if data_type == 'punches':
        # we need to return graph data for punches for all days in
        # between start and end.

        # columns contains the data that any given row needs to have.
        # rows contains multiple dates paired with punch count
        columns = [{
            "id": "",
            "label": "Date",
            "type": "string"
        }, {
            "id": "",
            "label": 'Punches',
            "type": "number"
        }]

        # get the Punches
        punches = store.get('punches',
                            createdAt__lte=end_aware,
                            createdAt__gte=start_aware,
                            order='createdAt',
                            limit=900)

        # have to clear the punches cache attr of store filled
        # by the above query
        store.punches = None

        #create dictionary for easy search
        punch_map = {}
        if punches:
            for punch in punches:
                # The keys in the punch map is the month/day of the
                # createdAt of the punch object. We also convert it
                # to the store's local time for when we send back the
                # data to the client.
                key = timezone.localtime(punch.createdAt,
                                         store_timezone).strftime("%m/%d")

                if key in punch_map:
                    # add to the punch count for the existing key
                    punch_map[key] =\
                        punch_map[key] + punch.get('punches')

                else:
                    # initialize the key in the punch map
                    punch_map[key] = punch.get('punches')

        for single_date in rputils.daterange(start, end):
            # we now populate the rows with the corresponding punch counts
            # str_date is a day in between start and end with the
            # same format as a key in our punch_map
            str_date = single_date.strftime("%m/%d")

            try:
                punch_count = punch_map[str_date]
            except KeyError:
                punch_count = 0

            # the first item in our row is the date
            # the second item is the corresponding punch_count
            row = [{"v": str_date}, {"v": punch_count}]
            rows.append({'c': row})

    elif data_type == 'facebook':
        # we need to return graph data for facebook posts for
        # all days in between start and end.

        # columns contains the data that any given row needs to have.
        # rows contains multiple dates paired with post count
        columns = [{
            "id": "",
            "label": "Date",
            "type": "string"
        }, {
            "id": "",
            "label": 'Posts',
            "type": "number"
        }]

        # get the FacebookPosts
        posts = store.get("facebookPosts",
                          createdAt__lte=end,
                          createdAt__gte=start,
                          limit=900)
        # have to clear the facebookPosts cache attr of store filled
        # by the above query
        store.facebookPosts = None

        #create dictionary for easy search
        post_map = {}
        if posts:
            for post in posts:
                # The keys in the post map is the month/day of the
                # createdAt of the punch object. We also convert it
                # to the store's local time for when we send back the
                # data to the client.
                key = timezone.localtime(post.createdAt,
                                         store_timezone).strftime("%m/%d")

                if key in post_map:
                    # add to the post count for the existing key
                    post_map[key] = post_map[key] + 1

                else:
                    # initialize the post count
                    post_map[key] = 1

        for single_date in rputils.daterange(start, end):
            # we now populate the rows with the corresponding post counts
            # str_date is a day in between start and end with the
            # same format as a key in our punch_map
            str_date = single_date.strftime("%m/%d")

            try:
                post_count = post_map[str_date]
            except KeyError:
                post_count = 0

            # the first item in our row is the date
            # the second item is the corresponding post_count
            row = [{"v": str_date}, {"v": post_count}]
            rows.append({'c': row})

    else:
        # we need to return graph data for unique patrons for
        # all days in between start and end.

        # columns contains the data that any given row needs to have.
        # rows contains multiple dates paired with accumulative patron count
        columns = [{
            "id": "",
            "label": "Date",
            "type": "string"
        }, {
            "id": "",
            "label": 'Patrons',
            "type": "number"
        }]

        for single_date in rputils.daterange(start, end):
            # str_date is a day in between start and end with the
            # same format as a key in our punch_map
            str_date = single_date.strftime("%m/%d")

            # FIXME In order to get the cumulative count for each day,
            # we make a query of the count for each day. Optimization?
            d = single_date.replace(hour=23, minute=59, second=59)
            d_aware = make_aware_to_utc(d, store_timezone)
            patron_count = store.get('patronStores',
                                     count=1,
                                     limit=0,
                                     createdAt__lte=d_aware)

            row = [{"v": str_date}, {"v": patron_count}]
            rows.append({'c': row})

    # return the graph data
    return HttpResponse(json.dumps({
        'cols': columns,
        'rows': rows
    }),
                        content_type="application/json")
Example #34
0
def image_crop(request):
    """
    Takes in crop coordinates and creates a new png image.
    """
    if request.method == "POST":
        data = {}
        store = SESSION.get_store(request.session)
        
        old_cover, old_thumbnail = None, None
        if store.get("cover_image"):
            old_cover = store.get("cover_image")
        if store.get("thumbnail_image"):
            old_thumbnail = store.get("thumbnail_image")
            
        # if there are 2 windows with the same session_key editing the 
        # store image, the image will be deleted by the first window
        # to crop. The 2nd window will then have no image.
        image = UploadedImageFile.objects.filter(session_key=\
            request.session.session_key)
            
        if not image:
            # flag the execution of image Crop Complete js function
            data['success'] = True
            return render(request, 'manage/image_crop.djhtml', data)
            
        image = image[0]
        
        # the crop coords are used for the thumbnail_image
        crop_coords = None
        if len(request.POST["x1"]) > 0:
            crop_coords = {
                "x1": int(request.POST["x1"].split(".")[0]),
                "y1": int(request.POST["y1"].split(".")[0]),
                "x2": int(request.POST["x2"].split(".")[0]),
                "y2": int(request.POST["y2"].split(".")[0]),
            }
        
        # save the session before a cloud call!
        request.session.save()
        
        res_cover = create_png(image.image.path)
        res_thumbnail = create_png(image.image.path,
            IMAGE_THUMBNAIL_SIZE, crop_coords)
        
        # make sure that we have the latest session
        session = SessionStore(request.session.session_key)
        store = SESSION.get_store(session)
        
        if res_cover and 'error' not in res_cover:
            setattr(store, "cover_image", res_cover.get('name'))
            setattr(store, "cover_image_url", res_cover.get('url').replace(\
                "http:/", "https://s3.amazonaws.com"))
        
        if res_thumbnail and 'error' not in res_thumbnail:
            setattr(store, "thumbnail_image", res_thumbnail.get('name'))
            setattr(store, "thumbnail_image_url", res_thumbnail.get('url').replace(\
                "http:/", "https://s3.amazonaws.com"))
                
            # below here for backwards compat
            store.store_avatar = getattr(store, "thumbnail_image")
            store.store_avatar_url = getattr(store, "thumbnail_image_url")
            store.update()
                
        # delete the model and file since it's useless to keep
        image.delete()
        
        # notify other dashboards of this change
        payload = {
            COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
            "updatedStoreThumbnailName": store.thumbnail_image,
            "updatedStoreThumbnailUrl": store.thumbnail_image_url,
            "updatedStoreCoverName": store.cover_image,
            "updatedStoreCoverUrl": store.cover_image_url,
        }
        
        comet_receive(store.objectId, payload)
        
        # need to remove old files
        if old_cover:
            delete_file(old_cover, 'image/png')
            
        if old_thumbnail:
            delete_file(old_thumbnail, 'image/png')
        
        # flag the execution of image Crop Complete js function
        data['success'] = True
    
        # make sure we have latest session data
        request.session.clear()
        request.session.update(SessionStore(request.session.session_key))
        
        return render(request, 'manage/image_crop.djhtml', data)
    
    raise Http404
Example #35
0
def breakdown_graph(request, data_type=None, filter=None, range=None):
    """
    handles requests for the breakdown graph.
    """
    store = SESSION.get_store(request.session)
    store_timezone = SESSION.get_store_timezone(request.session)
    (start, end) = rputils.calculate_daterange(range)
    start = start.replace(hour=0, minute=0, second=0, microsecond=0)
    end = end.replace(hour=23, minute=59, second=59, microsecond=0)
    # need to make aware and then convert to utc for querying
    start_aware = make_aware_to_utc(start, store_timezone)
    end_aware = make_aware_to_utc(end, store_timezone)

    results = []
    if data_type == 'punches':
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"])

            # WARNING! max punches returned is 1000!
            unknown, male, female = 0, 0, 0
            male_punches = relational_query(store.objectId, "Store", "Punches",
                                            "Punch", "Patron", "Patron",
                                            {"gender": "male"}, {
                                                'createdAt__lte': end_aware,
                                                'createdAt__gte': start_aware
                                            })
            female_punches = relational_query(store.objectId, "Store",
                                              "Punches", "Punch", "Patron",
                                              "Patron", {"gender": "female"}, {
                                                  'createdAt__lte': end_aware,
                                                  'createdAt__gte': start_aware
                                              })

            if male_punches:
                male_punches = male_punches['results']
                # aggregate the punches
                for p in male_punches:
                    male += p.get('punches')

            if female_punches:
                female_punches = female_punches['results']
                for p in female_punches:
                    female += p.get('punches')

            rows = [start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    unknown, male, female]
            results.append(rows)

        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"])

            now = datetime.now()
            rows = [
                start.strftime("%m/%d/%Y") + ' - ' + end.strftime("%m/%d/%Y"),
                0, 0, 0, 0, 0
            ]
            age_ranges = [(1, 0, -20), (2, -20, -30), (3, -30, -40),
                          (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, second=59)

                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)

                punches = relational_query(
                    store.objectId, "Store", "Punches", "Punch", "Patron",
                    "Patron", {
                        'date_of_birth__lte': end_dob_aware,
                        'date_of_birth__gte': start_dob_aware
                    }, {
                        'createdAt__lte': end_aware,
                        'createdAt__gte': start_aware
                    })
                punch_count = 0
                if punches:
                    punches = punches['results']
                    for punch in punches:
                        punch_count += punch['punches']
                rows[idx] = punch_count
            results.append(rows)

    elif data_type == 'facebook':
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"])
            results.append([
                start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    0,
                    relational_query(store.objectId, "Store",
                        "FacebookPosts", "FacebookPost",
                        "Patron", "Patron",
                        {"gender": "male"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True),
                    relational_query(store.objectId, "Store",
                        "FacebookPosts", "FacebookPost",
                        "Patron", "Patron",
                        {"gender": "female"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True),
            ])

        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"])

            now = datetime.now()
            rows = [
                start.strftime("%m/%d/%Y") + ' - ' + end.strftime("%m/%d/%Y"),
                0, 0, 0, 0, 0
            ]
            age_ranges = [(1, 0, -20), (2, -20, -30), (3, -30, -40),
                          (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, second=59)

                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)

                rows[idx] = relational_query(
                    store.objectId,
                    "Store",
                    "FacebookPosts",
                    "FacebookPost",
                    "Patron",
                    "Patron", {
                        'date_of_birth__lte': end_dob_aware,
                        'date_of_birth__gte': start_dob_aware
                    }, {
                        'createdAt__lte': end_aware,
                        'createdAt__gte': start_aware
                    },
                    count=True)

            results.append(rows)

    else:  # patrons
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"])
            results.append([
                start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    0,
                    relational_query(store.objectId, "Store",
                        "PatronStores", "PatronStore",
                        "Patron", "Patron",
                        {"gender": "male"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True),
                    relational_query(store.objectId, "Store",
                        "PatronStores", "PatronStore",
                        "Patron", "Patron",
                        {"gender": "female"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True),
            ])

        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"])

            now = datetime.now()
            rows = [
                start.strftime("%m/%d/%Y") + ' - ' + end.strftime("%m/%d/%Y"),
                0, 0, 0, 0, 0
            ]
            age_ranges = [(1, 0, -20), (2, -20, -30), (3, -30, -40),
                          (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, second=59)

                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)

                rows[idx] = relational_query(
                    store.objectId,
                    "Store",
                    "PatronStores",
                    "PatronStore",
                    "Patron",
                    "Patron", {
                        'date_of_birth__lte': end_dob_aware,
                        'date_of_birth__gte': start_dob_aware
                    }, {
                        'createdAt__lte': end_aware,
                        'createdAt__gte': start_aware
                    },
                    count=True)
            results.append(rows)

    return HttpResponse(json.dumps(results), content_type="application/json")
Example #36
0
def image_crop(request):
    """
    Takes in crop coordinates and creates a new png image.
    """
    if request.method == "POST":
        data = {}
        store = SESSION.get_store(request.session)

        old_cover, old_thumbnail = None, None
        if store.get("cover_image"):
            old_cover = store.get("cover_image")
        if store.get("thumbnail_image"):
            old_thumbnail = store.get("thumbnail_image")

        # if there are 2 windows with the same session_key editing the
        # store image, the image will be deleted by the first window
        # to crop. The 2nd window will then have no image.
        image = UploadedImageFile.objects.filter(session_key=\
            request.session.session_key)

        if not image:
            # flag the execution of image Crop Complete js function
            data['success'] = True
            return render(request, 'manage/image_crop.djhtml', data)

        image = image[0]

        # the crop coords are used for the thumbnail_image
        crop_coords = None
        if len(request.POST["x1"]) > 0:
            crop_coords = {
                "x1": int(request.POST["x1"].split(".")[0]),
                "y1": int(request.POST["y1"].split(".")[0]),
                "x2": int(request.POST["x2"].split(".")[0]),
                "y2": int(request.POST["y2"].split(".")[0]),
            }

        # save the session before a cloud call!
        request.session.save()

        res_cover = create_png(image.image.path)
        res_thumbnail = create_png(image.image.path, IMAGE_THUMBNAIL_SIZE,
                                   crop_coords)

        # make sure that we have the latest session
        session = SessionStore(request.session.session_key)
        store = SESSION.get_store(session)

        if res_cover and 'error' not in res_cover:
            setattr(store, "cover_image", res_cover.get('name'))
            setattr(store, "cover_image_url", res_cover.get('url').replace(\
                "http:/", "https://s3.amazonaws.com"))

        if res_thumbnail and 'error' not in res_thumbnail:
            setattr(store, "thumbnail_image", res_thumbnail.get('name'))
            setattr(store, "thumbnail_image_url", res_thumbnail.get('url').replace(\
                "http:/", "https://s3.amazonaws.com"))

            # below here for backwards compat
            store.store_avatar = getattr(store, "thumbnail_image")
            store.store_avatar_url = getattr(store, "thumbnail_image_url")
            store.update()

        # delete the model and file since it's useless to keep
        image.delete()

        # notify other dashboards of this change
        payload = {
            COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
            "updatedStoreThumbnailName": store.thumbnail_image,
            "updatedStoreThumbnailUrl": store.thumbnail_image_url,
            "updatedStoreCoverName": store.cover_image,
            "updatedStoreCoverUrl": store.cover_image_url,
        }

        comet_receive(store.objectId, payload)

        # need to remove old files
        if old_cover:
            delete_file(old_cover, 'image/png')

        if old_thumbnail:
            delete_file(old_thumbnail, 'image/png')

        # flag the execution of image Crop Complete js function
        data['success'] = True

        # make sure we have latest session data
        request.session.clear()
        request.session.update(SessionStore(request.session.session_key))

        return render(request, 'manage/image_crop.djhtml', data)

    raise Http404
Example #37
0
def update_subscription(request):
    """
    This view is also used for explicit upgrades.
    """
    do_upgrade = request.GET.get("do_upgrade") is not None

    if do_upgrade:
        data = {'account_nav': True, 'upgrade': True}
    else:
        data = {'account_nav': True, 'update': True}

    store = SESSION.get_store(request.session)
    subscription = SESSION.get_subscription(request.session)

    if request.method == 'POST':
        form = SubscriptionForm(request.POST)
        form.subscription = subscription  # to validate cc_number
        all_forms_valid = form.is_valid()

        if all_forms_valid:
            # upgrade account if date_passed_user_limit is on
            # should fetch the most up-to-date subscription first
            subscription = Subscription.objects().get(objectId=\
                subscription.objectId)
            upgraded = False
            if subscription.date_passed_user_limit or do_upgrade:
                level = subscription.get("subscriptionType")
                if level == 0:
                    subscription.set("subscriptionType", 1)
                    subscription.date_passed_user_limit = None
                    upgraded = True
                elif level == 1:
                    subscription.date_passed_user_limit = None
                    subscription.set("subscriptionType", 2)
                    upgraded = True

            # subscription.update() called in store_cc
            subscription.update_locally(request.POST.dict(), False)

            d = datetime(int(request.POST['date_cc_expiration_year']),
                         int(request.POST['date_cc_expiration_month']), 1)
            subscription.set(
                "date_cc_expiration",
                make_aware_to_utc(d,
                                  SESSION.get_store_timezone(request.session)))

            def invalid_card():
                # add some asterisk to cc_number
                if form.initial.get("cc_number"):
                    form.initial['cc_number'] = "*" * 12 +\
                        form.initial.get('cc_number')[-4:]
                errs = form._errors.setdefault(\
                    "cc_number", ErrorList())
                errs.append("Invalid credit " +\
                    "card. Please make sure that you provide " +\
                    "correct credit card information and that you " +\
                    "have sufficient funds, then try again.")
                data['form'] = form
                return render(request, 'manage/subscription_update.djhtml',
                              data)

            res = True
            # only store_cc if it is a digit (new)
            if str(form.data['cc_number']).isdigit():
                res = subscription.store_cc(form.data['cc_number'],
                                            form.data['cc_cvv'], False)
            if not res:
                return invalid_card()

            # if monthly billing failed
            if subscription.date_charge_failed:
                sub_cost = sub_type[subscription.get(\
                            "subscriptionType")]["monthly_cost"]
                invoice = subscription.charge_cc(\
                        sub_cost, EMAIL_MONTHLY_SUBJECT, MONTHLY)
                if invoice:
                    subscription.date_last_billed =\
                        subscription.date_last_billed +\
                        relativedelta(days=30)
                    subscription.date_charge_failed = None
                    subscription.update()
                    send_email_receipt_monthly_success(\
                        request.session['account'],
                        store, subscription, invoice)
                else:
                    return invalid_card()
            ###########

            if upgraded:
                max_users = sub_type[\
                        subscription.subscriptionType]["max_users"]
                if max_users == UNLIMITED:
                    max_users = "Unlimited"
                package = {
                    "sub_type": sub_type[\
                        subscription.subscriptionType-1]["name"],
                    "new_sub_type": sub_type[\
                        subscription.subscriptionType]["name"],
                    "new_sub_type_cost": sub_type[\
                        subscription.subscriptionType]["monthly_cost"],
                    "new_max_patronStore_count": max_users,
                }
                send_email_account_upgrade(request.session['account'], store,
                                           package)

            # Important that this is last since invalid_card may be
            # returned!
            subscription.update()

            # update the session cache
            request.session['store'] = store
            request.session['subscription'] = subscription

            # notify other dashboards of these changes
            payload = {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedSubscription": subscription.jsonify()
            }
            comet_receive(store.objectId, payload)

            # if coming from the message edit limit reached
            if do_upgrade:
                if request.session.get('from_limit_reached') and\
                    request.session.get('message_b4_upgrade'):
                    # redirect back to message_edit view to process
                    return redirect(reverse('message_edit',
                            args=(0,)) + "?%s" %\
                            urllib.urlencode({'send_message': '1'}))

            if do_upgrade:
                return redirect(reverse('store_index')+ "?%s" %\
                        urllib.urlencode({'success':\
                            'Your subscription has been upgraded.'}))
            else:
                return redirect(reverse('store_index')+ "?%s" %\
                            urllib.urlencode({'success':\
                                'Your subscription has been updated.'}))
    else:
        form = SubscriptionForm()
        form.initial = subscription.__dict__.copy()
        # add some asterisk to cc_number
        if form.initial.get("cc_number"):
            form.initial['cc_number'] = "*" * 12 +\
                form.initial.get('cc_number')[-4:]

        if do_upgrade:
            from_limit_reached =\
                request.session.get("from_limit_reached")
            if from_limit_reached:
                data['from_limit_reached'] = from_limit_reached

    # update the session cache
    request.session['store'] = store
    request.session['subscription'] = subscription

    data['form'] = form
    return render(request, 'manage/subscription_update.djhtml', data)
Example #38
0
def edit_location(request, store_location_id):
    """
    Renders the edit location template or handle form submissions
    for location creation or update.
    """
    data = {'account_nav': True, 'store_location_id': store_location_id}
    store = SESSION.get_store(request.session)

    # we are editing a new location if store_location_id is 0
    new_location = store_location_id == '0'

    def common(store_location_form):
        """
        Returns a rendered store location edit template with the given
        store location form.
        """
        data['store_location_form'] = store_location_form
        return render(request, 'manage/store_location_edit.djhtml', data)

    # Handle form submission and return the appropriate json response
    if request.method == 'POST':
        store_location_form = StoreLocationForm(request.POST)

        postDict = request.POST.dict()
        hours = HoursInterpreter(json.loads(postDict["hours"]))

        # we are either creating a new store location or updating an
        # existing one with new values in the postDict
        if new_location:
            store_location = StoreLocation(**postDict)
        else:
            store_location = SESSION.get_store_location(\
                request.session, store_location_id)
            store_location.update_locally(postDict, False)

        if store_location_form.is_valid():
            # validate and format the hours
            hours_validation = hours.is_valid()
            if type(hours_validation) is bool:
                store_location.set("hours", hours.from_javascript_to_parse())
            else:
                data['hours_data'] = hours._format_javascript_input()
                data['hours_error'] = hours_validation
                return HttpResponse(json.dumps({
                    "result":
                    "error",
                    "html":
                    common(store_location_form).content,
                }),
                                    content_type="application/json")

            # set the timezone
            if store_location.get('zip'):
                store_location.store_timezone =\
                    get_timezone(store_location.get('zip')).zone

            # format the phone number
            store_location.phone_number =\
                format_phone_number(postDict['phone_number'])
            # update the store's coordinates and neighborhood
            full_address = " ".join(\
                store_location.get_full_address().split(", "))
            map_data = 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")))

            if new_location:
                store_location.Store = store.objectId
                store_location.create()
                store.array_add_unique("store_locations", [store_location])

            else:
                store_location.update()
                # if this location is the first location then update
                # the corresponding store columns for backwards compat
                sl_list = SESSION.get_store_locations_list(request.session)
                if sl_list[0].objectId == store_location.objectId:
                    store.inherit_store_location(store_location)
                    store.update()

            payload = {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedStore": store.jsonify(),
                "updatedStoreLocation": store_location.jsonify(),
            }
            comet_receive(store.objectId, payload)

            # make sure that we have the latest session
            request.session.clear()
            request.session.update(SessionStore(request.session.session_key))

            if new_location:
                success_msg = 'New store location has been added.'
            else:
                success_msg = 'Store location has been updated.'

            # set the active location to this one
            SESSION.set_active_store_location_id(request.session,
                                                 store_location.objectId)

            return HttpResponse(json.dumps({
                "result": "success",
                "url": reverse('store_index')+ "?%s" %\
                    urllib.urlencode({'success': success_msg})
            }), content_type="application/json")

        else:
            data['store_location'] = store_location
            data['hours_data'] = hours._format_javascript_input()

            return HttpResponse(json.dumps({
                "result":
                "error",
                "html":
                common(store_location_form).content,
            }),
                                content_type="application/json")

    # user navigated to this page so just render a store location edit
    # template with a blank form (if new_location) or a form with fields
    # filled out if user is editing an existing location
    else:
        store_location_form = StoreLocationForm(None)

        # user is editing an existing location so fill up initial
        # form content
        if not new_location:
            store_location = SESSION.get_store_location(\
                request.session, store_location_id)
            store_location_form.initial = store_location.__dict__.copy()
            # make sure that the phone number is unformatted
            store_location_form.initial['phone_number'] =\
                store_location_form.initial['phone_number'].replace("(",
                    "").replace(")","").replace(" ", "").replace("-","")

            data['store_location'] = store_location
            data['hours_data'] = HoursInterpreter(\
                store_location.hours)._format_parse_input()

    return common(store_location_form)
Example #39
0
def edit_location(request, store_location_id):
    """
    Renders the edit location template or handle form submissions
    for location creation or update.
    """
    data = {'account_nav': True, 'store_location_id': store_location_id}
    store = SESSION.get_store(request.session)
    
    # we are editing a new location if store_location_id is 0
    new_location = store_location_id == '0'
        
    def common(store_location_form):
        """
        Returns a rendered store location edit template with the given
        store location form.
        """
        data['store_location_form'] = store_location_form
        return render(request, 'manage/store_location_edit.djhtml', data)
            
    # Handle form submission and return the appropriate json response
    if request.method == 'POST': 
        store_location_form = StoreLocationForm(request.POST)
        
        postDict = request.POST.dict()
        hours = HoursInterpreter(json.loads(postDict["hours"]))
        
        # we are either creating a new store location or updating an
        # existing one with new values in the postDict
        if new_location:
            store_location = StoreLocation(**postDict)
        else:
            store_location = SESSION.get_store_location(\
                request.session, store_location_id)
            store_location.update_locally(postDict, False)
            
        if store_location_form.is_valid(): 
            # validate and format the hours
            hours_validation = hours.is_valid()
            if type(hours_validation) is bool:
                store_location.set("hours", hours.from_javascript_to_parse())
            else:
                data['hours_data'] = hours._format_javascript_input()
                data['hours_error'] = hours_validation
                return HttpResponse(json.dumps({
                    "result": "error",
                    "html": common(store_location_form).content,
                }), content_type="application/json")
            
            # set the timezone
            if store_location.get('zip'):
                store_location.store_timezone =\
                    get_timezone(store_location.get('zip')).zone
                    
            # format the phone number
            store_location.phone_number =\
                format_phone_number(postDict['phone_number'])
            # update the store's coordinates and neighborhood
            full_address = " ".join(\
                store_location.get_full_address().split(", "))
            map_data = 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")))
           
            if new_location:
                store_location.Store = store.objectId  
                store_location.create()
                store.array_add_unique("store_locations", [store_location])

            else:  
                store_location.update()
                # if this location is the first location then update 
                # the corresponding store columns for backwards compat
                sl_list = SESSION.get_store_locations_list(request.session)
                if sl_list[0].objectId == store_location.objectId:
                    store.inherit_store_location(store_location)
                    store.update()
            
            payload = {
                COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                "updatedStore": store.jsonify(),
                "updatedStoreLocation": store_location.jsonify(),
            }
            comet_receive(store.objectId, payload)
            
            # make sure that we have the latest session
            request.session.clear()
            request.session.update(SessionStore(request.session.session_key))
            
            if new_location:
                success_msg = 'New store location has been added.'
            else:
                success_msg = 'Store location has been updated.'
                
            # set the active location to this one
            SESSION.set_active_store_location_id(request.session,
                store_location.objectId)
            
            return HttpResponse(json.dumps({
                "result": "success",
                "url": reverse('store_index')+ "?%s" %\
                    urllib.urlencode({'success': success_msg})
            }), content_type="application/json")
            
            
        else:
            data['store_location'] = store_location
            data['hours_data'] = hours._format_javascript_input()
            
            return HttpResponse(json.dumps({
                "result": "error",
                "html": common(store_location_form).content,
            }), content_type="application/json")
       
    # user navigated to this page so just render a store location edit
    # template with a blank form (if new_location) or a form with fields
    # filled out if user is editing an existing location    
    else:
        store_location_form = StoreLocationForm(None)
        
        # user is editing an existing location so fill up initial
        # form content
        if not new_location:
            store_location = SESSION.get_store_location(\
                request.session, store_location_id)
            store_location_form.initial = store_location.__dict__.copy()
            # make sure that the phone number is unformatted
            store_location_form.initial['phone_number'] =\
                store_location_form.initial['phone_number'].replace("(",
                    "").replace(")","").replace(" ", "").replace("-","")
                    
            data['store_location'] = store_location
            data['hours_data'] = HoursInterpreter(\
                store_location.hours)._format_parse_input()
         
    return common(store_location_form)
Example #40
0
def pull(request):
    """
    This is where the comet approach is put into play.
    This handles ajax requests from clients, holding on to the 
    request while checking Parse for new activity.
    
    IMPORTANT! The order in which the session cache is checked is very
    critical. Take for example and employee that registers.
    Dashboard A receives the pending employee and immediately 
    approves it. Now Dashboard B will run pull with the pending
    employee and the approved employee. We must first add the pending 
    then check for the approved!
    """
    def comet(session_copy):
        # used by more than 1 (note that it is ok to retrieve all of
        # the lists since they are all pointers - not the actual list!
        employees_pending_list_copy =\
            SESSION.get_employees_pending_list(session_copy)
        employees_approved_list_copy =\
            SESSION.get_employees_approved_list(session_copy)
        messages_received_list_copy =\
            SESSION.get_messages_received_list(session_copy)
        redemptions_pending_copy =\
            SESSION.get_redemptions_pending(session_copy)
        redemptions_past_copy =\
            SESSION.get_redemptions_past(session_copy)

        # this is the latest session data
        session = SessionStore(request.session.session_key)
        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)

        # put the diffs between session_copy and session here
        data = {}

        #############################################################
        # FEEDBACKS_UNREAD ##################################
        fbs_unread_copy = [ fb.objectId for fb in\
            messages_received_list_copy if not fb.is_read ]
        fbs_unread = [ fb.objectId for fb in\
            messages_received_list if not fb.is_read ]

        # get the difference between the two
        feedbacks_unread =\
            tuple(set(fbs_unread) - set(fbs_unread_copy))
        if feedbacks_unread:
            fb_unread = []
            messages_received_ids =\
                [ fb.objectId for fb in messages_received_list ]
            for feedback_id in feedbacks_unread:
                for fb in messages_received_list:
                    if fb.objectId == feedback_id:
                        fb_unread.append(fb.jsonify())
                        break

            if len(fb_unread) > 0:
                fb_count = 0
                for fb in messages_received_list:
                    if not fb.get("is_read"):
                        fb_count += 1
                data['feedbacks_unread'] = fb_unread
                data['feedback_unread_count'] = fb_count

        #############################################################
        # EMPLOYEES_PENDING ##################################
        # must also check if employee is already approved!
        emps_pending_copy = [
            emp.objectId for emp in employees_pending_list_copy
        ]
        emps_pending = [emp.objectId for emp in employees_pending_list]

        employees_pending =\
            tuple(set(emps_pending) - set(emps_pending_copy))

        if employees_pending:
            pending = []
            for emp_id in employees_pending:
                for emp in employees_pending_list:
                    if emp.objectId == emp_id:
                        pending.append(emp.jsonify())
                        break

            if len(pending) > 0:
                data['employees_pending_count'] =\
                    len(employees_pending_list)
                data['employees_pending'] = pending

        #############################################################
        # EMPLOYEES APPROVED (pending to approved) #################
        emps_approved_copy = [ emp.objectId for emp in\
            employees_approved_list_copy]
        emps_approved = [ emp.objectId for emp in\
            employees_approved_list]

        appr_emps =\
            tuple(set(emps_approved) - set(emps_approved_copy))

        if appr_emps:
            approved = []
            for appr_emp_id in appr_emps:
                for emp in employees_approved_list:
                    if emp.objectId == appr_emp_id:
                        approved.append(emp.jsonify())
                        break

            if len(approved) > 0:
                data['employees_approved'] = approved
                data['employees_pending_count'] =\
                    len(employees_pending_list)

        #############################################################
        # EMPLOYEES DELETED/DENIED/REJECTED (pending/approved to pop)!
        # need to compare approved and pending!
        emps_copy = emps_approved_copy[:]
        emps_copy.extend(emps_pending_copy)
        emps = emps_approved[:]
        emps.extend(emps_pending)

        # emps_copy has the same or more items that emps
        del_emps = tuple(set(emps_copy) - set(emps))

        if del_emps:
            deleted = []
            for demp_id in del_emps:
                if demp_id in emps_approved_copy:
                    emps_list = employees_approved_list_copy
                else:
                    emps_list = employees_pending_list_copy

                for emp in emps_list:
                    if emp.objectId == demp_id:
                        deleted.append(emp.jsonify())
                        break

            if len(deleted) > 0:
                data['employees_pending_count'] =\
                    len(employees_pending_list)
                data['employees_deleted'] = deleted

        #############################################################
        # REDEMPTIONS PENDING
        reds_pending_copy = [ r.objectId for r in\
            redemptions_pending_copy ]
        reds_pending = [r.objectId for r in redemptions_pending]

        reds = tuple(set(reds_pending) - set(reds_pending_copy))

        if reds:
            redemps = []
            for r_id in reds:
                for redemp in redemptions_pending:
                    if redemp.objectId == r_id:
                        redemps.append(redemp.jsonify())
                        break

            if len(redemps) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_pending'] = redemps

        #############################################################
        # REDEMPTIONS APPROVED (pending to history)
        reds_past_copy = [ r.objectId for r in\
            redemptions_past_copy ]
        reds_past = [r.objectId for r in redemptions_past]

        appr_redemps =\
            tuple(set(reds_past) - set(reds_past_copy))

        if appr_redemps:
            redemp_js = []
            for red_id in appr_redemps:
                for redemp in redemptions_past:
                    if redemp.objectId == red_id:
                        redemp_js.append(redemp.jsonify())
                        break

            if len(redemp_js) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_approved'] = redemp_js

        #############################################################
        # REDEMPTIONS DELETED ##############################
        # remove from pending (should not be in history!)
        reds_copy = reds_past_copy[:]
        reds_copy.extend(reds_pending_copy)
        reds = reds_past[:]
        reds.extend(reds_pending)

        # reds_copy has the same or more items that reds
        del_redemps = tuple(set(reds_copy) - set(reds))
        if del_redemps:
            redemp_js = []
            for red_id in del_redemps:
                reds_list = []
                if red_id in reds_past_copy:
                    reds_list = redemptions_past_copy
                elif red_id in reds_pending_copy:
                    reds_list = redemptions_pending_copy

                for redemp in reds_list:
                    if redemp.objectId == red_id:
                        redemp_js.append(redemp.jsonify())
                        break
            if len(redemp_js) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_deleted'] = redemp_js

        #############################################################
        # SETTINGS UPDATED ##############################
        settings_copy = session_copy.get("settings")
        settings = session.get("settings")
        if settings_copy.get("retailer_pin") !=\
            settings.get("retailer_pin"):
            data['retailer_pin'] = settings.get("retailer_pin")

        #############################################################
        # REWARDS UPDATED ##############################
        rewards_copy = session_copy.get("store").get("rewards")
        rewards_copy =\
            { reward['reward_id']:reward for reward in rewards_copy }

        rewards = session.get("store").get("rewards")
        rewards = {reward['reward_id']: reward for reward in rewards}
        updated_rewards = []

        for reward_id, rew_copy in rewards_copy.iteritems():
            # Note that some rewards may have been deleted!
            rew = rewards.get(reward_id)
            if rew and rew_copy['redemption_count'] !=\
                rew['redemption_count']:
                # only the redemtpion_count and reward_id are used
                # in the client side
                updated_rewards.append({
                    "reward_id":
                    reward_id,
                    "redemption_count":
                    rew['redemption_count'],
                })

        if updated_rewards:
            data['rewards'] = updated_rewards

        #############################################################
        # PATRONSTORE_COUNT ##################################
        patronStore_count_copy = int(session_copy["patronStore_count"])
        patronStore_count = int(session["patronStore_count"])
        if patronStore_count_copy != patronStore_count:
            data['patronStore_count'] = patronStore_count

        #############################################################
        # ACTIVE_STORE_LOCATION_ID ############################
        if session['active_store_location_id'] !=\
            session_copy['active_store_location_id']:
            data['active_store_location_id'] =\
                session['active_store_location_id']

        # IMPORTANT! The request.session is the same as the
        # SessionStore(session_key)! so we must use the
        # request.session because it is automatically saved at the end
        # of each request- thereby overriding/undoing any changes made
        # to the SessionStore(session_key) key!
        # need to check if we are still logged in
        session = SessionStore(request.session.session_key)
        if 'account' in session and SESSION_KEY in session:
            request.session.clear()
            request.session.update(session)
        else:
            flush(request.session)

        ############################################################
        # Respond ###########################################
        try:
            return HttpResponse(json.dumps(data),
                                content_type="application/json")
        except (IOError, socket.error) as e:  # broken pipe/socket.
            thread.exit()  # exit silently

    ##################################################################
    ##### ENTRY POINT
    ######################################################
    # get the timestamp and uid
    t = parser.parse(request.GET["timestamp"])
    timestamp = str(t.hour).zfill(2) + ":" +\
        str(t.minute).zfill(2) + ":" + str(t.second).zfill(2)
    uid = request.GET['uid']

    # update the last_updated field of the CometSessionIndex
    try:
        csi = CometSessionIndex.objects.get(session_key=\
            request.session.session_key)
        csi.last_updated = timezone.now()
        csi.save()
    except CometSessionIndex.DoesNotExist:
        # should never go here but just in case.
        CometSessionIndex.objects.create(session_key=\
            request.session.session_key,
            store_id=SESSION.get_store(request.session).objectId,
            last_updated=timezone.now())

    # register the CometSession
    CometSession.objects.update()
    CometSession.objects.create(session_key=\
        request.session.session_key, timestamp=timestamp, uid=uid)

    # cache the current session at this state
    session_copy = dict(request.session)
    timeout_time = timezone.now() + relativedelta(seconds=REQUEST_TIMEOUT)

    # keep going until its time to return a response forcibly
    while timezone.now() < timeout_time:
        # need to update he objects manager to get the latest objects
        CometSession.objects.update()
        try:
            scomet = CometSession.objects.get(session_key=\
                request.session.session_key,
                timestamp=timestamp, uid=uid)
        except CometSession.DoesNotExist:
            # cometsession was deleted - time to go
            try:
                # make sure that the latest session is saved!
                # need to check if we are still logged in
                session = SessionStore(request.session.session_key)
                if 'account' in session and SESSION_KEY in session:
                    request.session.clear()
                    request.session.update(session)
                else:
                    flush(request.session)
                return HttpResponse(json.dumps({"result": -1}),
                                    content_type="application/json")
            except (IOError, socket.error) as e:
                thread.exit()

        if scomet.modified:
            # delete the registered comet session object
            CometSession.objects.update()
            try:
                scomet = CometSession.objects.get(session_key=\
                    request.session.session_key,
                    timestamp=timestamp, uid=uid)
                scomet.delete()
            except CometSession.DoesNotExist:
                pass  # do nothing
            try:
                return comet(session_copy)
            except KeyError:
                # if a key error occurs then that probably means that
                # the session has been flushed- was logged out by user
                # or forcefully by server =)
                # now time to flag existing tabs.
                request.session.clear()
                try:
                    return HttpResponse(json.dumps({"result": -3}),
                                        content_type="application/json")
                except (IOError, socket.error) as e:  # broken pipe/socket.
                    thread.exit()  # exit silently
        else:  # nothing new, sleep for a bit
            sleep(COMET_PULL_RATE)

    # TIME IS UP - return a response result 0 means no change
    # try 1 last time
    if scomet.modified:
        # delete the registered comet session object
        CometSession.objects.update()
        try:
            scomet = CometSession.objects.get(session_key=\
                request.session.session_key,
                timestamp=timestamp, uid=uid)
            scomet.delete()
        except CometSession.DoesNotExist:
            pass  # do nothing
        return comet(session_copy)

    # make sure that request.session is the most up to date
    session = SessionStore(request.session.session_key)
    # need to check if we are still logged in
    if 'account' in session and SESSION_KEY in session:
        request.session.clear()
        request.session.update(session)
    else:
        flush(request.session)

    # attempt to delete registered comet session if not yet deleted
    try:
        scomet = CometSession.objects.get(session_key=\
            request.session.session_key,
            timestamp=timestamp, uid=uid)
        scomet.delete()
    except CometSession.DoesNotExist:
        pass  # do nothing

    try:
        return HttpResponse(json.dumps({"result": 0}),
                            content_type="application/json")
    except (IOError, socket.error) as e:
        thread.exit()  # exit silently
Example #41
0
def breakdown_graph(request, data_type=None, filter=None, range=None):
    """
    handles requests for the breakdown graph.
    """
    store = SESSION.get_store(request.session)
    store_timezone = SESSION.get_store_timezone(request.session)
    (start, end) = rputils.calculate_daterange(range)
    start = start.replace(hour=0, minute=0, second=0, microsecond=0)
    end = end.replace(hour=23, minute=59, second=59, microsecond=0)
    # need to make aware and then convert to utc for querying
    start_aware = make_aware_to_utc(start, store_timezone)
    end_aware = make_aware_to_utc(end, store_timezone)
    
    results = [] 
    if data_type == 'punches':
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"]);
            
            # WARNING! max punches returned is 1000!
            unknown, male, female = 0, 0, 0 
            male_punches = relational_query(store.objectId, "Store",
                "Punches", "Punch", "Patron", "Patron", 
                {"gender": "male"}, {'createdAt__lte':end_aware,
                    'createdAt__gte':start_aware})
            female_punches = relational_query(store.objectId, "Store",
                "Punches", "Punch", "Patron", "Patron", 
                {"gender": "female"}, {'createdAt__lte':end_aware,
                    'createdAt__gte':start_aware})
                    
            if male_punches:
                male_punches = male_punches['results']
                # aggregate the punches
                for p in male_punches:
                    male += p.get('punches')
            
            if female_punches:
                female_punches = female_punches['results']
                for p in female_punches:
                    female += p.get('punches')

            rows = [start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    unknown, male, female]
            results.append(rows)
        
        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"]);
           
            now = datetime.now()
            rows = [start.strftime("%m/%d/%Y")+' - '+end.strftime("%m/%d/%Y"), 0, 0, 0, 0, 0]
            age_ranges = [(1, 0, -20), (2, -20,-30), (3, -30, -40), (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, 
                                            second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, 
                                        second=59)
                
                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)
                
                punches = relational_query(store.objectId, "Store",
                    "Punches", "Punch", "Patron", "Patron", 
                    {'date_of_birth__lte':end_dob_aware,
                     'date_of_birth__gte':start_dob_aware},
                    {'createdAt__lte':end_aware, 
                     'createdAt__gte':start_aware})
                punch_count = 0
                if punches: 
                    punches = punches['results']
                    for punch in punches:
                        punch_count += punch['punches']
                rows[idx] = punch_count
            results.append(rows)
            
    elif data_type == 'facebook':
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"]);
            results.append([
                start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    0, 
                    relational_query(store.objectId, "Store",
                        "FacebookPosts", "FacebookPost", 
                        "Patron", "Patron", 
                        {"gender": "male"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True), 
                    relational_query(store.objectId, "Store",
                        "FacebookPosts", "FacebookPost", 
                        "Patron", "Patron", 
                        {"gender": "female"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True), 
            ])
        
        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"]);
           
            now = datetime.now()
            rows = [start.strftime("%m/%d/%Y")+' - '+end.strftime("%m/%d/%Y"), 0, 0, 0, 0, 0]
            age_ranges = [(1, 0, -20), (2, -20,-30), (3, -30, -40), (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, 
                                            second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, 
                                        second=59)
                                        
                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)
                
                rows[idx] = relational_query(store.objectId, "Store",
                    "FacebookPosts", "FacebookPost", 
                    "Patron", "Patron", 
                    {'date_of_birth__lte':end_dob_aware,
                     'date_of_birth__gte':start_dob_aware},
                    {'createdAt__lte':end_aware, 
                     'createdAt__gte':start_aware}, count=True)
                    
            results.append(rows)
            
    else: # patrons
        if filter == 'gender':
            results.append(["Range", "Unknown", "Male", "Female"]);
            results.append([
                start.strftime("%m/%d/%Y")+\
                    ' - '+end.strftime("%m/%d/%Y"),
                    0, 
                    relational_query(store.objectId, "Store",
                        "PatronStores", "PatronStore", 
                        "Patron", "Patron", 
                        {"gender": "male"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True), 
                    relational_query(store.objectId, "Store",
                        "PatronStores", "PatronStore", 
                        "Patron", "Patron", 
                        {"gender": "female"}, {'createdAt__lte':end_aware,
                        'createdAt__gte':start_aware}, count=True), 
            ])
            
        elif filter == 'age':
            results.append(["Range", "<20", "20-29", "30-39", "40-49", ">50"]);
            
            now = datetime.now()
            rows = [start.strftime("%m/%d/%Y")+' - '+end.strftime("%m/%d/%Y"), 0, 0, 0, 0, 0]
            age_ranges = [(1, 0, -20), (2, -20,-30), (3, -30, -40), (4, -40, -50), (5, -50, -200)]
            for (idx, start_age, end_age) in age_ranges:
                start_dob = now + relativedelta(years=end_age)
                start_dob = start_dob.replace(hour=0, minute=0, 
                                            second=0)
                end_dob = now + relativedelta(years=start_age)
                end_dob = end_dob + relativedelta(days=-1)
                end_dob = end_dob.replace(hour=23, minute=59, 
                                        second=59)
                                        
                # need to make aware and then convert to utc for querying
                start_dob_aware = make_aware_to_utc(start_dob, store_timezone)
                end_dob_aware = make_aware_to_utc(end_dob, store_timezone)
                
                rows[idx] = relational_query(store.objectId, "Store",
                    "PatronStores", "PatronStore", 
                    "Patron", "Patron", 
                    {'date_of_birth__lte':end_dob_aware,
                     'date_of_birth__gte':start_dob_aware},
                    {'createdAt__lte':end_aware, 
                     'createdAt__gte':start_aware}, count=True)
            results.append(rows)
        
    return HttpResponse(json.dumps(results), content_type="application/json")
Example #42
0
def redeem(request):
    """ returns json object. result is 0 if fail, 1 if success,
    2 if insufficient punches, 3 if already validated, 
    4 if successfully deleted/denied, 5 has been deleted elsewhere and
    action is deny, 6 PatronStore has been removed,
    7 deleted elsewhere and action is approve.
    """
    if request.method == "GET":
        # approve or deny
        action = request.GET.get("action")
        redeemId = request.GET.get('redeemRewardId')
        # may come in as "None" or "null" or "undefined"
        rewardId = request.GET.get('rewardId')
        if str(rewardId).isdigit():
            rewardId = int(rewardId)
        else:
            rewardId = None

        store = SESSION.get_store(request.session)
        if action == "approve":
            res = cloud_call(
                "validate_redeem", {
                    "redeem_id": redeemId,
                    "store_id": store.get("objectId"),
                    "reward_id": rewardId,
                })
        elif action == "deny":
            res = cloud_call("reject_redeem", {
                "redeem_id": redeemId,
                "store_id": store.get("objectId"),
            })

        # retrieve latest session since user may click a bunch
        # of redemptions consecutively
        session = SessionStore(request.session.session_key)

        data = {"result": 0}

        # success result removed means patronstore is null!
        if 'error' not in res:
            redemptions_pending =\
                    SESSION.get_redemptions_pending(session)
            i_remove = -1
            if action == "approve":
                result = res.get("result").get("code")
                result_red =\
                    RedeemReward(**res.get("result").get("result"))
            else:
                result = res.get("result")

            # remove from redemptions_pending
            for i, red in enumerate(redemptions_pending):
                if red.objectId == redeemId:
                    i_remove = i
                    break

            # IMPORTANT! Since comet receive  immediately commits
            # changes to a session, i_remove will probably be -1

            if action == "approve":
                redemptions_past =\
                    SESSION.get_redemptions_past(session)

                if result and result in ("insufficient", "PATRONSTORE_REMOVED"
                                         ) and i_remove != -1:
                    redemptions_pending.pop(i_remove)

                elif i_remove != -1:  # success
                    redemption = redemptions_pending.pop(i_remove)
                    redemption.is_redeemed = True
                    redemption.updatedAt = result_red.updatedAt
                    redemptions_past.append(redemption)
                    session['redemptions_past'] =\
                        redemptions_past

                # session changed only if i_remove was not 1
                if i_remove != -1:
                    session['redemptions_pending'] =\
                        redemptions_pending

                if result and result == "insufficient":
                    data["result"] = 2
                elif result and result == "validated":
                    data["result"] = 3
                elif result and result == "PATRONSTORE_REMOVED":
                    data["result"] = 6
                else:
                    data["result"] = 1

                # request.session will be saved after return
                request.session.clear()
                request.session.update(session)
                return HttpResponse(json.dumps(data),
                                    content_type="application/json")

            elif action == "deny":
                if i_remove != -1:
                    del_red = redemptions_pending.pop(i_remove)
                    session['redemptions_pending'] =\
                        redemptions_pending

                data["result"] = 4

                request.session.clear()
                request.session.update(session)
                return HttpResponse(json.dumps(data),
                                    content_type="application/json")

        elif 'error' in res:
            if res['error'] == "REDEEMREWARD_NOT_FOUND":
                if action == "approve":
                    data["result"] = 7
                elif action == "deny":
                    data["result"] = 5
            elif res['error'] == "REDEEMREWARD_VALIDATED":
                data["result"] = 3
            elif res['error'] == "PATRONSTORE_REMOVED":
                data["result"] = 6

    # always make sure to get the latest session since the session
    # will be saved on return!!!
    request.session.clear()
    request.session.update(SessionStore(request.session.session_key))
    return HttpResponse(json.dumps(data), content_type="application/json")
Example #43
0
def redeem(request):
    """ returns json object. result is 0 if fail, 1 if success,
    2 if insufficient punches, 3 if already validated, 
    4 if successfully deleted/denied, 5 has been deleted elsewhere and
    action is deny, 6 PatronStore has been removed,
    7 deleted elsewhere and action is approve.
    """
    if request.method == "GET":        
        # approve or deny
        action = request.GET.get("action")
        redeemId = request.GET.get('redeemRewardId')
        # may come in as "None" or "null" or "undefined"
        rewardId = request.GET.get('rewardId') 
        if str(rewardId).isdigit():
            rewardId = int(rewardId)
        else:
            rewardId = None
            
        store = SESSION.get_store(request.session)
        if action == "approve":
            res = cloud_call("validate_redeem", {
                    "redeem_id":redeemId,
                    "store_id":store.get("objectId"),
                    "reward_id":rewardId,
                    })
        elif action == "deny":
            res = cloud_call("reject_redeem", {
                    "redeem_id":redeemId,
                    "store_id":store.get("objectId"),
                    })
                    
        # retrieve latest session since user may click a bunch 
        # of redemptions consecutively
        session = SessionStore(request.session.session_key)
            
        data = {"result" : 0}
            
        # success result removed means patronstore is null!
        if 'error' not in res:
            redemptions_pending =\
                    SESSION.get_redemptions_pending(session)
            i_remove = -1
            if action == "approve":
                result = res.get("result").get("code")
                result_red =\
                    RedeemReward(**res.get("result").get("result"))
            else:
                result = res.get("result")
                
            # remove from redemptions_pending
            for i, red in enumerate(redemptions_pending):
                if red.objectId == redeemId:
                    i_remove = i 
                    break
           
            # IMPORTANT! Since comet receive  immediately commits
            # changes to a session, i_remove will probably be -1
            
            if action == "approve":
                redemptions_past =\
                    SESSION.get_redemptions_past(session)
                    
                if result and result in ("insufficient",
                    "PATRONSTORE_REMOVED") and i_remove != -1:
                    redemptions_pending.pop(i_remove)
                    
                elif i_remove != -1: # success
                    redemption = redemptions_pending.pop(i_remove)
                    redemption.is_redeemed = True
                    redemption.updatedAt = result_red.updatedAt 
                    redemptions_past.append(redemption)
                    session['redemptions_past'] =\
                        redemptions_past
                      
                # session changed only if i_remove was not 1
                if i_remove != -1: 
                    session['redemptions_pending'] =\
                        redemptions_pending
                
                if result and result == "insufficient":
                    data["result"] = 2
                elif result and result == "validated":
                    data["result"] = 3
                elif result and result == "PATRONSTORE_REMOVED":
                    data["result"] = 6
                else:
                    data["result"] = 1
                    
                # request.session will be saved after return
                request.session.clear()
                request.session.update(session)
                return HttpResponse(json.dumps(data), 
                            content_type="application/json")
                                
            elif action == "deny":
                if i_remove != -1:
                    del_red = redemptions_pending.pop(i_remove)
                    session['redemptions_pending'] =\
                        redemptions_pending
                        
                data["result"] = 4
               
                request.session.clear()
                request.session.update(session)
                return HttpResponse(json.dumps(data), 
                                content_type="application/json")
                                
        elif 'error' in res:
            if res['error'] == "REDEEMREWARD_NOT_FOUND":
                if action == "approve":
                    data["result"] = 7
                elif action == "deny":
                    data["result"] = 5
            elif res['error'] == "REDEEMREWARD_VALIDATED":
                data["result"] = 3
            elif res['error'] == "PATRONSTORE_REMOVED":
                data["result"] = 6
                        
    # always make sure to get the latest session since the session 
    # will be saved on return!!!       
    request.session.clear()             
    request.session.update(SessionStore(request.session.session_key))
    return HttpResponse(json.dumps(data), 
                    content_type="application/json")
Example #44
0
def account_is_owner(session):
    return SESSION.get_store(session).is_owner(session['account'])
Example #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)    
Example #46
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)
Example #47
0
def account_is_owner(session):
    return SESSION.get_store(session).is_owner(session['account'])
Example #48
0
def pull(request):
    """
    This is where the comet approach is put into play.
    This handles ajax requests from clients, holding on to the 
    request while checking Parse for new activity.
    
    IMPORTANT! The order in which the session cache is checked is very
    critical. Take for example and employee that registers.
    Dashboard A receives the pending employee and immediately 
    approves it. Now Dashboard B will run pull with the pending
    employee and the approved employee. We must first add the pending 
    then check for the approved!
    """
    def comet(session_copy):
        # used by more than 1 (note that it is ok to retrieve all of 
        # the lists since they are all pointers - not the actual list!
        employees_pending_list_copy =\
            SESSION.get_employees_pending_list(session_copy)
        employees_approved_list_copy =\
            SESSION.get_employees_approved_list(session_copy)
        messages_received_list_copy =\
            SESSION.get_messages_received_list(session_copy)
        redemptions_pending_copy =\
            SESSION.get_redemptions_pending(session_copy)
        redemptions_past_copy =\
            SESSION.get_redemptions_past(session_copy)
        
        # this is the latest session data
        session = SessionStore(request.session.session_key)
        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)
        
        # put the diffs between session_copy and session here
        data = {}
        
        #############################################################
        # FEEDBACKS_UNREAD ##################################
        fbs_unread_copy = [ fb.objectId for fb in\
            messages_received_list_copy if not fb.is_read ]
        fbs_unread = [ fb.objectId for fb in\
            messages_received_list if not fb.is_read ]
            
        # get the difference between the two
        feedbacks_unread =\
            tuple(set(fbs_unread) - set(fbs_unread_copy))
        if feedbacks_unread:
            fb_unread = []
            messages_received_ids =\
                [ fb.objectId for fb in messages_received_list ]
            for feedback_id in feedbacks_unread:
                for fb in messages_received_list:
                    if fb.objectId == feedback_id:
                        fb_unread.append(fb.jsonify())
                        break
                
            if len(fb_unread) > 0:
                fb_count = 0
                for fb in messages_received_list:
                    if not fb.get("is_read"):
                        fb_count += 1
                data['feedbacks_unread'] = fb_unread
                data['feedback_unread_count'] = fb_count
          
        #############################################################
        # EMPLOYEES_PENDING ##################################
        # must also check if employee is already approved!
        emps_pending_copy = [ emp.objectId for emp in
            employees_pending_list_copy ]
        emps_pending = [ emp.objectId for emp in
            employees_pending_list ]
            
        employees_pending =\
            tuple(set(emps_pending) - set(emps_pending_copy))
            
        if employees_pending:
            pending = []
            for emp_id in employees_pending:
                for emp in employees_pending_list:
                    if emp.objectId == emp_id:
                        pending.append(emp.jsonify())
                        break
                    
            if len(pending) > 0:   
                data['employees_pending_count'] =\
                    len(employees_pending_list)
                data['employees_pending'] = pending
        
        #############################################################
        # EMPLOYEES APPROVED (pending to approved) #################
        emps_approved_copy = [ emp.objectId for emp in\
            employees_approved_list_copy]
        emps_approved = [ emp.objectId for emp in\
            employees_approved_list]
            
        appr_emps =\
            tuple(set(emps_approved) - set(emps_approved_copy))
        
        if appr_emps:
            approved = []
            for appr_emp_id in appr_emps:
                for emp in employees_approved_list:
                    if emp.objectId == appr_emp_id:
                        approved.append(emp.jsonify())
                        break
                        
            if len(approved) > 0:
                data['employees_approved'] = approved
                data['employees_pending_count'] =\
                    len(employees_pending_list)
            
        #############################################################
        # EMPLOYEES DELETED/DENIED/REJECTED (pending/approved to pop)!
        # need to compare approved and pending!
        emps_copy = emps_approved_copy[:]
        emps_copy.extend(emps_pending_copy)
        emps = emps_approved[:]
        emps.extend(emps_pending)
        
        # emps_copy has the same or more items that emps
        del_emps = tuple(set(emps_copy) - set(emps))
        
        if del_emps:
            deleted = []
            for demp_id in del_emps:
                if demp_id in emps_approved_copy:
                    emps_list = employees_approved_list_copy
                else:
                    emps_list = employees_pending_list_copy
                    
                for emp in emps_list:
                    if emp.objectId == demp_id:
                        deleted.append(emp.jsonify())
                        break  
                        
            if len(deleted) > 0:   
                data['employees_pending_count'] =\
                    len(employees_pending_list)
                data['employees_deleted'] = deleted
           
        #############################################################
        # REDEMPTIONS PENDING
        reds_pending_copy = [ r.objectId for r in\
            redemptions_pending_copy ]
        reds_pending = [ r.objectId for r in redemptions_pending ]
        
        reds = tuple(set(reds_pending) - set(reds_pending_copy))
        
        if reds:
            redemps = []
            for r_id in reds:
                for redemp in redemptions_pending:
                    if redemp.objectId == r_id:
                        redemps.append(redemp.jsonify())
                        break
                        
            if len(redemps) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_pending'] = redemps
                
        #############################################################
        # REDEMPTIONS APPROVED (pending to history)
        reds_past_copy = [ r.objectId for r in\
            redemptions_past_copy ]
        reds_past = [ r.objectId for r in redemptions_past ]
        
        appr_redemps =\
            tuple(set(reds_past) - set(reds_past_copy))
            
        if appr_redemps:   
            redemp_js = []
            for red_id in appr_redemps:
                for redemp in redemptions_past:
                    if redemp.objectId == red_id:
                        redemp_js.append(redemp.jsonify())
                        break
            
            if len(redemp_js) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_approved'] = redemp_js
            
        #############################################################
        # REDEMPTIONS DELETED ##############################
        # remove from pending (should not be in history!)
        reds_copy = reds_past_copy[:]
        reds_copy.extend(reds_pending_copy)
        reds = reds_past[:]
        reds.extend(reds_pending)
        
        # reds_copy has the same or more items that reds
        del_redemps = tuple(set(reds_copy) - set(reds))
        if del_redemps:
            redemp_js = []
            for red_id in del_redemps:
                reds_list = []
                if red_id in reds_past_copy:
                    reds_list = redemptions_past_copy
                elif red_id in reds_pending_copy:
                    reds_list = redemptions_pending_copy
                    
                for redemp in reds_list:
                    if redemp.objectId == red_id:
                        redemp_js.append(redemp.jsonify())
                        break               
            if len(redemp_js) > 0:
                data['redemption_pending_count'] =\
                    len(redemptions_pending)
                data['redemptions_deleted'] = redemp_js
            
        #############################################################
        # SETTINGS UPDATED ##############################
        settings_copy = session_copy.get("settings")
        settings = session.get("settings")
        if settings_copy.get("retailer_pin") !=\
            settings.get("retailer_pin"):
            data['retailer_pin'] = settings.get("retailer_pin")
        
        #############################################################
        # REWARDS UPDATED ##############################
        rewards_copy = session_copy.get("store").get("rewards")
        rewards_copy =\
            { reward['reward_id']:reward for reward in rewards_copy }
            
        rewards = session.get("store").get("rewards")
        rewards = { reward['reward_id']:reward for reward in rewards }
        updated_rewards = []
        
        for reward_id, rew_copy in rewards_copy.iteritems():
            # Note that some rewards may have been deleted!
            rew = rewards.get(reward_id)
            if rew and rew_copy['redemption_count'] !=\
                rew['redemption_count']:
                # only the redemtpion_count and reward_id are used
                # in the client side
                updated_rewards.append({
                    "reward_id": reward_id,
                    "redemption_count": rew['redemption_count'],
                })
        
        if updated_rewards:
            data['rewards'] = updated_rewards
           
        #############################################################
        # PATRONSTORE_COUNT ##################################
        patronStore_count_copy =int(session_copy["patronStore_count"])
        patronStore_count = int(session["patronStore_count"])
        if patronStore_count_copy != patronStore_count:
            data['patronStore_count'] = patronStore_count
            
            
        #############################################################
        # ACTIVE_STORE_LOCATION_ID ############################
        if session['active_store_location_id'] !=\
            session_copy['active_store_location_id']:
            data['active_store_location_id'] =\
                session['active_store_location_id']
            

        # IMPORTANT! The request.session is the same as the 
        # SessionStore(session_key)! so we must use the 
        # request.session because it is automatically saved at the end
        # of each request- thereby overriding/undoing any changes made
        # to the SessionStore(session_key) key!
        # need to check if we are still logged in
        session = SessionStore(request.session.session_key)
        if 'account' in session and SESSION_KEY in session:
            request.session.clear()
            request.session.update(session)
        else:
            flush(request.session)
        
        ############################################################
        # Respond ###########################################
        try: 
            return HttpResponse(json.dumps(data), 
                        content_type="application/json")
        except (IOError, socket.error) as e: # broken pipe/socket. 
            thread.exit() # exit silently
            
            
    ##################################################################
    ##### ENTRY POINT
    ######################################################
    # get the timestamp and uid
    t = parser.parse(request.GET["timestamp"])
    timestamp = str(t.hour).zfill(2) + ":" +\
        str(t.minute).zfill(2) + ":" + str(t.second).zfill(2)
    uid = request.GET['uid']
    
    # update the last_updated field of the CometSessionIndex
    try:
        csi = CometSessionIndex.objects.get(session_key=\
            request.session.session_key)
        csi.last_updated = timezone.now()
        csi.save()
    except CometSessionIndex.DoesNotExist:
        # should never go here but just in case.
        CometSessionIndex.objects.create(session_key=\
            request.session.session_key, 
            store_id=SESSION.get_store(request.session).objectId,
            last_updated=timezone.now())
        
        
    # register the CometSession
    CometSession.objects.update()
    CometSession.objects.create(session_key=\
        request.session.session_key, timestamp=timestamp, uid=uid)
    
    # cache the current session at this state
    session_copy = dict(request.session)
    timeout_time = timezone.now() + relativedelta(seconds=REQUEST_TIMEOUT)
    
    # keep going until its time to return a response forcibly
    while timezone.now() < timeout_time:  
        # need to update he objects manager to get the latest objects
        CometSession.objects.update() 
        try:     
            scomet = CometSession.objects.get(session_key=\
                request.session.session_key,
                timestamp=timestamp, uid=uid)
        except CometSession.DoesNotExist:
            # cometsession was deleted - time to go
            try:
                # make sure that the latest session is saved!
                # need to check if we are still logged in
                session = SessionStore(request.session.session_key)
                if 'account' in session and SESSION_KEY in session:
                    request.session.clear()
                    request.session.update(session)
                else:
                    flush(request.session)
                return HttpResponse(json.dumps({"result":-1}), 
                            content_type="application/json")
            except (IOError, socket.error) as e: 
                thread.exit() 
                
        if scomet.modified:
            # delete the registered comet session object
            CometSession.objects.update()
            try:
                scomet = CometSession.objects.get(session_key=\
                    request.session.session_key,
                    timestamp=timestamp, uid=uid)
                scomet.delete()
            except CometSession.DoesNotExist:
                pass # do nothing
            try:
                return comet(session_copy)
            except KeyError:
                # if a key error occurs then that probably means that
                # the session has been flushed- was logged out by user
                # or forcefully by server =)
                # now time to flag existing tabs.
                request.session.clear()
                try: 
                    return HttpResponse(json.dumps({"result": -3}), 
                                content_type="application/json")
                except (IOError, socket.error) as e: # broken pipe/socket. 
                    thread.exit() # exit silently
        else: # nothing new, sleep for a bit
            sleep(COMET_PULL_RATE)
            
            
    # TIME IS UP - return a response result 0 means no change 
    # try 1 last time
    if scomet.modified:
        # delete the registered comet session object
        CometSession.objects.update()
        try:
            scomet = CometSession.objects.get(session_key=\
                request.session.session_key,
                timestamp=timestamp, uid=uid)
            scomet.delete()
        except CometSession.DoesNotExist:
            pass # do nothing
        return comet(session_copy)
            
    # make sure that request.session is the most up to date
    session = SessionStore(request.session.session_key)
    # need to check if we are still logged in
    if 'account' in session and SESSION_KEY in session:
        request.session.clear()
        request.session.update(session)
    else:
        flush(request.session)
    
    # attempt to delete registered comet session if not yet deleted
    try:
        scomet = CometSession.objects.get(session_key=\
            request.session.session_key,
            timestamp=timestamp, uid=uid)
        scomet.delete()
    except CometSession.DoesNotExist:
        pass # do nothing
    
    try:
        return HttpResponse(json.dumps({"result":0}), 
                        content_type="application/json")
    except (IOError, socket.error) as e:
        thread.exit() # exit silently
Example #49
0
def employee_is_owner(session, employee_id):
    account = Account.objects().get(Employee=employee_id)
    return SESSION.get_store(session).is_owner(account)
Example #50
0
def account_is_admin(session):
    return SESSION.get_store(session).is_admin(session['account'])
Example #51
0
def trends_graph(request, data_type=None, start=None, end=None ):
    """
    Handles requests for the trends graph.
    """
    store = SESSION.get_store(request.session)
    
    # We need the store's timezone to convert everything to UTC
    # because the time we get from start and end are local times
    # and in order to convert to UTC we must first make start and end
    # timezone aware. We use parse.utils.make_aware_to_utc to do
    # this in 1 step. We convert everything to UTC for use in queries.
    store_timezone = SESSION.get_store_timezone(request.session)
    start = datetime.strptime(start, "%Y-%m-%d")
    end = datetime.strptime(end, "%Y-%m-%d")
    start = start.replace(hour=0, minute=0, second=0, microsecond=0)
    end = end.replace(hour=23, minute=59, second=59, microsecond=0)
    start_aware = make_aware_to_utc(start, store_timezone)
    end_aware = make_aware_to_utc(end, store_timezone)
    
    rows, columns = [], []
    
    if data_type == 'punches':
        # we need to return graph data for punches for all days in
        # between start and end.
        
        # columns contains the data that any given row needs to have.
        # rows contains multiple dates paired with punch count
        columns = [
            {"id":"", "label":"Date", "type":"string"},
            {"id":"", "label":'Punches', "type":"number"}
        ]
            
        # get the Punches
        punches = store.get('punches', createdAt__lte=end_aware,
            createdAt__gte=start_aware,order='createdAt', limit=900)
            
        # have to clear the punches cache attr of store filled
        # by the above query
        store.punches = None
        
        #create dictionary for easy search
        punch_map = {}
        if punches:
            for punch in punches:
                # The keys in the punch map is the month/day of the
                # createdAt of the punch object. We also convert it
                # to the store's local time for when we send back the
                # data to the client.
                key = timezone.localtime(punch.createdAt, 
                    store_timezone).strftime("%m/%d")
                    
                if key in punch_map:
                    # add to the punch count for the existing key
                    punch_map[key] =\
                        punch_map[key] + punch.get('punches')
                        
                else:
                    # initialize the key in the punch map
                    punch_map[key] = punch.get('punches')
    
        for single_date in rputils.daterange(start, end):
            # we now populate the rows with the corresponding punch counts
            # str_date is a day in between start and end with the
            # same format as a key in our punch_map            
            str_date = single_date.strftime("%m/%d")
            
            try:
                punch_count = punch_map[str_date]
            except KeyError:
                punch_count = 0
                    
            # the first item in our row is the date
            # the second item is the corresponding punch_count
            row = [{"v": str_date}, {"v": punch_count}]
            rows.append({'c': row})
            
    elif data_type == 'facebook':
        # we need to return graph data for facebook posts for
        # all days in between start and end.
        
        # columns contains the data that any given row needs to have.
        # rows contains multiple dates paired with post count
        columns = [
            {"id":"", "label":"Date", "type":"string"},
            {"id":"", "label":'Posts', "type":"number"}
        ]
            
        # get the FacebookPosts
        posts = store.get("facebookPosts", createdAt__lte=end,
                    createdAt__gte=start, limit=900)
        # have to clear the facebookPosts cache attr of store filled
        # by the above query
        store.facebookPosts = None
        
        #create dictionary for easy search
        post_map = {}
        if posts:
            for post in posts:
                # The keys in the post map is the month/day of the
                # createdAt of the punch object. We also convert it
                # to the store's local time for when we send back the
                # data to the client.
                key = timezone.localtime(post.createdAt, 
                    store_timezone).strftime("%m/%d")
                    
                if key in post_map:
                    # add to the post count for the existing key
                    post_map[key] = post_map[key] + 1
                    
                else:
                    # initialize the post count
                    post_map[key] = 1
    
        for single_date in rputils.daterange(start, end):
            # we now populate the rows with the corresponding post counts
            # str_date is a day in between start and end with the
            # same format as a key in our punch_map    
            str_date = single_date.strftime("%m/%d")
            
            try:
                post_count = post_map[str_date]
            except KeyError:
                post_count = 0
                    
            # the first item in our row is the date
            # the second item is the corresponding post_count
            row = [{"v": str_date}, {"v": post_count}]
            rows.append({'c': row})
            
    else: 
        # we need to return graph data for unique patrons for
        # all days in between start and end.
        
        # columns contains the data that any given row needs to have.
        # rows contains multiple dates paired with accumulative patron count
        columns = [
            {"id":"", "label":"Date", "type":"string"},
            {"id":"", "label":'Patrons', "type":"number"}
        ]

        for single_date in rputils.daterange(start, end):
            # str_date is a day in between start and end with the
            # same format as a key in our punch_map    
            str_date = single_date.strftime("%m/%d")
            
            # FIXME In order to get the cumulative count for each day,
            # we make a query of the count for each day. Optimization?
            d = single_date.replace(hour=23, minute=59, second=59)
            d_aware = make_aware_to_utc(d, store_timezone)
            patron_count = store.get('patronStores', count=1,
                                limit=0, createdAt__lte=d_aware)
                    
            row = [{"v": str_date}, {"v": patron_count}]
            rows.append({'c': row})
        
    # return the graph data
    return HttpResponse(json.dumps({'cols': columns, 'rows': rows}),
        content_type="application/json")
Example #52
0
def employee_is_owner(session, employee_id):
    account = Account.objects().get(Employee=employee_id)
    return SESSION.get_store(session).is_owner(account)
Example #53
0
def feedback_reply(request, feedback_id):
    """
    Render the feedback reply template.
    """
    account = request.session['account']
    store = SESSION.get_store(request.session)
    # data to be passed in the templace context
    data = {
        'messages_nav': True,
        'from_address': store.get("store_name"),
    }

    # get from the messages_received_list in session cache
    messages_received_list = SESSION.get_messages_received_list(\
        request.session)
    i_remove, feedback = 0, None
    for ind, m in enumerate(messages_received_list):
        if m.objectId == feedback_id:
            feedback = m
            i_remove = ind
            break

    if not feedback:
        # feedack not found - redirect to messages page with error message
        return redirect(reverse('messages_index')+ "?%s" %\
             urllib.urlencode({'error': 'Feedback not found.'}))

    if request.method == 'POST':
        # user submitted reply form
        body = request.POST.get('body')
        if body is not None:
            # strip the body so that it doesn't have trailing or
            # leading whitespaces
            body = body.strip()
        else:
            body = ""

        data['body'] = body

        if len(body) == 0:
            # body cannot be empty
            data['error'] = 'Please enter a message.'

        elif len(body) > 750:
            # body cannot exceed 750 cahracters
            data['error'] = 'Body must be less than 750 characters.'

        elif feedback.get('Reply'):
            # double check if feedback already has a reply
            # should not go here unless it is a hacker
            return redirect(reverse('messages_index')+ "?%s" %\
                 urllib.urlencode({'error':\
                    'Feedback has already been replied to.'}))

        else:
            # all valid - this method of validation is dirty and not
            # the way to do it in Django. Use a form instead.
            # I just got lazy here.

            # create the Parse Message object
            msg = Message.objects().create(message_type=\
                FEEDBACK, sender_name=store.get('store_name'),
                store_id=store.objectId, body=body)
            # add the created reply to the store's sent messages relation
            store.add_relation("SentMessages_", [msg.objectId])
            # set feedback Reply pointer to message and update it
            feedback.set('Reply', msg.objectId)
            feedback.update()

            # store the updated feedback
            messages_received_list.pop(i_remove)
            messages_received_list.insert(i_remove, feedback)
            request.session['messages_received_list'] =\
                messages_received_list

            # save the session now! cloud_call may take a bit!
            request.session.save()

            # make the cloud call
            cloud_call(
                "retailer_message", {
                    "store_id": store.objectId,
                    "store_name": store.get('store_name'),
                    "message_id": feedback.objectId,
                    "filter": 'one',
                    "patron_id": feedback.get('patron_id'),
                    "feedback_reply_body": body,
                })

            # notify other tabs/browsers logged into the same store
            # about the newly created message.
            comet_receive(
                store.objectId, {
                    COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY,
                    "newMessage": feedback.jsonify()
                })

            # make sure we have the latest session to save!
            request.session.clear()
            request.session.update(SessionStore(request.session.session_key))

            return redirect(reverse('feedback_details',
                args=(feedback.objectId,)) + "?%s" %\
                urllib.urlencode({'success':'Reply has been sent.'}))

    else:
        # user navigated to this page
        if feedback.get("Reply"):
            # if the user manually tweaks the url, then s/he might be
            # able to reply to a feedback that already has a reply.
            return redirect(reverse('feedback_details',
                args=(feedback.objectId,)) + "?%s" %\
                urllib.urlencode({'error':'Cannot reply more than once.'}))

    # update store session cache
    request.session['store'] = store
    data['feedback'] = feedback

    # store the updated feedback
    messages_received_list.pop(i_remove)
    messages_received_list.insert(i_remove, feedback)
    request.session['messages_received_list'] =\
        messages_received_list

    return render(request, 'manage/feedback_reply.djhtml', data)