import datetime import json as python_json import re import dateutil import requests import stripe from django.conf import settings from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth import login as login_user from django.contrib.auth import logout as logout_user from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.core.mail import mail_admins from django.db.models.aggregates import Sum from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render from django.urls import reverse from django.views.decorators.csrf import csrf_exempt, csrf_protect from django.views.decorators.http import require_POST from paypal.standard.forms import PayPalPaymentsForm from paypal.standard.ipn.views import ipn as paypal_standard_ipn from apps.analyzer.models import ( MClassifierAuthor, MClassifierFeed, MClassifierTag, MClassifierTitle, ) from apps.profile.forms import ( PLANS, AccountSettingsForm, DeleteAccountForm, ForgotPasswordForm, ForgotPasswordReturnForm, RedeemCodeForm, StripePlusPaymentForm, ) from apps.profile.models import ( MGiftCode, MRedeemedCode, PaymentHistory, PaypalIds, Profile, RNewUserQueue, ) from apps.reader.forms import LoginForm, SignupForm from apps.reader.models import RUserStory, UserSubscription, UserSubscriptionFolders from apps.rss_feeds.models import MStarredStory, MStarredStoryCounts from apps.social.models import MActivity, MSocialProfile, MSocialServices from utils import json_functions as json from utils import log as logging from utils.user_functions import ajax_login_required, get_user from utils.view_functions import is_true, render_to from vendor.paypalapi.exceptions import PayPalAPIResponseError INTEGER_FIELD_PREFS = ("feed_pane_size", "days_of_unread") SINGLE_FIELD_PREFS = ( "timezone", "hide_mobile", "send_emails", "hide_getting_started", "has_setup_feeds", "has_found_friends", "has_trained_intelligence", ) SPECIAL_PREFERENCES = ( "old_password", "new_password", "autofollow_friends", "dashboard_date", ) @ajax_login_required @require_POST @json.json_view def set_preference(request): code = 1 message = "" new_preferences = request.POST preferences = json.decode(request.user.profile.preferences) for preference_name, preference_value in list(new_preferences.items()): if preference_value in ["true", "false"]: preference_value = True if preference_value == "true" else False if preference_name in SINGLE_FIELD_PREFS: setattr(request.user.profile, preference_name, preference_value) elif preference_name in INTEGER_FIELD_PREFS: if ( preference_name == "days_of_unread" and int(preference_value) != request.user.profile.days_of_unread ): UserSubscription.all_subs_needs_unread_recalc(request.user.pk) setattr(request.user.profile, preference_name, int(preference_value)) if preference_name in preferences: del preferences[preference_name] elif preference_name in SPECIAL_PREFERENCES: if preference_name == "autofollow_friends": social_services = MSocialServices.get_user(request.user.pk) social_services.autofollow = preference_value social_services.save() elif preference_name == "dashboard_date": request.user.profile.dashboard_date = datetime.datetime.utcnow() else: if preference_value in ["true", "false"]: preference_value = True if preference_value == "true" else False preferences[preference_name] = preference_value if preference_name == "intro_page": logging.user(request, "~FBAdvancing intro to page ~FM~SB%s" % preference_value) request.user.profile.preferences = json.encode(preferences) request.user.profile.save() logging.user(request, "~FMSaving preference: %s" % new_preferences) response = dict(code=code, message=message, new_preferences=new_preferences) return response @ajax_login_required @json.json_view def get_preference(request): code = 1 preference_name = request.POST.get("preference") preferences = json.decode(request.user.profile.preferences) payload = preferences if preference_name: payload = preferences.get(preference_name) response = dict(code=code, payload=payload) return response @csrf_protect def login(request): form = LoginForm() if request.method == "POST": form = LoginForm(data=request.POST) if form.is_valid(): login_user(request, form.get_user(), backend="django.contrib.auth.backends.ModelBackend") logging.user(form.get_user(), "~FG~BBOAuth Login~FW") return HttpResponseRedirect(request.POST["next"] or reverse("index")) return render( request, "accounts/login.html", {"form": form, "next": request.POST.get("next", "") or request.GET.get("next", "")}, ) @csrf_exempt def signup(request): form = SignupForm(prefix="signup") recaptcha = request.POST.get("g-recaptcha-response", None) recaptcha_error = None if settings.ENFORCE_SIGNUP_CAPTCHA: if not recaptcha: recaptcha_error = 'Please hit the "I\'m not a robot" button.' else: response = requests.post( "https://www.google.com/recaptcha/api/siteverify", { "secret": settings.RECAPTCHA_SECRET_KEY, "response": recaptcha, }, ) result = response.json() if not result["success"]: recaptcha_error = 'Really, please hit the "I\'m not a robot" button.' if request.method == "POST": form = SignupForm(data=request.POST, prefix="signup") if form.is_valid() and not recaptcha_error: new_user = form.save() login_user(request, new_user, backend="django.contrib.auth.backends.ModelBackend") logging.user(new_user, "~FG~SB~BBNEW SIGNUP: ~FW%s" % new_user.email) new_user.profile.activate_free() return HttpResponseRedirect(request.POST["next"] or reverse("index")) return render( request, "accounts/signup.html", {"form": form, "recaptcha_error": recaptcha_error, "next": request.POST.get("next", "")}, ) @login_required @csrf_protect def redeem_code(request): code = request.GET.get("code", None) form = RedeemCodeForm(initial={"gift_code": code}) if request.method == "POST": form = RedeemCodeForm(data=request.POST) if form.is_valid(): gift_code = request.POST["gift_code"] MRedeemedCode.redeem(user=request.user, gift_code=gift_code) return render(request, "reader/paypal_return.xhtml") return render( request, "accounts/redeem_code.html", {"form": form, "code": request.POST.get("code", ""), "next": request.POST.get("next", "")}, ) @ajax_login_required @require_POST @json.json_view def set_account_settings(request): code = -1 message = "OK" form = AccountSettingsForm(user=request.user, data=request.POST) if form.is_valid(): form.save() code = 1 else: message = form.errors[list(form.errors.keys())[0]][0] payload = { "username": request.user.username, "email": request.user.email, "social_profile": MSocialProfile.profile(request.user.pk), } return dict(code=code, message=message, payload=payload) @ajax_login_required @require_POST @json.json_view def set_view_setting(request): code = 1 feed_id = request.POST["feed_id"] feed_view_setting = request.POST.get("feed_view_setting") feed_order_setting = request.POST.get("feed_order_setting") feed_read_filter_setting = request.POST.get("feed_read_filter_setting") feed_layout_setting = request.POST.get("feed_layout_setting") feed_dashboard_count_setting = request.POST.get("feed_dashboard_count_setting") view_settings = json.decode(request.user.profile.view_settings) setting = view_settings.get(feed_id, {}) if isinstance(setting, str): setting = {"v": setting} if feed_view_setting: setting["v"] = feed_view_setting if feed_order_setting: setting["o"] = feed_order_setting if feed_read_filter_setting: setting["r"] = feed_read_filter_setting if feed_dashboard_count_setting: setting["d"] = feed_dashboard_count_setting if feed_layout_setting: setting["l"] = feed_layout_setting view_settings[feed_id] = setting request.user.profile.view_settings = json.encode(view_settings) request.user.profile.save() logging.user( request, "~FMView settings: %s/%s/%s/%s" % (feed_view_setting, feed_order_setting, feed_read_filter_setting, feed_layout_setting), ) response = dict(code=code) return response @ajax_login_required @require_POST @json.json_view def clear_view_setting(request): code = 1 view_setting_type = request.POST.get("view_setting_type") view_settings = json.decode(request.user.profile.view_settings) new_view_settings = {} removed = 0 for feed_id, view_setting in list(view_settings.items()): if view_setting_type == "layout" and "l" in view_setting: del view_setting["l"] removed += 1 if view_setting_type == "view" and "v" in view_setting: del view_setting["v"] removed += 1 if view_setting_type == "order" and "o" in view_setting: del view_setting["o"] removed += 1 if view_setting_type == "order" and "r" in view_setting: del view_setting["r"] removed += 1 new_view_settings[feed_id] = view_setting request.user.profile.view_settings = json.encode(new_view_settings) request.user.profile.save() logging.user(request, "~FMClearing view settings: %s (found %s)" % (view_setting_type, removed)) response = dict(code=code, view_settings=view_settings, removed=removed) return response @ajax_login_required @json.json_view def get_view_setting(request): code = 1 feed_id = request.POST["feed_id"] view_settings = json.decode(request.user.profile.view_settings) response = dict(code=code, payload=view_settings.get(feed_id)) return response @ajax_login_required @require_POST @json.json_view def set_collapsed_folders(request): code = 1 collapsed_folders = request.POST["collapsed_folders"] request.user.profile.collapsed_folders = collapsed_folders request.user.profile.save() logging.user(request, "~FMCollapsing folder: %s" % collapsed_folders) response = dict(code=code) return response def paypal_ipn(request): try: return paypal_standard_ipn(request) except AssertionError: # Paypal may have sent webhooks to ipn, so redirect logging.user(request, f" ---> Paypal IPN to webhooks redirect: {request.body}") return paypal_webhooks(request) def paypal_webhooks(request): try: data = json.decode(request.body) except python_json.decoder.JSONDecodeError: # Kick it over to paypal ipn return paypal_standard_ipn(request) logging.user(request, f" ---> Paypal webhooks {data.get('event_type', '')} data: {data}") if data["event_type"] == "BILLING.SUBSCRIPTION.CREATED": # Don't start a subscription but save it in case the payment comes before the subscription activation user = User.objects.get(pk=int(data["resource"]["custom_id"])) user.profile.store_paypal_sub_id(data["resource"]["id"], skip_save_primary=True) elif data["event_type"] in ["BILLING.SUBSCRIPTION.ACTIVATED", "BILLING.SUBSCRIPTION.UPDATED"]: user = User.objects.get(pk=int(data["resource"]["custom_id"])) user.profile.store_paypal_sub_id(data["resource"]["id"]) # plan_id = data['resource']['plan_id'] # if plan_id == Profile.plan_to_paypal_plan_id('premium'): # user.profile.activate_premium() # elif plan_id == Profile.plan_to_paypal_plan_id('archive'): # user.profile.activate_archive() # elif plan_id == Profile.plan_to_paypal_plan_id('pro'): # user.profile.activate_pro() user.profile.cancel_premium_stripe() user.profile.setup_premium_history() if data["event_type"] == "BILLING.SUBSCRIPTION.ACTIVATED": user.profile.cancel_and_prorate_existing_paypal_subscriptions(data) elif data["event_type"] == "PAYMENT.SALE.COMPLETED": user = User.objects.get(pk=int(data["resource"]["custom"])) user.profile.setup_premium_history() elif data["event_type"] == "PAYMENT.CAPTURE.REFUNDED": user = User.objects.get(pk=int(data["resource"]["custom_id"])) user.profile.setup_premium_history() elif data["event_type"] in ["BILLING.SUBSCRIPTION.CANCELLED", "BILLING.SUBSCRIPTION.SUSPENDED"]: custom_id = data["resource"].get("custom_id", None) if custom_id: user = User.objects.get(pk=int(custom_id)) else: paypal_id = PaypalIds.objects.get(paypal_sub_id=data["resource"]["id"]) user = paypal_id.user user.profile.setup_premium_history() return HttpResponse("OK") def paypal_form(request): domain = Site.objects.get_current().domain if settings.DEBUG: domain = "73ee-71-233-245-159.ngrok.io" paypal_dict = { "cmd": "_xclick-subscriptions", "business": "samuel@ofbrooklyn.com", "a3": "12.00", # price "p3": 1, # duration of each unit (depends on unit) "t3": "Y", # duration unit ("M for Month") "src": "1", # make payments recur "sra": "1", # reattempt payment on payment error "no_note": "1", # remove extra notes (optional) "item_name": "NewsBlur Premium Account", "notify_url": "https://%s%s" % (domain, reverse("paypal-ipn")), "return_url": "https://%s%s" % (domain, reverse("paypal-return")), "cancel_return": "https://%s%s" % (domain, reverse("index")), "custom": request.user.username, } # Create the instance. form = PayPalPaymentsForm(initial=paypal_dict, button_type="subscribe") logging.user(request, "~FBLoading paypal/feedchooser") # Output the button. return HttpResponse(form.render(), content_type="text/html") @login_required def paypal_return(request): return render( request, "reader/paypal_return.xhtml", { "user_profile": request.user.profile, }, ) @login_required def paypal_archive_return(request): return render( request, "reader/paypal_archive_return.xhtml", { "user_profile": request.user.profile, }, ) @login_required def activate_premium(request): return HttpResponseRedirect(reverse("index")) @ajax_login_required @json.json_view def profile_is_premium(request): # Check tries code = 0 retries = int(request.GET["retries"]) subs = UserSubscription.objects.filter(user=request.user) total_subs = subs.count() activated_subs = subs.filter(active=True).count() if retries >= 30: code = -1 if not request.user.profile.is_premium: subject = "Premium activation failed: %s (%s/%s)" % (request.user, activated_subs, total_subs) message = """User: %s (%s) -- Email: %s""" % ( request.user.username, request.user.pk, request.user.email, ) mail_admins(subject, message) request.user.profile.activate_premium() profile = Profile.objects.get(user=request.user) return { "is_premium": profile.is_premium, "is_premium_archive": profile.is_archive, "code": code, "activated_subs": activated_subs, "total_subs": total_subs, } @ajax_login_required @json.json_view def profile_is_premium_archive(request): # Check tries code = 0 retries = int(request.GET["retries"]) subs = UserSubscription.objects.filter(user=request.user) total_subs = subs.count() activated_subs = subs.filter(feed__archive_subscribers__gte=1).count() if retries >= 30: code = -1 if not request.user.profile.is_premium_archive: subject = "Premium archive activation failed: %s (%s/%s)" % ( request.user, activated_subs, total_subs, ) message = """User: %s (%s) -- Email: %s""" % ( request.user.username, request.user.pk, request.user.email, ) mail_admins(subject, message) request.user.profile.activate_archive() profile = Profile.objects.get(user=request.user) return { "is_premium": profile.is_premium, "is_premium_archive": profile.is_archive, "code": code, "activated_subs": activated_subs, "total_subs": total_subs, } @ajax_login_required @json.json_view def save_ios_receipt(request): receipt = request.POST.get("receipt") product_identifier = request.POST.get("product_identifier") transaction_identifier = request.POST.get("transaction_identifier") logging.user(request, "~BM~FBSaving iOS Receipt: %s %s" % (product_identifier, transaction_identifier)) paid = request.user.profile.activate_ios_premium(transaction_identifier) if paid: logging.user( request, "~BM~FBSending iOS Receipt email: %s %s" % (product_identifier, transaction_identifier) ) subject = "iOS Premium: %s (%s)" % (request.user.profile, product_identifier) message = """User: %s (%s) -- Email: %s, product: %s, txn: %s, receipt: %s""" % ( request.user.username, request.user.pk, request.user.email, product_identifier, transaction_identifier, receipt, ) mail_admins(subject, message) else: logging.user( request, "~BM~FBNot sending iOS Receipt email, already paid: %s %s" % (product_identifier, transaction_identifier), ) return request.user.profile @ajax_login_required @json.json_view def save_android_receipt(request): order_id = request.POST.get("order_id") product_id = request.POST.get("product_id") logging.user(request, "~BM~FBSaving Android Receipt: %s %s" % (product_id, order_id)) paid = request.user.profile.activate_android_premium(order_id) if paid: logging.user(request, "~BM~FBSending Android Receipt email: %s %s" % (product_id, order_id)) subject = "Android Premium: %s (%s)" % (request.user.profile, product_id) message = """User: %s (%s) -- Email: %s, product: %s, order: %s""" % ( request.user.username, request.user.pk, request.user.email, product_id, order_id, ) mail_admins(subject, message) else: logging.user( request, "~BM~FBNot sending Android Receipt email, already paid: %s %s" % (product_id, order_id) ) return request.user.profile @login_required def stripe_form(request): user = request.user success_updating = False stripe.api_key = settings.STRIPE_SECRET plan = PLANS[0][0] renew = is_true(request.GET.get("renew", False)) error = None if request.method == "POST": zebra_form = StripePlusPaymentForm(request.POST, email=user.email) if zebra_form.is_valid(): user.email = zebra_form.cleaned_data["email"] user.save() customer = None current_premium = ( user.profile.is_premium and user.profile.premium_expire and user.profile.premium_expire > datetime.datetime.now() ) # Are they changing their existing card? if user.profile.stripe_id: customer = stripe.Customer.retrieve(user.profile.stripe_id) try: card = customer.sources.create(source=zebra_form.cleaned_data["stripe_token"]) except stripe.error.CardError: error = "This card was declined." else: customer.default_card = card.id customer.save() user.profile.strip_4_digits = zebra_form.cleaned_data["last_4_digits"] user.profile.save() user.profile.activate_premium() # TODO: Remove, because webhooks are slow success_updating = True else: try: customer = stripe.Customer.create( **{ "source": zebra_form.cleaned_data["stripe_token"], "plan": zebra_form.cleaned_data["plan"], "email": user.email, "description": user.username, } ) except stripe.error.CardError: error = "This card was declined." else: user.profile.strip_4_digits = zebra_form.cleaned_data["last_4_digits"] user.profile.stripe_id = customer.id user.profile.save() user.profile.activate_premium() # TODO: Remove, because webhooks are slow success_updating = True # Check subscription to ensure latest plan, otherwise cancel it and subscribe if success_updating and customer and customer.subscriptions.total_count == 1: subscription = customer.subscriptions.data[0] if subscription["plan"]["id"] != "newsblur-premium-36": for sub in customer.subscriptions: sub.delete() customer = stripe.Customer.retrieve(user.profile.stripe_id) if success_updating and customer and customer.subscriptions.total_count == 0: params = dict( customer=customer.id, items=[ { "plan": "newsblur-premium-36", }, ], ) premium_expire = user.profile.premium_expire if current_premium and premium_expire: if premium_expire < (datetime.datetime.now() + datetime.timedelta(days=365)): params["billing_cycle_anchor"] = premium_expire.strftime("%s") params["trial_end"] = premium_expire.strftime("%s") stripe.Subscription.create(**params) else: zebra_form = StripePlusPaymentForm(email=user.email, plan=plan) if success_updating: return render(request, "reader/paypal_return.xhtml") new_user_queue_count = RNewUserQueue.user_count() new_user_queue_position = RNewUserQueue.user_position(request.user.pk) new_user_queue_behind = 0 if new_user_queue_position >= 0: new_user_queue_behind = new_user_queue_count - new_user_queue_position new_user_queue_position -= 1 immediate_charge = True if user.profile.premium_expire and user.profile.premium_expire > datetime.datetime.now(): immediate_charge = False logging.user(request, "~BM~FBLoading Stripe form") return render( request, "profile/stripe_form.xhtml", { "zebra_form": zebra_form, "publishable": settings.STRIPE_PUBLISHABLE, "success_updating": success_updating, "new_user_queue_count": new_user_queue_count - 1, "new_user_queue_position": new_user_queue_position, "new_user_queue_behind": new_user_queue_behind, "renew": renew, "immediate_charge": immediate_charge, "error": error, }, ) @login_required def switch_stripe_subscription(request): plan = request.POST["plan"] if plan == "change_stripe": return stripe_checkout(request) elif plan == "change_paypal": paypal_url = request.user.profile.paypal_change_billing_details_url() return HttpResponseRedirect(paypal_url) switch_successful = request.user.profile.switch_stripe_subscription(plan) logging.user( request, "~FCSwitching subscription to ~SB%s~SN~FC (%s)" % (plan, "~FGsucceeded~FC" if switch_successful else "~FRfailed~FC"), ) if switch_successful: return HttpResponseRedirect(reverse("stripe-return")) return stripe_checkout(request) def switch_paypal_subscription(request): plan = request.POST["plan"] if plan == "change_stripe": return stripe_checkout(request) elif plan == "change_paypal": paypal_url = request.user.profile.paypal_change_billing_details_url() return HttpResponseRedirect(paypal_url) approve_url = request.user.profile.switch_paypal_subscription_approval_url(plan) logging.user( request, "~FCSwitching subscription to ~SB%s~SN~FC (%s)" % (plan, "~FGsucceeded~FC" if approve_url else "~FRfailed~FC"), ) if approve_url: return HttpResponseRedirect(approve_url) paypal_return = reverse("paypal-return") if plan == "archive": paypal_return = reverse("paypal-archive-return") return HttpResponseRedirect(paypal_return) @login_required def stripe_checkout(request): stripe.api_key = settings.STRIPE_SECRET domain = Site.objects.get_current().domain plan = request.POST["plan"] if plan == "change_stripe": checkout_session = stripe.billing_portal.Session.create( customer=request.user.profile.stripe_id, return_url="http://%s%s?next=payments" % (domain, reverse("index")), ) return HttpResponseRedirect(checkout_session.url, status=303) price = Profile.plan_to_stripe_price(plan) session_dict = { "line_items": [ { "price": price, "quantity": 1, }, ], "mode": "subscription", "metadata": {"newsblur_user_id": request.user.pk}, "success_url": "http://%s%s" % (domain, reverse("stripe-return")), "cancel_url": "http://%s%s" % (domain, reverse("index")), } if request.user.profile.stripe_id: session_dict["customer"] = request.user.profile.stripe_id else: session_dict["customer_email"] = request.user.email checkout_session = stripe.checkout.Session.create(**session_dict) logging.user(request, "~BM~FBLoading Stripe checkout") return HttpResponseRedirect(checkout_session.url, status=303) @render_to("reader/activities_module.xhtml") def load_activities(request): user = get_user(request) page = max(1, int(request.GET.get("page", 1))) activities, has_next_page = MActivity.user(user.pk, page=page) return { "activities": activities, "page": page, "has_next_page": has_next_page, "username": "You", } @ajax_login_required @json.json_view def payment_history(request): user = request.user if request.user.is_staff: user_id = request.GET.get("user_id", request.user.pk) user = User.objects.get(pk=user_id) history = PaymentHistory.objects.filter(user=user) statistics = { "created_date": user.date_joined, "last_seen_date": user.profile.last_seen_on, "last_seen_ip": user.profile.last_seen_ip, "timezone": str(user.profile.timezone), "stripe_id": user.profile.stripe_id, "paypal_email": user.profile.latest_paypal_email, "profile": user.profile, "feeds": UserSubscription.objects.filter(user=user).count(), "email": user.email, "read_story_count": RUserStory.read_story_count(user.pk), "feed_opens": UserSubscription.objects.filter(user=user).aggregate(sum=Sum("feed_opens"))["sum"], "training": { "title_ps": MClassifierTitle.objects.filter(user_id=user.pk, score__gt=0).count(), "title_ng": MClassifierTitle.objects.filter(user_id=user.pk, score__lt=0).count(), "tag_ps": MClassifierTag.objects.filter(user_id=user.pk, score__gt=0).count(), "tag_ng": MClassifierTag.objects.filter(user_id=user.pk, score__lt=0).count(), "author_ps": MClassifierAuthor.objects.filter(user_id=user.pk, score__gt=0).count(), "author_ng": MClassifierAuthor.objects.filter(user_id=user.pk, score__lt=0).count(), "feed_ps": MClassifierFeed.objects.filter(user_id=user.pk, score__gt=0).count(), "feed_ng": MClassifierFeed.objects.filter(user_id=user.pk, score__lt=0).count(), }, } next_invoice = None stripe_customer = user.profile.stripe_customer() paypal_api = user.profile.paypal_api() if stripe_customer: try: invoice = stripe.Invoice.upcoming(customer=stripe_customer.id) for lines in invoice.lines.data: next_invoice = dict( payment_date=datetime.datetime.fromtimestamp(lines.period.start), payment_amount=invoice.amount_due / 100.0, payment_provider="(scheduled)", scheduled=True, ) break except stripe.error.InvalidRequestError: pass if paypal_api and not next_invoice and user.profile.premium_renewal and len(history): next_invoice = dict( payment_date=history[0].payment_date + dateutil.relativedelta.relativedelta(years=1), payment_amount=history[0].payment_amount, payment_provider="(scheduled)", scheduled=True, ) return { "is_premium": user.profile.is_premium, "is_archive": user.profile.is_archive, "is_pro": user.profile.is_pro, "premium_expire": user.profile.premium_expire, "premium_renewal": user.profile.premium_renewal, "active_provider": user.profile.active_provider, "payments": history, "statistics": statistics, "next_invoice": next_invoice, } @ajax_login_required @json.json_view def cancel_premium(request): canceled = request.user.profile.cancel_premium() return { "code": 1 if canceled else -1, } @staff_member_required @ajax_login_required @json.json_view def refund_premium(request): user_id = request.POST.get("user_id") partial = request.POST.get("partial", False) provider = request.POST.get("provider", None) user = User.objects.get(pk=user_id) try: refunded = user.profile.refund_premium(partial=partial, provider=provider) except stripe.error.InvalidRequestError as e: refunded = e except PayPalAPIResponseError as e: refunded = e return {"code": 1 if type(refunded) == int else -1, "refunded": refunded} @staff_member_required @ajax_login_required @json.json_view def upgrade_premium(request): user_id = request.POST.get("user_id") user = User.objects.get(pk=user_id) gift = MGiftCode.add(gifting_user_id=User.objects.get(username="samuel").pk, receiving_user_id=user.pk) MRedeemedCode.redeem(user, gift.gift_code) return {"code": user.profile.is_premium} @staff_member_required @ajax_login_required @json.json_view def never_expire_premium(request): user_id = request.POST.get("user_id") years = int(request.POST.get("years", 0)) user = User.objects.get(pk=user_id) if user.profile.is_premium: if years: user.profile.premium_expire = datetime.datetime.now() + datetime.timedelta(days=365 * years) else: user.profile.premium_expire = None user.profile.save() return {"code": 1} return {"code": -1} @staff_member_required @ajax_login_required @json.json_view def update_payment_history(request): user_id = request.POST.get("user_id") user = User.objects.get(pk=user_id) user.profile.setup_premium_history(set_premium_expire=False) return {"code": 1} @login_required @render_to("profile/delete_account.xhtml") def delete_account(request): if request.method == "POST": form = DeleteAccountForm(request.POST, user=request.user) if form.is_valid(): logging.user(request.user, "~SK~BC~FRDeleting ~SB%s~SN's account." % request.user.username) request.user.profile.delete_user(confirm=True) logout_user(request) return HttpResponseRedirect(reverse("index")) else: logging.user( request.user, "~BC~FRFailed attempt to delete ~SB%s~SN's account." % request.user.username ) else: logging.user(request.user, "~BC~FRAttempting to delete ~SB%s~SN's account." % request.user.username) form = DeleteAccountForm(user=request.user) return { "delete_form": form, } @render_to("profile/forgot_password.xhtml") def forgot_password(request): if request.method == "POST": form = ForgotPasswordForm(request.POST) if form.is_valid(): logging.user(request.user, "~BC~FRForgot password: ~SB%s" % request.POST["email"]) try: user = User.objects.get(email__iexact=request.POST["email"]) except User.MultipleObjectsReturned: user = User.objects.filter(email__iexact=request.POST["email"])[0] user.profile.send_forgot_password_email() return HttpResponseRedirect(reverse("index")) else: logging.user(request.user, "~BC~FRFailed forgot password: ~SB%s~SN" % request.POST["email"]) else: logging.user(request.user, "~BC~FRAttempting to retrieve forgotton password.") form = ForgotPasswordForm() return { "forgot_password_form": form, } @login_required @render_to("profile/forgot_password_return.xhtml") def forgot_password_return(request): if request.method == "POST": logging.user(request.user, "~BC~FRReseting ~SB%s~SN's password." % request.user.username) new_password = request.POST.get("password", "") request.user.set_password(new_password) request.user.save() return HttpResponseRedirect(reverse("index")) else: logging.user(request.user, "~BC~FRAttempting to reset ~SB%s~SN's password." % request.user.username) form = ForgotPasswordReturnForm() return { "forgot_password_return_form": form, } @ajax_login_required @json.json_view def delete_starred_stories(request): timestamp = request.POST.get("timestamp", None) if timestamp: delete_date = datetime.datetime.fromtimestamp(int(timestamp)) else: delete_date = datetime.datetime.now() starred_stories = MStarredStory.objects.filter(user_id=request.user.pk, starred_date__lte=delete_date) stories_deleted = starred_stories.count() starred_stories.delete() MStarredStoryCounts.count_for_user(request.user.pk, total_only=True) starred_counts, starred_count = MStarredStoryCounts.user_counts(request.user.pk, include_total=True) logging.user( request.user, "~BC~FRDeleting %s/%s starred stories (%s)" % (stories_deleted, stories_deleted + starred_count, delete_date), ) return dict( code=1, stories_deleted=stories_deleted, starred_counts=starred_counts, starred_count=starred_count ) @ajax_login_required @json.json_view def delete_all_sites(request): request.user.profile.send_opml_export_email( reason="You have deleted all of your sites, so here's a backup of all of your subscriptions just in case." ) subs = UserSubscription.objects.filter(user=request.user) sub_count = subs.count() subs.delete() usf = UserSubscriptionFolders.objects.get(user=request.user) usf.folders = "[]" usf.save() logging.user(request.user, "~BC~FRDeleting %s sites" % sub_count) return dict(code=1) @login_required @render_to("profile/email_optout.xhtml") def email_optout(request): user = request.user user.profile.send_emails = False user.profile.save() return { "user": user, } @json.json_view def ios_subscription_status(request): logging.debug(" ---> iOS Subscription Status: %s" % request.body) data = json.decode(request.body) subject = "iOS Subscription Status: %s" % data.get("notification_type", "[missing]") message = """%s""" % (request.body) mail_admins(subject, message) return {"code": 1} def trigger_error(request): logging.user(request.user, "~BR~FW~SBTriggering divison by zero") division_by_zero = 1 / 0 return HttpResponseRedirect(reverse("index"))