def _retailer_message(store_id, subject, body, date_offer_expiration, message_type, offer_title, gift_title, gift_description, sender_name="Test Store", receiver_count=100, is_read=False, filter="all"): # first create the message message = Message(store_id=store_id, subject=subject, body=body, filter=filter, sender_name=sender_name, offer_title=offer_title, message_type=message_type, date_offer_expiration=\ date_offer_expiration, is_read=is_read, gift_description=\ gift_description, gift_title=gift_title) message.create() return cloud_call( "retailer_message", { "subject": subject, "message_id": message.objectId, "store_id": store_id, "store_name": sender_name, "filter": filter, })
def request_redeem_offers(patron_store_id): """ Requests all offers in the given patron_store's MessageStatus """ ps = PatronStore.objects().get(objectId=patron_store_id, include="Patron,Store") patron, store = ps.patron, ps.store message_statuses = patron.get("receivedMessages", redeem_available="yes", limit=999) for ms in message_statuses: message = Message.objects().get(objectId=ms.Message) cloud_call( "request_redeem", { "patron_id": ps.Patron, "store_id": ps.Store, "store_location_id": store.store_locations[0].objectId, "patron_store_id": ps.objectId, "title": message.offer_title, "reward_id": None, "num_punches": 0, "name": patron.get_fullname(), "message_status_id": ms.objectId, })
def _retailer_message(store_id, subject, body, date_offer_expiration, message_type, offer_title, gift_title, gift_description, sender_name="Test Store", receiver_count=100, is_read=False, filter="all"): # first create the message message = Message(store_id=store_id, subject=subject, body=body, filter=filter, sender_name=sender_name, offer_title=offer_title, message_type=message_type, date_offer_expiration=\ date_offer_expiration, is_read=is_read, gift_description=\ gift_description, gift_title=gift_title) message.create() return cloud_call("retailer_message", { "subject": subject, "message_id": message.objectId, "store_id": store_id, "store_name": sender_name, "filter": filter, })
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}))
def create_offer(self): offer = Message.objects().create(**{ 'subject': u'test_request_validate_redeem script message offer', 'body': u'test_request_validate_redeem script generate offer', 'sender_name': u'test_request_validate_redeem', 'store_id': self.store.objectId, 'is_read': False, 'offer_redeemed': False, 'date_offer_expiration': timezone.now()+relativedelta(days=1), 'filter': u'all', 'offer_title': u'test_request_validate_redeem script offer', 'message_type': 'offer', }) cloud_call("retailer_message", { "filter": offer.filter, "store_name": self.store.store_name, "message_id": offer.objectId, "store_id": self.store.objectId, "subject": offer.subject, }) return offer
def request_redeem_offers(patron_store_id): """ Requests all offers in the given patron_store's MessageStatus """ ps = PatronStore.objects().get(objectId=patron_store_id, include="Patron,Store") patron, store = ps.patron, ps.store message_statuses = patron.get("receivedMessages", redeem_available="yes", limit=999) for ms in message_statuses: message = Message.objects().get(objectId=ms.Message) cloud_call("request_redeem", { "patron_id": ps.Patron, "store_id": ps.Store, "store_location_id": store.store_locations[0].objectId, "patron_store_id": ps.objectId, "title": message.offer_title, "reward_id": None, "num_punches": 0, "name": patron.get_fullname(), "message_status_id": ms.objectId, })
def processCometReceivedDict(session, postDict): employees_pending_list =\ SESSION.get_employees_pending_list(session) employees_approved_list =\ SESSION.get_employees_approved_list(session) messages_received_list =\ SESSION.get_messages_received_list(session) redemptions_pending =\ SESSION.get_redemptions_pending(session) redemptions_past =\ SESSION.get_redemptions_past(session) ############################################################# # FEEDBACKS_UNREAD ################################## newFeedback = postDict.get('newFeedback') if newFeedback: messages_received_ids =\ [ fb.objectId for fb in messages_received_list ] m = Message(**newFeedback) if m.objectId not in messages_received_ids: messages_received_list.insert(0, m) session['messages_received_list'] =\ messages_received_list ############################################################# # FEEDBACK DELETED ################################## deletedFeedback = postDict.get("deletedFeedback") if deletedFeedback: fb = Message(**deletedFeedback) for i, mro in enumerate(messages_received_list): if fb.objectId == mro.objectId: messages_received_list.pop(i) break session['messages_received_list'] =\ messages_received_list ############################################################# # MESSAGE SENT ################################## # need to check if this new message is an original message # or a reply to a feedback (the message sent by the patron)! # also may increment the message count! newMessage = postDict.get("newMessage") if newMessage: messages_received_ids =\ [ fb.objectId for fb in messages_received_list ] messages_sent_list =\ SESSION.get_messages_sent_list(session) messages_sent_ids =\ [ msg.objectId for msg in messages_sent_list ] m = Message(**newMessage) if m.objectId not in messages_sent_ids and\ m.message_type != FEEDBACK: messages_sent_list.insert(0, m) if 'message_count' in session: session['message_count'] =\ int(session['message_count']) + 1 # update an existing feedback if m.objectId in messages_received_ids and\ m.message_type == FEEDBACK: for i, mrl in enumerate(messages_received_list): if mrl.objectId == m.objectId: messages_received_list.pop(i) messages_received_list.insert(i, m) break session['messages_received_list'] =\ messages_received_list session['messages_sent_list'] = messages_sent_list ############################################################# # EMPLOYEES_PENDING ################################## # must also check if employee is already approved! pendingEmployee = postDict.get("pendingEmployee") if pendingEmployee: employees_approved_ids =\ [ emp.objectId for emp in employees_approved_list ] employees_pending_ids =\ [ emp.objectId for emp in employees_pending_list ] e = Employee(**pendingEmployee) if e.objectId not in employees_pending_ids and\ e.objectId not in employees_approved_ids: employees_pending_list.insert(0, e) session['employees_pending_list'] =\ employees_pending_list ############################################################# # EMPLOYEES APPROVED (pending to approved) ################# approvedEmployee = postDict.get("approvedEmployee") if approvedEmployee: emp = Employee(**approvedEmployee) # first check if the employee is in the pending list # if not then check if it is already approved for i, emp_pending in\ enumerate(employees_pending_list): if emp.objectId == emp_pending.objectId: emp = employees_pending_list.pop(i) emp.status = APPROVED employees_approved_list.insert(0, emp) break session['employees_pending_list'] =\ employees_pending_list session['employees_approved_list'] =\ employees_approved_list ############################################################# # EMPLOYEES NEW (straight to approved) ################# newEmployee = postDict.get("newEmployee") if newEmployee: employees_approved_ids =\ [ emp.objectId for emp in employees_approved_list ] emp = Employee(**newEmployee) if emp.objectId not in employees_approved_ids: employees_approved_list.insert(0, emp) session['employees_approved_list'] =\ employees_approved_list ############################################################# # EMPLOYEES DELETED/DENIED/REJECTED (pending/approved to pop)! deletedEmployee = postDict.get("deletedEmployee") if deletedEmployee: emp = Employee(**deletedEmployee) # check in approved emps for i, cop in enumerate(employees_approved_list): if cop.objectId == emp.objectId: employees_approved_list.pop(i) break # check in pending emps for i, cop in enumerate(employees_pending_list): if cop.objectId == emp.objectId: employees_pending_list.pop(i) break session['employees_approved_list'] =\ employees_approved_list session['employees_pending_list'] =\ employees_pending_list ############################################################# # EMPLOYEE UPDATED PUNCHES updatedEmployeePunch = postDict.get("updatedEmployeePunch") if updatedEmployeePunch: u_emp = Employee(**updatedEmployeePunch) for emp in employees_approved_list: if u_emp.objectId == emp.objectId: emp.set("lifetime_punches", u_emp.lifetime_punches) break session['employees_approved_list'] =\ employees_approved_list ############################################################# # REDEMPTIONS PENDING ### Only added to cache if it has the store_location_id as ### active_store_location_id pendingRedemption = postDict.get("pendingRedemption") if pendingRedemption: rr = RedeemReward(**pendingRedemption) # store_location_id can be null for backwards compat if not rr.store_location_id or rr.store_location_id ==\ session.get('active_store_location_id'): redemptions_pending_ids =\ [ red.objectId for red in redemptions_pending ] redemptions_past_ids =\ [ red.objectId for red in redemptions_past ] # need to check here if the redemption is new because # the dashboard that validated it will also receive # the validated redemption back. if rr.objectId not in redemptions_past_ids and\ rr.objectId not in redemptions_pending_ids: redemptions_pending.insert(0, rr) session['redemptions_pending'] =\ redemptions_pending ############################################################# # REDEMPTIONS APPROVED (pending to history) # Save cpu by skipping those that do not have the same # store_location_id as active_store_location_id approvedRedemption = postDict.get("approvedRedemption") if approvedRedemption: redemp = RedeemReward(**approvedRedemption) # store_location_id can be null for backwards compat if not redemp.store_location_id or redemp.store_location_id ==\ session.get('active_store_location_id'): # check if redemp is still in pending for i, redem in enumerate(redemptions_pending): if redem.objectId == redemp.objectId: r = redemptions_pending.pop(i) r.is_redeemed = True r.updatedAt = redemp.updatedAt redemptions_past.insert(0, r) break # if not then check if it is in the history already # the above shouldn't happen! session['redemptions_pending'] =\ redemptions_pending session['redemptions_past'] =\ redemptions_past ############################################################# # REDEMPTIONS DELETED ############################## # remove from pending (should not be in history!) # Save cpu by skipping those that do not have the same # store_location_id as active_store_location_id deletedRedemption = postDict.get("deletedRedemption") if deletedRedemption: redemp = RedeemReward(**deletedRedemption) # store_location_id can be null for backwards compat if not redemp.store_location_id or redemp.store_location_id ==\ session.get('active_store_location_id'): # check if redemp is still in pending for i, redem in enumerate(redemptions_pending): if redem.objectId == redemp.objectId: redemptions_pending.pop(i) break session['redemptions_pending'] =\ redemptions_pending ############################################################# # STORE UPDATED ############################## updatedStore = postDict.get("updatedStore") if updatedStore: store = Store(**updatedStore) # have to add the image url manually store.thumbnail_image_url = updatedStore.get("thumbnail_image_url") store.cover_image_url = updatedStore.get("cover_image_url") # below here for backwards compat store.store_avatar_url = store.thumbnail_image_url session['store'] = store updatedStoreThumbnailName = postDict.get("updatedStoreThumbnailName") if updatedStoreThumbnailName: store = session['store'] store.thumbnail_image = updatedStoreThumbnailName store.thumbnail_image_url = postDict.get( "updatedStoreThumbnailUrl") # below here for backwards compat store.store_avatar = store.thumbnail_image store.store_avatar_url = store.thumbnail_image_url session['store'] = store updatedStoreCoverName = postDict.get("updatedStoreCoverName") if updatedStoreCoverName: store = session['store'] store.cover_image = updatedStoreCoverName store.cover_image_url = postDict.get("updatedStoreCoverUrl") session['store'] = store # this is in the settings tab in the dashboard but the field # is in the Store class updatedPunchesFacebook_int =\ postDict.get("updatedPunchesFacebook_int") if updatedPunchesFacebook_int: store = session['store'] store.punches_facebook = int(updatedPunchesFacebook_int) session['store'] = store ############################################################# # STORE LOCATION UPDATED ############################## ### Note that this is also being used to insert new StoreLocations updatedStoreLocation = postDict.get("updatedStoreLocation") if updatedStoreLocation: store_location = StoreLocation(**updatedStoreLocation) session['store_locations'][store_location.objectId] =\ store_location try: # also update the store_timezone session['store_timezone'] =\ pytz.timezone(store_location.get('store_timezone')) except Exception: # assign a default timezone session['store_timezone'] =\ pytz.timezone(TIME_ZONE) ############################################################# # ACCOUNT UPDATED ############################## updatedAccount = postDict.get("updatedAccount") if updatedAccount: updatedAccountObject = Account(**updatedAccount) # need to make sure that these are the same accounts! if session['account'].objectId ==\ updatedAccountObject.objectId: session['account'] = updatedAccountObject ############################################################# # SUBSCRIPTION UPDATED ############################## updatedSubscription =\ postDict.get("updatedSubscription") if updatedSubscription: subscription = Subscription(**updatedSubscription) store = session["store"] store.set('subscription', subscription) store.set('Subscription', subscription.objectId) session['subscription'] = subscription session['store'] = store ############################################################# # SETTINGS UPDATED ############################## updatedSettings = postDict.get("updatedSettings") if updatedSettings: settings = Settings(**updatedSettings) store = session["store"] store.set('settings', settings) store.set("Settings", settings.objectId) session['settings'] = settings session['store'] = store ############################################################# # REWARDS NEW ############################## newReward = postDict.get("newReward") if newReward: store = session['store'] rewards = store.get("rewards") rewards_ids = [r['reward_id'] for r in rewards] if newReward['reward_id'] not in rewards_ids: rewards.append(newReward) store.rewards = rewards session['store'] = store ############################################################# # REWARDS UPDATED ############################## updatedReward = postDict.get('updatedReward') if updatedReward: store = session['store'] mod_rewards = store.get("rewards") for i, mreward in enumerate(mod_rewards): # [{"reward_name":"Free bottle of wine", # "description":"Must be under $25 in value", # "punches":10,"redemption_count":0,reward_id:0},] if updatedReward['reward_id'] == mreward['reward_id']: if updatedReward.has_key("redemption_count"): mod_rewards[i]['redemption_count'] =\ updatedReward['redemption_count'] if updatedReward.has_key("reward_name"): mod_rewards[i]['reward_name'] =\ updatedReward['reward_name'] if updatedReward.has_key("punches"): mod_rewards[i]['punches'] =\ updatedReward['punches'] if updatedReward.has_key("description"): mod_rewards[i]['description'] =\ updatedReward['description'] break store.rewards = mod_rewards session['store'] = store ############################################################# # REWARDS DELETED ############################## deletedReward = postDict.get("deletedReward") if deletedReward: store = session['store'] rewards = store.get("rewards") rewards_ids = [r['reward_id'] for r in rewards] if deletedReward['reward_id'] in rewards_ids: for i, r in enumerate(rewards): if r['reward_id'] == deletedReward['reward_id']: rewards.pop(i) break store.rewards = rewards session['store'] = store ############################################################# # PATRONSTORE_COUNT ################################## patronStore_int = postDict.get('patronStore_int') if patronStore_int: patronStore_int = int(patronStore_int) session['patronStore_count'] = patronStore_int
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)
def edit(request, message_id): """ Render the message edit template for a new message and handles send message forms. """ data = {'messages_nav': True, 'message_id': message_id, "filters": FILTERS} store = SESSION.get_store(request.session) # number of patron stores mp = SESSION.get_patronStore_count(request.session) # make sure cache attr is None for future queries! store.patronStores = None data['mp_slider_value'] = int(ceil(float(mp) * 0.50)) data['mp_slider_min'] = 1 data['mp_slider_max'] = mp # redirect if no patrons if not store.get("patronStores", count=1, limit=0): return redirect(reverse("messages_index")) # user submitted a form by form submission through POST request # or user is coming from an upgrade sequence from subscription_update if request.method == 'POST' or (request.method == "GET" and\ request.GET.get("send_message") and "message_b4_upgrade" in\ request.session): if request.method == "GET": # user is coming from an upgrade sequence from subscription_update postDict = request.session['message_b4_upgrade'].copy() # cleanup temp vars in session del request.session['message_b4_upgrade'] del request.session['from_limit_reached'] else: # user submitted a form by form submission through POST request postDict = request.POST.dict().copy() # populate a message form with the POST data for validation form = MessageForm(postDict) if form.is_valid(): # form is valid so continue to send the message subscription = SESSION.get_subscription(request.session) subType = subscription.get('subscriptionType') # refresh the message count - make sure we get the one in the cloud if 'message_count' in request.session: del request.session['message_count'] message_count = SESSION.get_message_count(request.session) # get the max_messages from the user's subscriptionType # or the highest level if god_mode is on if subscription.god_mode: max_messages = sub_type[2]['max_messages'] else: max_messages = sub_type[subType]['max_messages'] # limit is reached if the amount of messages sent this # billing cycle passed the amount for that subscription type limit_reached = message_count >= max_messages # We always enforce the limit when we are in production # otherwise, we ignore it if we have message_limit_off in our session if limit_reached and (PRODUCTION_SERVER or\ (not PRODUCTION_SERVER and "message_limit_off" not in request.session)): data['limit_reached'] = limit_reached # not the highest level of subscription so an upgrade # is still possible if subType != 2: # save the dict to the session request.session['message_b4_upgrade'] =\ request.POST.dict().copy() # the highest level of subscription so no more # upgrades can occur - therefore maxed_out elif subType == 2: data['maxed_out'] = True else: # limit has not yet been reached - send the message # build the message from session and POST data message = Message(\ sender_name=store.get('store_name'), store_id=store.objectId ) message.update_locally(postDict, False) # check if attach offer is selected if 'attach_offer' in postDict: # message has an offer - extract it from the post # post data ensuring proper datetime format d = parser.parse(postDict['date_offer_expiration']) d = make_aware_to_utc( d, SESSION.get_store_timezone(request.session)) message.set('date_offer_expiration', d) message.set('message_type', OFFER) else: # make sure to delete offer information in the case # that attach offer is not checked but the form # submitted still contained offer information message.set('offer_title', None) message.set('date_offer_expiration', None) message.set('message_type', BASIC) # actually create the message to Parse message.create() # put the message in the template context for rendering data['message'] = message # add to the store's relation store.add_relation("SentMessages_", [message.objectId]) # prepare the parameters for the cloud call params = { "store_id": store.objectId, "store_name": store.get('store_name'), "subject": message.get('subject'), "message_id": message.objectId, "filter": message.filter, } # process the filter option if message.filter == "idle": # pass in the correct idle_date which is today # minus the days specified by idle_latency idle_days = postDict['idle_latency'] d = timezone.now() + relativedelta(days=\ -1*int(idle_days)) params.update({"idle_date": d.isoformat()}) elif message.filter == "most_loyal": # pass in the number of patrons params.update({"num_patrons": postDict['num_patrons']}) # update store and message_count in session cache request.session['message_count'] = message_count request.session['store'] = store # save session- cloud_call may take a while! request.session.save() # make the cloud call res = cloud_call("retailer_message", params) if "error" not in res and res.get("result"): message.set("receiver_count", res.get("result").get("receiver_count")) # notify other tabs and windows that are logged into # this store about the new message sent. payload = { COMET_RECEIVE_KEY_NAME: COMET_RECEIVE_KEY, "newMessage": message.jsonify() } comet_receive(store.objectId, payload) # Note that the new message is saved in comet_receive # make sure we have the latest session to save! request.session.clear() request.session.update( SessionStore(request.session.session_key)) return HttpResponseRedirect(message.get_absolute_url()) elif 'num_patrons' in form.errors: # form is invalid due to the number of patrons input # for most_loyal filter data['error'] = "Number of customers must be a "+\ "whole number and greater than 0." else: # form has some errors data['error'] = "The form you submitted has errors." else: # check if the incoming request is for an account upgrade if request.GET.get("do_upgrade"): # flag the upgrade view request.session["from_limit_reached"] = True # redirect to upgrade account return HttpResponseRedirect(reverse("subscription_update") +\ "?do_upgrade=1") if message_id in (0, '0'): # this is a new message so just instantiate a new form form = MessageForm() else: # this is an existing message that the user wants to view # 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("error"): data['error'] = request.GET.get("error") if request.GET.get("success"): data['success'] = request.GET.get("success") # get from the messages_sent_list in session cache messages_sent_list = SESSION.get_messages_sent_list(\ request.session) for m in messages_sent_list: if m.objectId == message_id: data['message'] = m if data['message']: # message is found so fill up the form with its data form = MessageForm(data['message'].__dict__.copy()) else: # message not found so just instantiate a new form form = MessageForm() # update store session cache request.session['store'] = store # inject the form in the template context for rendering data['form'] = form return render(request, 'manage/message_edit.djhtml', data)