mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	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:
		
							
								
								
									
										0
									
								
								zilencer/lib/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								zilencer/lib/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										63
									
								
								zilencer/lib/stripe.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								zilencer/lib/stripe.py
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -1,6 +1,4 @@
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
import os
 | 
			
		||||
from typing import Any, Dict, Optional, Text, Union, cast
 | 
			
		||||
 | 
			
		||||
from django.http import HttpRequest, HttpResponse
 | 
			
		||||
@@ -10,13 +8,9 @@ from django.shortcuts import render
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from django.views.decorators.http import require_GET
 | 
			
		||||
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.lib.exceptions import JsonableError
 | 
			
		||||
from zerver.lib.logging_util import log_to_file
 | 
			
		||||
from zerver.lib.push_notifications import send_android_push_notification, \
 | 
			
		||||
    send_apple_push_notification
 | 
			
		||||
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.models import UserProfile, Realm
 | 
			
		||||
from zerver.views.push_notifications import validate_token
 | 
			
		||||
from zilencer.models import RemotePushDeviceToken, RemoteZulipServer, 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)
 | 
			
		||||
from zilencer.lib.stripe import STRIPE_PUBLISHABLE_KEY, count_stripe_cards, \
 | 
			
		||||
    save_stripe_token, CardError, StripeError, billing_logger
 | 
			
		||||
from zilencer.models import RemotePushDeviceToken, RemoteZulipServer
 | 
			
		||||
 | 
			
		||||
def validate_entity(entity: Union[UserProfile, RemoteZulipServer]) -> None:
 | 
			
		||||
    if not isinstance(entity, RemoteZulipServer):
 | 
			
		||||
@@ -121,44 +104,6 @@ def remote_server_notify_push(request: HttpRequest, entity: Union[UserProfile, R
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
def add_payment_method(request: HttpRequest) -> HttpResponse:
 | 
			
		||||
    user = request.user
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user