billing: Move most Stripe code to its own file.

We'll handle the error-handling in a separate commit, as it's still
entangled with the view function.
This commit is contained in:
Greg Price 2018-01-30 11:49:25 -08:00
parent 5feb31a957
commit 0b81762350
3 changed files with 66 additions and 58 deletions

0
zilencer/lib/__init__.py Normal file
View File

63
zilencer/lib/stripe.py Normal file
View File

@ -0,0 +1,63 @@
import logging
import os
from django.conf import settings
import stripe
from stripe.error import CardError, RateLimitError, InvalidRequestError, \
AuthenticationError, APIConnectionError, StripeError
from zerver.lib.logging_util import log_to_file
from zerver.models import Realm, UserProfile
from zilencer.models import Customer
from zproject.settings import get_secret
STRIPE_SECRET_KEY = get_secret('stripe_secret_key')
STRIPE_PUBLISHABLE_KEY = get_secret('stripe_publishable_key')
stripe.api_key = STRIPE_SECRET_KEY
BILLING_LOG_PATH = os.path.join('/var/log/zulip'
if not settings.DEVELOPMENT
else settings.DEVELOPMENT_LOG_DIRECTORY,
'billing.log')
billing_logger = logging.getLogger('zilencer.stripe')
log_to_file(billing_logger, BILLING_LOG_PATH)
log_to_file(logging.getLogger('stripe'), BILLING_LOG_PATH)
def count_stripe_cards(realm: Realm) -> int:
try:
customer_obj = Customer.objects.get(realm=realm)
cards = stripe.Customer.retrieve(customer_obj.stripe_customer_id).sources.all(object="card")
return len(cards["data"])
except Customer.DoesNotExist:
return 0
def save_stripe_token(user: UserProfile, token: str) -> int:
"""Returns total number of cards."""
# The card metadata doesn't show up in Dashboard but can be accessed
# using the API.
card_metadata = {"added_user_id": user.id, "added_user_email": user.email}
try:
customer_obj = Customer.objects.get(realm=user.realm)
customer = stripe.Customer.retrieve(customer_obj.stripe_customer_id)
billing_logger.info("Adding card on customer %s: source=%r, metadata=%r",
customer_obj.stripe_customer_id, token, card_metadata)
card = customer.sources.create(source=token, metadata=card_metadata)
customer.default_source = card.id
customer.save()
return len(customer.sources.all(object="card")["data"])
except Customer.DoesNotExist:
customer_metadata = {"string_id": user.realm.string_id}
# Description makes it easier to identify customers in Stripe dashboard
description = "{} ({})".format(user.realm.name, user.realm.string_id)
billing_logger.info("Creating customer: source=%r, description=%r, metadata=%r",
token, description, customer_metadata)
customer = stripe.Customer.create(source=token,
description=description,
metadata=customer_metadata)
card = customer.sources.all(object="card")["data"][0]
card.metadata = card_metadata
card.save()
Customer.objects.create(realm=user.realm, stripe_customer_id=customer.id)
return 1

View File

@ -1,6 +1,4 @@
import logging
import os
from typing import Any, Dict, Optional, Text, Union, cast from typing import Any, Dict, Optional, Text, Union, cast
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
@ -10,13 +8,9 @@ from django.shortcuts import render
from django.conf import settings from django.conf import settings
from django.views.decorators.http import require_GET from django.views.decorators.http import require_GET
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
import stripe
from stripe.error import CardError, RateLimitError, InvalidRequestError, \
AuthenticationError, APIConnectionError, StripeError
from zerver.decorator import require_post, zulip_login_required from zerver.decorator import require_post, zulip_login_required
from zerver.lib.exceptions import JsonableError from zerver.lib.exceptions import JsonableError
from zerver.lib.logging_util import log_to_file
from zerver.lib.push_notifications import send_android_push_notification, \ from zerver.lib.push_notifications import send_android_push_notification, \
send_apple_push_notification send_apple_push_notification
from zerver.lib.request import REQ, has_request_variables from zerver.lib.request import REQ, has_request_variables
@ -24,20 +18,9 @@ from zerver.lib.response import json_error, json_success
from zerver.lib.validator import check_int from zerver.lib.validator import check_int
from zerver.models import UserProfile, Realm from zerver.models import UserProfile, Realm
from zerver.views.push_notifications import validate_token from zerver.views.push_notifications import validate_token
from zilencer.models import RemotePushDeviceToken, RemoteZulipServer, Customer from zilencer.lib.stripe import STRIPE_PUBLISHABLE_KEY, count_stripe_cards, \
from zproject.settings import get_secret save_stripe_token, CardError, StripeError, billing_logger
from zilencer.models import RemotePushDeviceToken, RemoteZulipServer
STRIPE_SECRET_KEY = get_secret('stripe_secret_key')
STRIPE_PUBLISHABLE_KEY = get_secret('stripe_publishable_key')
stripe.api_key = STRIPE_SECRET_KEY
BILLING_LOG_PATH = os.path.join('/var/log/zulip'
if not settings.DEVELOPMENT
else settings.DEVELOPMENT_LOG_DIRECTORY,
'billing.log')
billing_logger = logging.getLogger('zilencer.stripe')
log_to_file(billing_logger, BILLING_LOG_PATH)
log_to_file(logging.getLogger('stripe'), BILLING_LOG_PATH)
def validate_entity(entity: Union[UserProfile, RemoteZulipServer]) -> None: def validate_entity(entity: Union[UserProfile, RemoteZulipServer]) -> None:
if not isinstance(entity, RemoteZulipServer): if not isinstance(entity, RemoteZulipServer):
@ -121,44 +104,6 @@ def remote_server_notify_push(request: HttpRequest, entity: Union[UserProfile, R
return json_success() return json_success()
def count_stripe_cards(realm: Realm) -> int:
try:
customer_obj = Customer.objects.get(realm=realm)
cards = stripe.Customer.retrieve(customer_obj.stripe_customer_id).sources.all(object="card")
return len(cards["data"])
except Customer.DoesNotExist:
return 0
def save_stripe_token(user: UserProfile, token: str) -> int:
"""Returns total number of cards."""
# The card metadata doesn't show up in Dashboard but can be accessed
# using the API.
card_metadata = {"added_user_id": user.id, "added_user_email": user.email}
try:
customer_obj = Customer.objects.get(realm=user.realm)
customer = stripe.Customer.retrieve(customer_obj.stripe_customer_id)
billing_logger.info("Adding card on customer %s: source=%r, metadata=%r",
customer_obj.stripe_customer_id, token, card_metadata)
card = customer.sources.create(source=token, metadata=card_metadata)
customer.default_source = card.id
customer.save()
return len(customer.sources.all(object="card")["data"])
except Customer.DoesNotExist:
customer_metadata = {"string_id": user.realm.string_id}
# Description makes it easier to identify customers in Stripe dashboard
description = "{} ({})".format(user.realm.name, user.realm.string_id)
billing_logger.info("Creating customer: source=%r, description=%r, metadata=%r",
token, description, customer_metadata)
customer = stripe.Customer.create(source=token,
description=description,
metadata=customer_metadata)
card = customer.sources.all(object="card")["data"][0]
card.metadata = card_metadata
card.save()
Customer.objects.create(realm=user.realm, stripe_customer_id=customer.id)
return 1
@zulip_login_required @zulip_login_required
def add_payment_method(request: HttpRequest) -> HttpResponse: def add_payment_method(request: HttpRequest) -> HttpResponse:
user = request.user user = request.user