def form_valid(self, form): """Create the request""" if self.request.user.is_authenticated: user = self.request.user else: try: user = self._handle_anonymous_submitter(form) except requests.exceptions.RequestException: return self.form_invalid(form) if form.cleaned_data["action"] in ("save", "submit"): composer = form.save() # if a new agency is added while the user is anonymous, # we want to associate that agency to the user once they # login or register composer.agencies.filter(user=None, status="pending").update(user=user) if form.cleaned_data["action"] == "save": self.request.session["ga"] = "request_drafted" mixpanel_event( self.request, "Request Saved", self._composer_mixpanel_properties(composer), ) messages.success(self.request, "Request saved") elif form.cleaned_data["action"] == "submit": self._submit_composer(composer, form) return redirect(composer)
def form_valid(self, form): """Saves relationship and sends action before returning URL""" redirection = super(ProjectCrowdfundView, self).form_valid(form) crowdfund = self.object project = self.get_project() relationship = ProjectCrowdfunds.objects.create( project=project, crowdfund=crowdfund ) new_action( self.request.user, "began crowdfunding", action_object=relationship.crowdfund, target=relationship.project, ) crowdfund.send_intro_email(self.request.user) mixpanel_event( self.request, "Launch Project Crowdfund", self._project_mixpanel_properties( project, { "Name": crowdfund.name, "Payment Capped": crowdfund.payment_capped, "Payment Required": float(crowdfund.payment_required), "Date Due": crowdfund.date_due.isoformat(), }, ), ) return redirection
def _handle_anonymous_submitter(self, form): """Handle a submission from an anonymous user""" # form validation guarentees we have either registration or login info if form.cleaned_data.get('register_full_name'): user = self.miniregister( form.cleaned_data['register_full_name'], form.cleaned_data['register_email'], form.cleaned_data.get('register_newsletter'), ) if form.cleaned_data.get('register_pro'): try: user.profile.start_pro_subscription( form.cleaned_data.get('stripe_token'), ) except StripeError: messages.error( self.request, 'There was an error processing your ' 'payment. Your account has been created, but you ' 'have not been subscribed to a professional account. ' 'You can subscribe from the settings page.') else: mixpanel_event(self.request, 'Pro Subscription Started') return user else: login(self.request, form.user) return form.user
def follow(request, jurisdiction, jidx, slug, idx): """Follow or unfollow a request""" foia = get_object_or_404( FOIARequest, agency__jurisdiction__slug=jurisdiction, agency__jurisdiction__pk=jidx, slug=slug, pk=idx, ) if actstream.actions.is_following(request.user, foia): actstream.actions.unfollow(request.user, foia) messages.success(request, 'You are no longer following this request.') mixpanel_event( request, 'Unfollow', foia.mixpanel_data(), ) else: actstream.actions.follow(request.user, foia, actor_only=False) messages.success(request, 'You are now following this request.') mixpanel_event( request, 'Follow', foia.mixpanel_data(), ) return redirect(foia)
def _handle_cancel_payments(self, attr, arg): """Handle cancelling recurring donations or crowdfunds""" payments = ( getattr(self.request.user, attr) .filter(pk__in=self.request.POST.getlist(arg)) ) attr_type = { 'donations': 'Donation', 'recurring_crowdfund_payments': 'Recurring Crowdfund', } for payment in payments: payment.cancel() mixpanel_event( self.request, 'Cancel {}'.format(attr_type[attr]), {'Amount': payment.amount}, ) msg = attr.replace('_', ' ') if payments: messages.success( self.request, 'The selected {} have been cancelled.'.format(msg), ) else: messages.warning( self.request, 'No {} were selected to be cancelled.'.format(msg), )
def form_valid(self, form): """Create the request""" if self.request.user.is_authenticated: user = self.request.user else: user = self._handle_anonymous_submitter(form) if form.cleaned_data['action'] in ('save', 'submit'): composer = form.save(commit=False) composer.user = user composer.save() form.save_m2m() # if a new agency is added while the user is anonymous, # we want to associate that agency to the user once they # login or register composer.agencies.filter(user=None, status='pending').update(user=user) if form.cleaned_data['action'] == 'save': self.request.session['ga'] = 'request_drafted' mixpanel_event( self.request, 'Request Saved', self._composer_mixpanel_properties(composer), ) messages.success(self.request, 'Request saved') elif form.cleaned_data['action'] == 'submit': self._submit_composer(composer, form) return redirect(composer)
def form_valid(self, form): """When form is valid, create the user and begin their professional subscription.""" new_user = create_new_user(self.request, form) welcome.delay(new_user) try: new_user.profile.start_pro_subscription( self.request.POST['stripe_token']) success_msg = 'Your professional account was successfully created. Welcome to MuckRock!' messages.success(self.request, success_msg) mixpanel_event( self.request, 'Pro Subscription Started', ) except (KeyError, AttributeError): # no payment information provided logger.warn('No payment information provided.') error_msg = ('Your account was successfully created, ' 'but you did not provide payment information. ' 'You can subscribe from the account management page.') messages.error(self.request, error_msg) except stripe.error.CardError: # card declined logger.warn('Card was declined.') error_msg = ( 'Your account was successfully created, but your card was declined. ' 'You can subscribe from the account management page.') messages.error(self.request, error_msg) except (stripe.error.InvalidRequestError, stripe.error.APIError): # invalid request made to stripe logger.warn('No payment information provided.') error_msg = ('Your account was successfully created, ' 'but we could not contact our payment provider. ' 'You can subscribe from the account management page.') messages.error(self.request, error_msg) return super(ProfessionalSignupView, self).form_valid(form)
def _user_follow_up(self, request, foia): """Handle follow ups for non-admins""" has_perm = foia.has_perm(request.user, 'followup') contact_info_form = ContactInfoForm(request.POST, foia=foia, prefix='followup') has_contact_perm = request.user.has_perm('foia.set_info_foiarequest') contact_valid = contact_info_form.is_valid() use_contact_info = ( has_contact_perm and contact_info_form.cleaned_data.get('use_contact_information')) comm_sent = self._new_comm( request, foia, has_perm and (not use_contact_info or contact_valid), 'Your follow up has been sent.', contact_info=contact_info_form.cleaned_data if use_contact_info else None, ) if use_contact_info: foia.add_contact_info_note( request.user, contact_info_form.cleaned_data, ) if comm_sent: new_action(request.user, 'followed up on', target=foia) mixpanel_event( request, 'Follow Up', foia.mixpanel_data({ 'Use Contact Info': use_contact_info, }), ) return redirect(foia.get_absolute_url() + '#')
def _submit_composer(self, composer, form): """Submit a composer""" # pylint: disable=not-an-iterable if form.cleaned_data.get('num_requests', 0) > 0: self.buy_requests(form) if (form.cleaned_data.get('use_contact_information') and self.request.user.profile.is_advanced() and len(composer.agencies.all()) == 1): contact_info = { k: form.cleaned_data.get(k) for k in ContactInfoForm.base_fields } else: contact_info = None try: composer.submit(contact_info) except InsufficientRequestsError: messages.warning(self.request, 'You need to purchase more requests') else: messages.success(self.request, 'Request submitted') self.request.session['ga'] = 'request_submitted' mixpanel_event( self.request, 'Request Submitted', self._composer_mixpanel_properties(composer), ) warning = self._proxy_warnings(composer) if warning: messages.warning(self.request, warning)
def miniregister(self, form, full_name, email, newsletter=False): """Create a new user from their full name and email""" full_name = full_name.strip() user_json = self._create_squarelet_user(form, { "name": full_name, "preferred_username": full_name, "email": email }) user, _ = Profile.objects.squarelet_update_or_create( user_json["uuid"], user_json) login(self.request, user, backend="muckrock.accounts.backends.SquareletBackend") if newsletter: mailchimp_subscribe( self.request, user.email, source="Mini-Register: {}".format(self.minireg_source), url="{}{}".format(settings.MUCKROCK_URL, self.request.path), ) mixpanel_event( self.request, "Sign Up", { "Source": "Mini-Register: {}".format(self.minireg_source), "Newsletter": newsletter, }, signup=True, ) return user
def _user_follow_up(request, foia): """Handle follow ups for non-admins""" has_perm = foia.has_perm(request.user, "followup") contact_info_form = ContactInfoForm(request.POST, foia=foia, prefix="followup") has_contact_perm = request.user.has_perm("foia.set_info_foiarequest") contact_valid = contact_info_form.is_valid() use_contact_info = has_contact_perm and contact_info_form.cleaned_data.get( "use_contact_information" ) comm_sent = _new_comm( request, foia, has_perm and (not use_contact_info or contact_valid), "Your follow up has been sent.", contact_info=contact_info_form.cleaned_data if use_contact_info else None, ) if use_contact_info: foia.add_contact_info_note(request.user, contact_info_form.cleaned_data) if comm_sent: new_action(request.user, "followed up on", target=foia) mixpanel_event( request, "Follow Up", foia.mixpanel_data({"Use Contact Info": use_contact_info}), ) return _get_redirect(request, foia)
def get(self, request, *args, **kwargs): response = super(ProjectCrowdfundView, self).get(request, *args, **kwargs) mixpanel_event( request, "Start Project Crowdfund", self._project_mixpanel_properties(self.get_project()), ) return response
def post(self, request, **kwargs): """ First we validate the payment form, so we don't charge someone's card by accident. Next, we charge their card. Finally, use the validated payment form to create and return a CrowdfundRequestPayment object. """ # pylint: disable=too-many-locals token = request.POST.get('stripe_token') email = request.POST.get('stripe_email') email = validate_stripe_email(email) payment_form = CrowdfundPaymentForm(request.POST) if payment_form.is_valid() and token and email: amount = payment_form.cleaned_data['stripe_amount'] # If there is no user but the show and full_name fields are filled in, # and a user with that email does not already exists, # create the user with our "miniregistration" functionality and then log them in user = request.user if request.user.is_authenticated else None registered = False show = payment_form.cleaned_data['show'] full_name = payment_form.cleaned_data['full_name'] email_exists = User.objects.filter(email__iexact=email).exists() if user is None and show and full_name and not email_exists: user = self.miniregister(full_name, email) registered = True crowdfund = payment_form.cleaned_data['crowdfund'] try: if (crowdfund.can_recur() and payment_form.cleaned_data['recurring']): crowdfund.make_recurring_payment(token, email, amount, show, user) event = 'Recurring Crowdfund Payment' kwargs = {} else: crowdfund.make_payment(token, email, amount, show, user) event = 'Crowdfund Payment' kwargs = {'charge': float(amount)} except stripe.StripeError as payment_error: logging.warn(payment_error) return self.return_error(request, payment_error) else: mixpanel_event( request, event, { 'Amount': float(amount), 'Crowdfund': crowdfund.name, 'Crowdfund ID': crowdfund.pk, 'Show': show, }, **kwargs) if request.is_ajax(): data = { 'authenticated': user.is_authenticated() if user else False, 'registered': registered, } return JsonResponse(data, status=200) else: messages.success(request, 'Thank you for your contribution!') return redirect(self.get_redirect_url()) return self.return_error(request)
def downgrade(request): """Downgrades the user from a Professional to a Basic account.""" if not request.user.is_authenticated(): raise AttributeError('Cannot downgrade an anonymous user.') if request.user.profile.acct_type != 'pro': raise ValueError( 'Cannot downgrade this account, it is not Professional.') request.user.profile.cancel_pro_subscription() mixpanel_event(request, 'Pro Subscription Cancelled')
def crowdfund_request(request, idx, **kwargs): """Crowdfund a request""" # pylint: disable=unused-argument # select for update locks this request in order to prevent a race condition # allowing multiple crowdfunds to be created for it foia = get_object_or_404( FOIARequest.objects.select_for_update().select_related( "agency__jurisdiction", "composer" ), pk=idx, ) # check for unauthorized access if not foia.has_perm(request.user, "crowdfund"): messages.error(request, "You may not crowdfund this request.") return redirect(foia) if request.method == "POST": # save crowdfund object form = CrowdfundForm(request.POST) if form.is_valid(): crowdfund = form.save() foia.crowdfund = crowdfund foia.save(comment="added a crowdfund") messages.success(request, "Your crowdfund has started, spread the word!") new_action( request.user, "began crowdfunding", action_object=crowdfund, target=foia ) crowdfund.send_intro_email(request.user) mixpanel_event( request, "Launch Request Crowdfund", foia.mixpanel_data( { "Name": crowdfund.name, "Payment Capped": crowdfund.payment_capped, "Payment Required": float(crowdfund.payment_required), "Date Due": crowdfund.date_due.isoformat(), } ), ) return redirect(foia) elif request.method == "GET": # create crowdfund form default_crowdfund_duration = 30 date_due = timezone.now() + timedelta(default_crowdfund_duration) initial = { "name": "Crowdfund Request: %s" % str(foia), "description": "Help cover the request fees needed to free these docs!", "payment_required": foia.get_stripe_amount(), "date_due": date_due, "foia": foia, } form = CrowdfundForm(initial=initial) mixpanel_event(request, "Start Request Crowdfund", foia.mixpanel_data()) return render(request, "forms/foia/crowdfund.html", {"form": form})
def post(self, request, *args, **kwargs): """Check for cancel pro before checking form""" if (request.user.is_staff and request.POST.get('action') == 'cancel-pro'): self.user.profile.cancel_pro_subscription() mixpanel_event(request, 'Pro Subscription Cancelled') messages.success(request, 'Pro account has been cancelled') return redirect('acct-profile', username=self.user.username) else: return super(ProfileView, self).post(request, *args, **kwargs)
def buy_requests(self, form, organization=None, payer=None): """Buy requests""" if 'organization' in form.cleaned_data: organization = payer = form.cleaned_data['organization'] try: num_requests = form.cleaned_data['num_requests'] price = self.get_price(num_requests) payer.pay( amount=price, description='Purchase {} requests'.format(num_requests), token=form.cleaned_data['stripe_token'], save_card=form.cleaned_data['save_card'], ) organization.add_requests(num_requests) except requests.exceptions.RequestException as exc: logger.warn('Payment error: %s', exc, exc_info=sys.exc_info()) if exc.response.status_code / 100 == 4: messages.error( self.request, 'Payment Error: {}'.format( '\n'.join( '{}: {}'.format(k, v) for k, v in exc.response.json().iteritems() ) ) ) else: messages.error(self.request, 'Payment Error') return self.request.session['ga'] = 'request_purchase' mixpanel_event( self.request, 'Requests Purchased', { 'Number': num_requests, 'Recipient': organization.name, 'Price': price / 100, }, charge=price / 100, ) if organization.individual: msg = ( 'Purchase successful. {} requests have been added to your ' 'account.'.format(num_requests) ) else: msg = ( 'Purchase successful. {} requests have been added to ' '{}\'s account.'.format(num_requests, organization.name) ) messages.success(self.request, msg)
def form_valid(self, form): """Save the form results""" crowdsource = self.get_object() has_data = crowdsource.data.exists() if self.request.user.is_authenticated: user = self.request.user else: user = self.miniregister( form.cleaned_data['full_name'], form.cleaned_data['email'], form.cleaned_data.get('newsletter'), ) number = ( self.object.responses.filter(user=user, data=self.data).count() + 1) if not has_data or self.data is not None: response = CrowdsourceResponse.objects.create( crowdsource=crowdsource, user=user, data=self.data, number=number, ) response.create_values(form.cleaned_data) messages.success(self.request, 'Thank you!') properties = { 'Crowdsource': crowdsource.title, 'Crowdsource ID': crowdsource.pk, 'Number': number, } if self.data: properties['Data'] = self.data.url mixpanel_event( self.request, 'Assignment Completed', properties, ) for email in crowdsource.submission_emails.all(): response.send_email(email.email) if self.request.POST['submit'] == 'Submit and Add Another': return self.render_to_response( self.get_context_data(data=self.data), ) if has_data: return redirect( 'crowdsource-assignment', slug=crowdsource.slug, idx=crowdsource.pk, ) else: return redirect('crowdsource-list')
def form_valid(self, form): """Update the request""" if form.cleaned_data['action'] == 'save': composer = form.save() self.request.session['ga'] = 'request_drafted' mixpanel_event( self.request, 'Request Saved', self._composer_mixpanel_properties(composer), ) messages.success(self.request, 'Request saved') elif form.cleaned_data['action'] == 'submit': composer = form.save() self._submit_composer(composer, form) return redirect(composer)
def form_valid(self, form): """Should handle a valid form differently depending on whether the user is staff.""" organization = self.get_object() user = self.request.user max_users = form.cleaned_data['max_users'] if user.is_staff: # if staff we want the changes made to the org to be saved before updating organization = form.save() organization.update_subscription(max_users) mixpanel_event( self.request, 'Organization Updated', organization.mixpanel_event(), ) return redirect(self.get_success_url())
def form_valid(self, form): """Update the request""" if form.cleaned_data["action"] == "save": composer = form.save() self.request.session["ga"] = "request_drafted" mixpanel_event( self.request, "Request Saved", self._composer_mixpanel_properties(composer), ) messages.success(self.request, "Request saved") elif form.cleaned_data["action"] == "submit": composer = form.save() self._submit_composer(composer, form) return redirect(composer)
def create_new_user(request, valid_form): """Create a user from the valid form, give them a profile, and log them in.""" new_user = valid_form.save() Profile.objects.create(user=new_user, acct_type='basic', monthly_requests=0, date_update=date.today()) new_user = authenticate(username=valid_form.cleaned_data['username'], password=valid_form.cleaned_data['password1']) login(request, new_user) mixpanel_event( request, 'Sign Up', {'Source': 'Sign Up Page'}, signup=True, ) return new_user
def make_charge(self, token, amount, email): """Make a Stripe charge and catch any errors.""" charge = None error_msg = None try: charge = stripe_retry_on_error( stripe.Charge.create, amount=amount, currency='usd', source=token, description='Donation from %s' % email, metadata={'email': email, 'action': 'donation'}, idempotency_key=True, ) except stripe.error.CardError: # card declined logger.warn('Card was declined.') error_msg = 'Your card was declined' except ( stripe.error.InvalidRequestError, # Invalid parameters were supplied to Stripe's API stripe.error.AuthenticationError, # Authentication with Stripe's API failed stripe.error.APIConnectionError, # Network communication with Stripe failed stripe.error.StripeError, # Generic error ) as exception: logger.error(exception, exc_info=sys.exc_info()) error_msg = ( 'Oops, something went wrong on our end.' ' Sorry about that!' ) finally: if error_msg: messages.error(self.request, error_msg) else: self.request.session['donated'] = amount self.request.session['ga'] = 'donation' mixpanel_event( self.request, 'Donate', {'Amount': amount / 100}, charge=amount / 100, ) return charge
def buy_requests(self, form, organization=None, payer=None): """Buy requests""" if "organization" in form.cleaned_data: organization = payer = form.cleaned_data["organization"] try: num_requests = form.cleaned_data["num_requests"] price = self.get_price(num_requests) payer.pay( amount=price, description="Purchase {} requests".format(num_requests), token=form.cleaned_data["stripe_token"], save_card=form.cleaned_data["save_card"], ) organization.add_requests(num_requests) except requests.exceptions.RequestException as exc: logger.warning("Payment error: %s", exc, exc_info=sys.exc_info()) if exc.response.status_code // 100 == 4: messages.error( self.request, "Payment Error: {}".format("\n".join( "{}: {}".format(k, v) for k, v in exc.response.json().items())), ) else: messages.error(self.request, "Payment Error") return self.request.session["ga"] = "request_purchase" mixpanel_event( self.request, "Requests Purchased", { "Number": num_requests, "Recipient": organization.name, "Price": price / 100, }, charge=price / 100, ) if organization.individual: msg = ("Purchase successful. {} requests have been added to your " "account.".format(num_requests)) else: msg = ("Purchase successful. {} requests have been added to " "{}'s account.".format(num_requests, organization.name)) messages.success(self.request, msg)
def form_valid(self, form): """ When form is valid, create the user and the organization. Then redirect to the organization activation page. """ new_user = create_new_user(self.request, form) new_org = form.create_organization(new_user) mixpanel_event( self.request, 'Organization Created', new_org.mixpanel_event(), ) welcome.delay(new_user) messages.success( self.request, 'Your account and organization were successfully created.') return HttpResponseRedirect( reverse('org-activate', kwargs={'slug': new_org.slug}))
def upgrade(request): """Upgrades the user from a Basic to a Professional account.""" if not request.user.is_authenticated(): raise AttributeError('Cannot upgrade an anonymous user.') is_pro_user = request.user.profile.acct_type in ['pro', 'proxy'] is_org_owner = Organization.objects.filter(owner=request.user).exists() if is_pro_user: raise ValueError( 'Cannot upgrade this account, it is already Professional.') if is_org_owner: raise ValueError( 'Cannot upgrade this account, it owns an organization.') token = request.POST.get('stripe_token') if not token: raise ValueError( 'Cannot upgrade this account, no Stripe token provided.') request.user.profile.start_pro_subscription(token) mixpanel_event(request, 'Pro Subscription Started')
def miniregister(self, full_name, email, newsletter=False): """Create a new user from their full name and email and login""" password = generate_key(12) full_name = full_name.strip() username = unique_username(full_name) first_name, last_name = split_name(full_name) # create a new User user = User.objects.create_user(username, email, password, first_name=first_name, last_name=last_name) # create a new Profile Profile.objects.create(user=user, acct_type='basic', monthly_requests=settings.MONTHLY_REQUESTS.get( 'basic', 0), date_update=date.today()) # send the new user a welcome email welcome_miniregister.delay(user) user = authenticate( username=user.username, password=password, ) login(self.request, user) if newsletter: mailchimp_subscribe( self.request, user.email, source='Mini-Register: {}'.format(self.minireg_source), url='https://{}{}'.format(settings.MUCKROCK_URL, self.request.path), ) mixpanel_event( self.request, 'Sign Up', { 'Source': 'Mini-Register: {}'.format(self.minireg_source), 'Newsletter': newsletter, }, signup=True, ) return user
def make_subscription(self, token, amount, email): """Start a subscription for recurring donations""" subscription = None quantity = amount / 100 customer = stripe_get_customer( self.request.user, email, 'Donation for {}'.format(email), ) if self.request.user.is_authenticated: user = self.request.user else: user = None try: subscription = stripe_retry_on_error( customer.subscriptions.create, plan='donate', source=token, quantity=quantity, idempotency_key=True, ) except stripe.error.CardError: logger.warn('Card was declined.') messages.error(self.request, 'Your card was declined') except stripe.error.StripeError as exception: logger.error(exception, exc_info=sys.exc_info()) messages.error( self.request, 'Oops, something went wrong on our end. Sorry about that!', ) else: RecurringDonation.objects.create( user=user, email=email, amount=quantity, customer_id=customer.id, subscription_id=subscription.id, ) mixpanel_event( self.request, 'Recurring Donation', {'Amount': quantity}, ) return subscription
def _pay_fee(self, request, foia): """A user pays the fee for a request""" form = RequestFeeForm(request.POST, user=self.request.user) if not self.request.user.is_authenticated: messages.error(self.request, 'Must be logged in to pay') return redirect(foia.get_absolute_url() + '#') if form.is_valid(): try: form.cleaned_data['organization'].pay( amount=int(form.cleaned_data['amount'] * 1.05), fee_amount=5, description='Pay ${:.2f} fee for request #{}'.format( form.cleaned_data['amount'] / 100.0, foia.pk), token=form.cleaned_data['stripe_token'], save_card=form.cleaned_data['save_card'], ) except requests.exceptions.RequestException as exc: logger.warn('Payment error: %s', exc, exc_info=sys.exc_info()) if exc.response.status_code / 100 == 4: messages.error( self.request, 'Payment Error: {}'.format('\n'.join( '{}: {}'.format(k, v) for k, v in exc.response.json().iteritems()))) else: messages.error(self.request, 'Payment Error') return redirect(foia.get_absolute_url() + '#') else: messages.success( self.request, 'Your payment was successful. ' 'We will get this to the agency right away!') amount = form.cleaned_data['amount'] / 100.0 foia.pay(self.request.user, amount) mixpanel_event( request, 'Request Fee Paid', foia.mixpanel_data({'Price': amount}), charge=amount, ) return redirect(foia.get_absolute_url() + '#') else: self.fee_form = form raise FoiaFormError
def form_valid(self, form): """When the form is valid, activate the organization.""" # should expect a token from Stripe token = self.request.POST.get('stripe_token') organization = self.get_object() # Do not save the form! The activate_subscription method needs to compare the # new number of seats to the existing number of seats. If the UpdateForm is saved, # it will automatically save the new number of seats to the model since it is a ModelForm. num_seats = form.cleaned_data['max_users'] an_error = False if token: try: organization.activate_subscription(token, num_seats) messages.success(self.request, 'Your organization subscription is active.') logging.info('%s activated %s', self.request.user, organization) mixpanel_event( self.request, 'Organization Activated', organization.mixpanel_event(), ) except (AttributeError, ValueError) as exception: messages.error(self.request, exception) an_error = True except stripe.CardError as exception: messages.error(self.request, exception) an_error = True except (stripe.AuthenticationError, stripe.InvalidRequestError, stripe.StripeError): messages.error( self.request, 'Payment error. Your card has not been charged.') an_error = True else: messages.error(self.request, 'No payment information provided!') an_error = True if an_error: return self.form_invalid(form) else: return redirect(self.get_success_url())