def update_person_details(backend, user, user_profile, response, **kwargs): """Update user profile using data from provider.""" if user is None or user_profile is None: return try: person_auth = user.social_auth.get(provider=backend.name) except ObjectDoesNotExist: # TODO: person_auth should always exist in our pipeline, but for some # reason it sometimes doesn't. Find out why return if response: if not user_profile.city: city = response.get('location', None) if city: # Uppsala, Sweden -> Uppsala user_profile.city = city['name'].split(',')[0] if not user_profile.birthday: birthday = response.get('birthday', None) if birthday: month, day, year = birthday.split('/') # Quick hack, make this prettier if int(month) > 12: month, day = day, month user_profile.birthday = '-'.join([year, month, day]) if not user_profile.gender: gender = response.get('gender', 'male') if gender == 'male': user_profile.gender = UserProfile.GENDER_MALE elif gender == 'female': user_profile.gender = UserProfile.GENDER_FEMALE user_profile.save() _load_person_avatar(backend, user, user_profile, response) _load_person_description(backend, user, user_profile, person_auth) # When all the data is synchronised with facebook do a 'user_signup' event # These accounts don't require activation because it comes via Facebook if kwargs.get('is_new', False): Events(kwargs['request']).user_signup(user, requires_activation=False) else: Events(kwargs['request']).logged_in(user) return {}
def form_valid(self, form): user = form.save() if user.user_profile is None: profile = UserProfile(user=user) else: profile = user.user_profile gender = form.cleaned_data.get('gender') if gender is not None and not 'x' in gender: profile.gender = gender profile.send_newsletters = form.cleaned_data.get( 'marketing_optin') != 'false' profile.activation_key = profile.generate_activation_key() profile.detected_country = self.request.country profile.preferred_currency = self.request.session.get( 'preferred_currency', '') profile.save() Events(self.request).user_signup(user) # login user password = form.cleaned_data.get('password') user = authenticate(username=user.username, password=password) login(self.request, user) messages.success(self.request, REGISTER_SUCCESS_MESSAGE) return render(self.request, "mailing_lists/fragments/capture_complete.html")
def update_cartstall(self, cart, product, quantity): try: cart.set_quantity(product, quantity) except purchase.models.OutOfStockError: return HttpResponse(status=409, content=json.dumps({ "error_title": "not enough stock", "error_message": "There is not enough stock to increase " "the number of items", }), content_type="application/json") Events(self.request).cart_updated(cart) if quantity < 0: quantity = 0 if quantity == 0: return self.render_to_response( self.request, { "product_id": product.id, "quantity": 0, "num_items": float(cart.num_items()), }) cart_stall = cart.cart_stalls.get(stall=product.stall) return self.render_to_response( self.request, { "product_id": product.id, "quantity": quantity, "total": float(cart_stall.total().amount), "subtotal": float(cart_stall.sub_total.amount), "discount": float(cart_stall.discount_amount().amount), "delivery": float(cart_stall.delivery_total().amount), "num_items": float(cart.num_items()), })
def put(self, request, cart_stall=None): try: data = json.loads(request.body) except ValueError: return HttpResponseBadRequest("invalid json") if "country" in data: country_id = data["country"]["id"] if country_id is not None: country = get_object_or_404(Country, id=country_id) else: country = None # This should be done with an exception on the mode if country not in cart_stall.get_countries(): return HttpResponse( status=409, content=json.dumps({ "error_title": "Unavailable Country", "error_message": "These items cannot be shipped to that country" }), content_type="application/json") cart_stall.speculative_country = country if "coupon" in data: cart_stall.coupon_code = data["coupon"] if "note" in data: cart_stall.note = data["note"] cart_stall.save() Events(request).cart_updated(cart_stall.cart) return HttpResponse(json.dumps(cart_stall.to_json()), content_type="application/json")
def create_stall(request, template_name='marketplace/create_stall.html'): """ Handles the first time creation of a stall. Also handles some stall owner details which goto UserProfile models. """ context = {} user = request.user # If stall exists, redirect to edit version try: stall = user.stall if stall: return redirect('edit_stall', stall.slug) except: stall = None profile_form = StallOwnerProfileForm(request.POST or None, instance=user.get_profile()) creation_form = StallForm(request.POST or None) if request.method == "POST": # Forcing all to validate to populate errors profile_form.is_valid() or creation_form.is_valid() if profile_form.is_valid() and creation_form.is_valid(): profile_form.save() stall = creation_form.save(commit=False) stall.user = request.user stall.save() user_email = request.user.email_notification if stall.email_opt_in: user_email.stall_owner_tips = True else: user_email.stall_owner_tips = False user_email.save() if not stall.user.get_profile().is_activated(): stall.user.todos.create(view_name="validate_email") Events(request).stall_opened(stall) request.session.pop('new_user', None) request.session['new_seller'] = True return HttpResponseRedirect( reverse('profile') + '?openStallSuccess=true') else: if not (profile_form.is_valid() or creation_form.is_valid()): messages.info(request, STALL_CREATE_MESSAGE) context.update({ 'profile_form': profile_form, 'creation_form': creation_form }) return render(request, template_name, context)
def save(self, *args, **kwargs): """ Notify events subsystem when user changes their e-mail This handles updating mailing lists etc. """ result = super(AccountForm, self).save(*args, **kwargs) if self.email_changed: Events(None).user_changed_email(self.instance, self.old_email, self.new_email) return result
def mark_dispatched(request, order_id=None): order = get_object_or_404(Order, id=order_id) if "redirect_url" in request.REQUEST: redirect_url = request.REQUEST["redirect_url"] else: redirect_url = reverse("sold_awaiting_shipping") if order.stall.user != request.user: return HttpResponseForbidden("You cannot mark this order dispatched") order.mark_dispatched() Events(request).order_dispatched(order) return HttpResponseRedirect(redirect_url)
def handle(self, *args, **kwargs): # handle orders which have not been dispatched after 14 days self.stdout.write("Processing overdue orders\n") for order in Order.objects.dispatch_overdue(14).all(): self.stdout.write("overdue order number {0}\n".format(order.id)) # if email not sent then send email to seller asking them # to mark dispatched. Also, this will send a reminder every # day, we may want to control that a bit. Events(none).order_reminder(order) self.stdout.write("Refunding orders overdue by 30 days\n") for order in Order.objects.dispatch_overdue(30).all(): self.stdout.write("Refunding order number {0}\n".format(order.id)) # refund order and notify merchant and user order.refund() Events(none).order_refunded(order) self.stdout.write("Executing payments\n") for order in Order.objects.ready_to_pay(30).all(): self.stdout.write("Executing payment for order number {0}\n".format(order.id)) order.payment.execute()
def checkout_pay_stall(request, cart_stall_id, template_name=None): """ Generates Pay(PAY_PRIMARY) request, and redirects buyer to paypal. """ # TODO Put this all in a model somewhere context = {} cart_stall = get_object_or_404(CartStall, id=cart_stall_id) payment = Payment.objects.create( purchaser=request.user, amount=cart_stall.total(), discount_amount=cart_stall.discount_amount(), ) payment_attempt = PaymentAttempt.objects.create(payment=payment, cart_stall=cart_stall) try: success = payment.process(request) except PayError as pe: seller_notified = False # Either errors where seller account is not verified/confirmed OR # seller needs to change settings to accept payment in another currency # see http://bit.ly/183muku if pe.error_id in ['559044', '569042', '520009']: Events(request).seller_paypal_error(payment_attempt) error_message = UNVERIFIED_PAYPAL_EMAIL_ERROR seller_notified = True else: error_message = "There was an error communicating with PayPal" notify_directors_of_paypal_error( request, { 'payment': payment, 'payment_attempt': payment_attempt, 'seller_notified': seller_notified, 'pe': pe, 'cart_stall': cart_stall }) cart_url = reverse("checkout_cart") messages.error(request, error_message) return HttpResponseRedirect(cart_url) if success: return HttpResponseRedirect(payment.next_url()) # Normally the user will never get here, on production nobody has ever # gotten here.... does it even work? context.update({ 'cart': cart_stall.cart, 'cart_stall': cart_stall, 'success': success, }) request.clicktale.record = True return render(request, template_name, context) # TODO: error template
def try_become_friends(request, user_id): redirect_url = request.GET.get('follow') follow_user = get_object_or_404(User, pk=user_id) if follow_user != request.user: relation_exists = UserFollow.relation_exists(request.user, follow_user) if not relation_exists: follow = UserFollow(user=request.user, target=follow_user) follow.save() Events(request).user_followed(follow) messages.success(request, 'Thanks, you have been logged in and you are ' 'now following %s' % follow_user.username) return HttpResponseRedirect(redirect_url)
def form_valid(self, form): # discard if notifications are unwanted marketing_optin = form.cleaned_data.get('marketing_optin', True) form.instance.set_ip_address(self.request) mls = form.save() # This is used in Campaign Tracking self.request.session['email_lead'] = mls.id Events(self.request).newsletter_signup(email=mls.email_address) url_data = urlencode({ "marketing_optin": "true" if marketing_optin else "false", "email": form.cleaned_data["email_address"], }) return HttpResponseRedirect(reverse("quick_register") + "?" + url_data)
def checkout_add(request, slug): """ Adds product to cart. """ product = get_object_or_404(Product, slug=slug) country = None if request.POST.get('shipping_country', None): try: country = Country.objects.get( code=request.POST.get('shipping_country', None)) except: pass # When no cart is found, send them to login - where all users have carts if getattr(request.user, 'cart', None) is None: # This allows a streamlined log in process, the product_to_add_id # session variable is used by the register view to add a product # to the cart and redirect straight to the cart view. request.session["product_to_add_id"] = product.id login_url = reverse('login') return redirect_to_login(reverse('checkout_cart'), login_url=login_url) cart = request.user.cart try: # If the user is anonymous the cart won't exist in the DB yet # This avoids doing a DB insert for every request. if cart.id is None: cart.save() cart.add(product, country=country) mixpanel_track( request, 'Clicked Add to Cart', { 'Product Title': product.title, 'Product ID': product.id, 'Number in stock': 'unlimited' if product.stock is None else product.stock, 'Number of Images': product.images.all().count(), 'Has Welcome Video': product.stall.has_welcome_video(), 'Ships Worldwide': product.shipping_profile.ships_worldwide(), 'Price': str(product.get_price_instance().amount) }) Events(request).cart_updated(cart) except purchase.models.OutOfStockError: messages.error(request, "That product is out of stock") return HttpResponseRedirect(reverse('checkout_cart'))
def handle(self, *args, **kwargs): exceptions = [] from purchase.models import Order for order in Order.objects.ready_to_pay(0): try: order.payment.execute() except Exception as ex: logger.error("Error processing payment for order {0}".format( order.id), exc_info=True) for overdue_days in [3, 7, 13, 14]: for order in Order.objects.dispatch_overdue_by(overdue_days): print("Sending {0} day overdue reminder for order id " "{1}".format(overdue_days, order.id)) Events(None).order_reminder(order)
def save(self, domain_override=None, subject_template_name=None, email_template_name=None, use_https=False, token_generator=default_token_generator, from_email=None, request=None): """ Overriding the save function, so we can use our own html email template """ for user in self.users_cache: if not domain_override: current_site = get_current_site(request) site_name = current_site.name domain = current_site.domain else: site_name = domain = domain_override Events(request).forgot_password(user)
def register(request, template_name='accounts/register.html'): """ Allow a user to register an account. :returns: A :py:class:`!django.http.HttpResponse` on GET, which renders a registration form. A :py:class:`!django.http.HttpResponseRedirect on successful POST, which redirects to the 'success' view. """ context = {} post_signup_url = request.REQUEST.get('next') or 'register_success' if "post_signup_url" in request.session: post_signup_url = request.session["post_signup_url"] reg_form = RegistrationForm(request.POST or None) profile_form = UserProfileForm(request.POST or None) if reg_form.is_valid() and profile_form.is_valid(): user = reg_form.save() if user.user_profile is not None: # Re-make the profile form against the auto-created user profile profile_form = UserProfileForm(request.POST, instance=user.user_profile) user_profile = profile_form.save(commit=False) user_profile.user = user user_profile.activation_key = user_profile.generate_activation_key() user_profile.detected_country = request.country user_profile.preferred_currency = request.session.get( 'preferred_currency', '') user_profile.save() Events(request).user_signup(user) # logging him in user.backend = 'django.contrib.auth.backends.ModelBackend' auth_login(request, user) request.session['new_user'] = True messages.success(request, REGISTER_SUCCESS_MESSAGE) return redirect(post_signup_url) context.update({'reg_form': reg_form, 'profile_form': profile_form}) return render(request, template_name, context)
def follow(request, user_id): if request.method == "POST": follow_user = User.objects.get(pk=user_id) if follow_user == request.user: return JsonResponse({"status": "KO", "error_message": "You cannot become friends with yourself", 'user': request.user.pk, 'other_user': follow_user.pk }) relation_exists = UserFollow.relation_exists(request.user, follow_user) if relation_exists: return JsonResponse({"status": "KO", "error_message": "You cannot become friends with a user you follow."}) follow = UserFollow(user=request.user, target=follow_user) follow.save() Events(request).user_followed(follow) return JsonResponse({"status": "OK"})
def stockcheck_start(request, template_name='accounts/stockcheck/landing.html'): """ Allow a user to log in with either username/email and password. """ next_url = reverse('stockcheck_update') context = { 'next': next_url, 'social_login_error': int(request.GET.get('social-login-error', 0)), } mixpanel_track( request, 'Clicked CTA In Renewal Email' ) data = request.POST or None login_form = LoginForm(data=data) if request.user.is_authenticated(): return HttpResponseRedirect(next_url) if login_form.is_valid(): username = login_form.cleaned_data.get('username', None) password = login_form.cleaned_data.get('password', None) user = authenticate(username=username, password=password) login_success = user and not user.is_anonymous() if login_success: login(request, user) Events(request).logged_in(user) if not request.POST.get('remember_me', None): expiry = 0 else: expiry = SESSION_EXPIRY request.session.set_expiry(expiry) return HttpResponseRedirect(next_url) context.update({'login_form': login_form}) return render(request, template_name, context)
def unfollow(request, user_id): if request.is_ajax() and request.method == "POST": unfollow_user = User.objects.get(pk=user_id) if unfollow_user == request.user: error_message = "You cannot stop being friends with yourself " \ "because you cannot be friends with yourself" return JsonResponse({"status": "KO", "error_message": error_message}) relation_exists = UserFollow.relation_exists(request.user, unfollow_user) if not relation_exists: error_message = "You cannot stop being friends with someone you are not friends with." return JsonResponse({"status": "KO", "error_message": error_message}) relation = UserFollow.objects.get(user=request.user, target=unfollow_user) Events(request).user_unfollowed(relation) relation.delete() return JsonResponse({"status": "OK"})
def login(request, template_name='accounts/login.html'): """ Allow a user to log in with either username/email and password. """ next_url = request.REQUEST.get('next') context = { 'next': next_url, 'social_login_error': int(request.GET.get('social-login-error', 0)), } data = request.POST or None login_form = LoginForm(data=data) redirect_to = next_url or '/' if request.user.is_authenticated(): return redirect(redirect_to) if login_form.is_valid(): username = login_form.cleaned_data.get('username', None) password = login_form.cleaned_data.get('password', None) user = authenticate(username=username, password=password) login_success = user and not user.is_anonymous() if login_success: auth_login(request, user) Events(request).logged_in(user) if not request.POST.get('remember_me', None): expiry = 0 else: expiry = SESSION_EXPIRY request.session.set_expiry(expiry) return redirect(redirect_to) context.update({'login_form': login_form}) return render(request, template_name, context)
def post(self, request, order_id=None, *args, **kwargs): data = request.REQUEST order = get_object_or_404(Order, id=order_id) if request.user != order.stall.user: return HttpResponseForbidden("That order does not belong to you") if "reason" not in data: return HttpResponseBadRequest("You must specify a reason") if "entire_order" in data: order.refund(data["reason"]) order.save() else: if "line_items" not in data: return HttpResponseBadRequest("You must specify line items" "as a list of ids or set entire " "order to True") ids = data["line_items"] line_items = order.line_items.filter(id__in=ids) order.refund(data["reason"], line_items=line_items) order.save() Events(request).order_refunded(order) redirect_url = reverse("invoice", kwargs={"order_id": order.id}) messages.success( request, "Thanks. We have refunded your item as requested and " "the customer will get an email notifying them of " "this. Please do remember that sellers must not have " "products published on Eco Market that are out of " "stock. Refunding products a lot will eventually " "negatively impact your ranking on our site so " "please try to avoid doing this too often (and only " "in cases where the customer needs to send the item " "back for " "some reason).") return HttpResponseRedirect(redirect_url)
def validate_email_resend_validation(request, force=False): profile = request.user.get_profile() if force or profile.activation_key_expired(): profile.generate_activation_key_and_save() Events(request).user_signup(request.user) return redirect("todos:validate_email_validation_sent")
def delete(self, request, cart=None, product=None): cart = cart or request.user.cart cart.remove_product(product) Events(self.request).cart_updated(cart) return self.render_to_response(self.request, {"message": "OK"})
def ipn_handler(request, payment_id, payment_secret_uuid): # have to grab this here because accessing the body property # after the POST variable is not allowed. But we need the raw # request for validting the IPN body = request.body logger.debug("raw post is: {0}".format(body)) logger.debug("IPN handler called, request data is " "{0}".format(request.POST)) if not client.validate_ipn(body): logger.debug("Message could not be validated") return HttpResponseBadRequest("Unable to validate ipn data") logger.debug("ipn data validated") parsed_data = client.parse_ipn(request.POST) logger.debug("IPN parsed") logger.debug("parsed_data is {0}".format(parsed_data)) payment = get_object_or_404(Payment, id=payment_id, secret_uuid=payment_secret_uuid) if parsed_data.get("reason_code", "not found").lower() == "refund": logger.debug("Refunding") try: if payment.order is not None and not payment.order.is_refunded(): payment.order.refund("refunded from outside of ecomarket", send_to_paypal=False) except Order.DoesNotExist: pass elif parsed_data.get("action_type", None).upper() == "PAY_PRIMARY": if parsed_data["status"] == "INCOMPLETE": logger.debug("Marking payment as PRIMARY_PAID") payment.payment_attempt.complete() payment = Payment.objects.get(id=payment.id) order = payment.order for line_item in order.line_items.all(): # Update number_of_sales line_item.product.number_of_sales += line_item.quantity line_item.product.save() share_orders = order.user.email_notification.share_orders_in_activity_feed if share_orders: action.send(order.user, verb='purchased product at', action_object=line_item.product, target=order) Events(request).order_placed(order) order_payed.send(sender=order, order=order, request=request) payment.status = Payment.STATUS_PRIMARY_PAID payment.save() elif parsed_data["status"] == "COMPLETED": logger.debug("marking payment as complete") payment.status = Payment.STATUS_COMPLETED payment.save() return HttpResponse("All ok")
def reply(request, message_id, form_class=ComposeForm, template_name='messaging/fragments/_modal_reply_form.html', success_url=None, recipient_filter=None, quote_helper=format_quote): """ Prepares the ``form_class`` form for writing a reply to a given message (specified via ``message_id``). Uses the ``format_quote`` helper from ``messages.utils`` to pre-format the quote. To change the quote format assign a different ``quote_helper`` kwarg in your url-conf. """ parent = get_object_or_404(Message, id=message_id) user = request.user if parent.sender != user and parent.recipient != user: raise Http404 if request.method == "POST": form = form_class(request.POST, recipient_filter=recipient_filter) if form.is_valid(): msg = form.save(sender=user, parent_msg=parent) Events(request).message_sent(msg) if request.GET.get('resolve') == '1': mark_action_thread(user, parent.thread, 'resolved') messages.success(request, _(u"Your message has been sent. Great job!")) if not request.is_ajax(): if success_url is None: success_url = reverse('messaging_inbox') return HttpResponseRedirect(success_url) else: thread = parent.thread thread_user_state = ThreadUserState.objects.get(thread=thread, user=user) thread_user_state.read_at = datetime.datetime.now() thread_user_state.save() recipient = parent.sender if recipient == user: # Find the real recipient. recipient = thread.messages.exclude(recipient=user)[0].recipient form = form_class( initial={ 'body': quote_helper(parent.sender, parent.body), 'subject': _(u"Re: %(subject)s") % { 'subject': parent.subject }, 'recipient': [recipient] }) return render_to_response( template_name, { 'form': form, 'message_id': message_id, 'subject': parent.subject, 'message_list': parent.thread.messages.all().order_by('sent_at'), 'message_to_reply': message_to_reply(parent.thread, user) }, context_instance=RequestContext(request))
def compose(request, recipient=None, form_class=ComposeForm, success_url=None, recipient_filter=None): """ Displays and handles the ``form_class`` form to compose new messages. Required Arguments: None Optional Arguments: ``recipient``: username of a `django.contrib.auth` User, who should receive the message, optionally multiple usernames could be separated by a '+' ``form_class``: the form-class to use ``template_name``: the template to use ``success_url``: where to redirect after successfull submission """ if not recipient_filter: recipient_filter = [request.user] form = form_class(request.POST or None, recipient_filter=recipient_filter) recipients = [] if request.method == "POST": if form.is_valid(): message = form.save(sender=request.user) Events(request).message_sent(message) if request.GET.get('product_to_be_delivered', None): country = Country.objects.get(code=request.country) product = Product.objects.get( pk=request.GET.get('product_to_be_delivered', None)) index = 1 cats = product.category_objs() i = 0 related_search_category = None for v in cats: if i == index: related_search_category = v i = i + 1 messages.success( request, _(u"Your message has been sent. Great job! \ In the mean time why don't you <a href=\"{url}\">check out these products</a> that do \ deliver to {country}".format( country=country.title, url=reverse('category_discover', args=(related_search_category.slug, ))))) else: messages.success(request, _(u"Your message has been sent. Great job!")) if not request.is_ajax(): success_url = request.GET.get('next', '') or \ reverse('messaging_inbox') return HttpResponseRedirect(success_url) else: if recipient is not None: # Todo: recipient can be email address too? recipients = [ u for u in User.objects.filter( username__in=[r.strip() for r in recipient.split('+')]) ] if len(recipients) > 1: form.recipient.error_messages[ 'recipient_error'] = "You must send a message to only one user." form.fields['recipient'].initial = recipients if request.GET.get('request_delivery_to_country', None): country = Country.objects.get(code=request.country) product = Product.objects.get( pk=request.GET.get('product_to_be_delivered', None)) form.fields[ 'subject'].initial = 'I would like to buy your product delivered to %s' % country.title form.fields['body'].initial = '''Hello {stall_owner}, I am trying to buy a {product}... however you don't have shipping rates set up for {country}. Could you please let me know if this is possible and update your \ shipping rates to include {country} if so, on Eco Market, so that \ I can purchase the above. \ You can see how to do this in the help center at \ http://help.ecomarket.com/customer/portal/articles/398297-how-to-create-and-apply-shipping-rates {customer}'''.format(stall_owner=str(product.stall.user).capitalize(), country=country.title, product=str(product.title).lower(), customer=str(request.user.first_name).capitalize()) if request.is_ajax(): product = None if request.GET.get('request_delivery_to_country', None): product = Product.objects.get( pk=request.GET.get('product_to_be_delivered', None)) template_name = 'messaging/fragments/_modal_compose_form.html' if product: return render_to_response(template_name, { 'form': form, 'product_to_be_delivered': product.id, }, context_instance=RequestContext(request)) else: return render_to_response(template_name, { 'form': form, }, context_instance=RequestContext(request)) template_name = 'messaging/compose.html' _recipient = None if recipient and recipients: _recipient = recipients[0].username return render_to_response(template_name, { 'form': form, 'recipient': _recipient }, context_instance=RequestContext(request))
def delete(self, request, cart_stall=None): cart_stall.delete() Events(request).cart_updated(cart_stall.cart) content = json.dumps(request.user.cart.to_json()) return HttpResponse(content, content_type="application/json")