Example #1
0
    def post(self, request, *args, **kwargs):
        form = PrepareWebAppForm(request.DATA)
        if not form.is_valid():
            return Response(form.errors, status=status.HTTP_400_BAD_REQUEST)
        app = form.cleaned_data['app']

        region = getattr(request, 'REGION', None)
        if region and region.id not in app.get_price_region_ids():
            log.info('Region {0} is not in {1}'
                     .format(region.id, app.get_price_region_ids()))
            return Response('Payments are limited and flag not enabled',
                            status=status.HTTP_403_FORBIDDEN)

        if app.is_premium() and app.has_purchased(request._request.amo_user):
            log.info('Already purchased: {0}'.format(app.pk))
            return Response({'reason': u'Already purchased app.'},
                            status=status.HTTP_409_CONFLICT)

        app_pay_cef.log(request._request, 'Preparing JWT', 'preparing_jwt',
                        'Preparing JWT for: {0}'.format(app.pk), severity=3)

        token = get_product_jwt(
            WebAppProduct(app),
            client_data=ClientData.get_or_create(request._request),
            lang=request._request.LANG,
            region=request._request.REGION,
            source=request._request.REQUEST.get('src', ''),
            user=request._request.amo_user,
        )

        return Response(token, status=status.HTTP_201_CREATED)
Example #2
0
def prepare_pay(request, addon):
    """Prepare a BlueVia JWT to pass into navigator.pay()"""
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug('Storing contrib for uuid: %s' % uuid_)
    Contribution.objects.create(addon_id=addon.id, amount=amount,
                                source=request.REQUEST.get('src', ''),
                                source_locale=request.LANG,
                                uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                                paykey=None, user=request.amo_user,
                                price_tier=addon.premium.price,
                                client_data=ClientData.get_or_create(request))

    acct = addon.app_payment_account.payment_account
    seller_uuid = acct.solitude_seller.uuid
    data = {'amount': str(amount),
            'price_point': addon.premium.price.pk,
            'id': addon.pk,
            'app_name': unicode(addon.name),
            'app_description': unicode(addon.summary),
            'postback_url': absolutify(reverse('webpay.postback')),
            'chargeback_url': absolutify(reverse('webpay.chargeback')),
            'seller': addon.pk,
            'product_data': urlencode({'contrib_uuid': uuid_,
                                       'seller_uuid': seller_uuid,
                                       'addon_id': addon.pk}),
            'typ': 'tu.com/payments/inapp/v1',
            'aud': 'tu.com',
            'memo': contrib_for}

    jwt_ = prepare_webpay_pay(data)
    log.debug('Preparing webpay JWT for addon %s: %s' % (addon, jwt_))
    return {'webpayJWT': jwt_,
            'contribStatusURL': reverse('webpay.pay_status',
                                        args=[addon.app_slug, uuid_])}
Example #3
0
def prepare_pay(request, addon):
    """Prepare a BlueVia JWT to pass into navigator.pay()"""
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug('Storing contrib for uuid: %s' % uuid_)
    Contribution.objects.create(addon_id=addon.id, amount=amount,
                                source=request.REQUEST.get('src', ''),
                                source_locale=request.LANG,
                                uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                                paykey=None, user=request.amo_user,
                                price_tier=addon.premium.price,
                                client_data=ClientData.get_or_create(request))

    prices = [{'currency': cur,
               'country': 'XX',  # This is unused but required!
               'amount': str(tier.price)}
              for cur, tier in addon.premium.price.currencies()]

    data = {'amount': str(amount),
            'prices': prices, 'currency': currency,
            'app_name': unicode(addon.name),
            'app_description': unicode(addon.description),
            'postback_url': absolutify(reverse('webpay.postback')),
            'chargeback_url': absolutify(reverse('webpay.chargeback')),
            'seller': addon.pk,
            'product_data': urlencode({'contrib_uuid': uuid_,
                                       'addon_id': addon.pk}),
            'typ': 'tu.com/payments/inapp/v1',
            'aud': 'tu.com',
            'memo': contrib_for}

    return {'webpayJWT': prepare_webpay_pay(data),
            'contribStatusURL': reverse('webpay.pay_status',
                                        args=[addon.app_slug, uuid_])}
Example #4
0
def prepare_pay(request, addon):
    """Prepare a BlueVia JWT to pass into navigator.pay()"""
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug('Storing contrib for uuid: %s' % uuid_)
    Contribution.objects.create(addon_id=addon.id, amount=amount,
                                source=request.REQUEST.get('src', ''),
                                source_locale=request.LANG,
                                uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                                paykey=None, user=request.amo_user,
                                price_tier=addon.premium.price,
                                client_data=ClientData.get_or_create(request))
    data = {'amount': str(amount), 'currency': currency,
            'app_name': unicode(addon.name),
            'app_description': unicode(addon.description),
            'postback_url': absolutify(reverse('bluevia.postback')),
            'chargeback_url': absolutify(reverse('bluevia.chargeback')),
            'seller': addon.pk,
            'product_data': urlencode({'contrib_uuid': uuid_,
                                       'addon_id': addon.pk}),
            'typ': 'tu.com/payments/inapp/v1',
            'aud': 'tu.com',
            'memo': contrib_for}

    if waffle.flag_is_active(request, 'solitude-payments'):
        bluevia_jwt = client.prepare_bluevia_pay(data)
    else:
        bluevia_jwt = prepare_bluevia_pay(data)
    return {'blueviaJWT': bluevia_jwt,
            'contribStatusURL': reverse('bluevia.pay_status',
                                        args=[addon.app_slug, uuid_])}
Example #5
0
    def post(self, request, *args, **kwargs):
        form = PrepareInAppForm(request.DATA)
        if not form.is_valid():
            app_pay_cef.log(
                request._request,
                'Preparing InApp JWT Failed',
                'preparing_inapp_jwt_failed',
                'Preparing InApp JWT Failed error: {0}'.format(form.errors),
                severity=3
            )
            return Response(form.errors, status=status.HTTP_400_BAD_REQUEST)

        inapp = form.cleaned_data['inapp']

        app_pay_cef.log(
            request._request,
            'Preparing InApp JWT',
            'preparing_inapp_jwt',
            'Preparing InApp JWT for: {0}'.format(inapp.pk), severity=3
        )

        token = get_product_jwt(
            InAppProduct(inapp),
            client_data=ClientData.get_or_create(request._request),
            lang=request._request.LANG,
            source=request._request.REQUEST.get('src', ''),
        )

        return Response(token, status=status.HTTP_201_CREATED)
Example #6
0
def prepare_pay(request, addon):
    """Prepare a BlueVia JWT to pass into navigator.pay()"""
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug('Storing contrib for uuid: %s' % uuid_)
    Contribution.objects.create(addon_id=addon.id, amount=amount,
                                source=request.REQUEST.get('src', ''),
                                source_locale=request.LANG,
                                uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                                paykey=None, user=request.amo_user,
                                price_tier=addon.premium.price,
                                client_data=ClientData.get_or_create(request))

    prices = [{'currency': cur, 'amount': str(tier.price)}
              for cur, tier in addon.premium.price.currencies()]

    data = {'amount': str(amount),
            'prices': prices, 'currency': currency,
            'app_name': unicode(addon.name),
            'app_description': unicode(addon.description),
            'postback_url': absolutify(reverse('bluevia.postback')),
            'chargeback_url': absolutify(reverse('bluevia.chargeback')),
            'seller': addon.pk,
            'product_data': urlencode({'contrib_uuid': uuid_,
                                       'addon_id': addon.pk}),
            'typ': 'tu.com/payments/inapp/v1',
            'aud': 'tu.com',
            'memo': contrib_for}

    return {'blueviaJWT': prepare_bluevia_pay(data),
            'contribStatusURL': reverse('bluevia.pay_status',
                                        args=[addon.app_slug, uuid_])}
Example #7
0
def _prepare_pay(request, addon):
    """Prepare a JWT to pass into navigator.pay()"""
    if addon.is_premium() and addon.has_purchased(request.amo_user):
        log.info('Already purchased: %d' % addon.pk)
        raise AlreadyPurchased

    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug('Storing contrib for uuid: %s' % uuid_)
    Contribution.objects.create(addon_id=addon.id, amount=amount,
                                source=request.REQUEST.get('src', ''),
                                source_locale=request.LANG,
                                uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                                paykey=None, user=request.amo_user,
                                price_tier=addon.premium.price,
                                client_data=ClientData.get_or_create(request))

    # Until atob() supports encoded HTML we are stripping all tags.
    # See bug 831524
    app_description = bleach.clean(unicode(addon.description), strip=True,
                                   tags=[])

    acct = addon.app_payment_account.payment_account
    seller_uuid = acct.solitude_seller.uuid
    application_size = addon.current_version.all_files[0].size
    issued_at = calendar.timegm(time.gmtime())
    icons = {}
    for size in amo.ADDON_ICON_SIZES:
        icons[str(size)] = absolutify(addon.get_icon_url(size))
    req = {
        'iss': settings.APP_PURCHASE_KEY,
        'typ': settings.APP_PURCHASE_TYP,
        'aud': settings.APP_PURCHASE_AUD,
        'iat': issued_at,
        'exp': issued_at + 3600,  # expires in 1 hour
        'request': {
            'name': unicode(addon.name),
            'description': app_description,
            'pricePoint': addon.premium.price.name,
            'id': make_ext_id(addon.pk),
            'postbackURL': absolutify(reverse('webpay.postback')),
            'chargebackURL': absolutify(reverse('webpay.chargeback')),
            'productData': urlencode({'contrib_uuid': uuid_,
                                      'seller_uuid': seller_uuid,
                                      'addon_id': addon.pk,
                                      'application_size': application_size}),
            'icons': icons,
        }
    }

    jwt_ = sign_webpay_jwt(req)
    log.debug('Preparing webpay JWT for addon %s: %s' % (addon, jwt_))
    app_pay_cef.log(request, 'Preparing JWT', 'preparing_jwt',
                    'Preparing JWT for: %s' % (addon.pk), severity=3)

    if request.API:
        url = reverse('webpay-status', kwargs={'uuid': uuid_})
    else:
        url = reverse('webpay.pay_status', args=[addon.app_slug, uuid_])
    return {'webpayJWT': jwt_, 'contribStatusURL': url}
Example #8
0
def prepare_pay(request, addon):
    if addon.is_premium() and addon.has_purchased(request.amo_user):
        log.info('Already purchased: %d' % addon.pk)
        raise AlreadyPurchased

    app_pay_cef.log(request, 'Preparing JWT', 'preparing_jwt',
                    'Preparing JWT for: %s' % (addon.pk), severity=3)

    return get_product_jwt(
        WebAppProduct(addon),
        user=request.amo_user,
        region=request.REGION,
        source=request.REQUEST.get('src', ''),
        lang=request.LANG,
        client_data=ClientData.get_or_create(request),
    )
Example #9
0
def prepare_pay(request, addon):
    """Prepare a BlueVia JWT to pass into navigator.pay()"""
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug('Storing contrib for uuid: %s' % uuid_)
    Contribution.objects.create(addon_id=addon.id, amount=amount,
                                source=request.REQUEST.get('src', ''),
                                source_locale=request.LANG,
                                uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                                paykey=None, user=request.amo_user,
                                price_tier=addon.premium.price,
                                client_data=ClientData.get_or_create(request))

    # Until atob() supports encoded HTML we are stripping all tags.
    # See bug 831524
    app_summary = bleach.clean(unicode(addon.summary), strip=True, tags=[])

    acct = addon.app_payment_account.payment_account
    seller_uuid = acct.solitude_seller.uuid
    issued_at = calendar.timegm(time.gmtime())
    req = {
        'iss': settings.APP_PURCHASE_KEY,
        'typ': settings.APP_PURCHASE_TYP,
        'aud': settings.APP_PURCHASE_AUD,
        'iat': issued_at,
        'exp': issued_at + 3600,  # expires in 1 hour
        'request': {
            'name': unicode(addon.name),
            'description': app_summary,
            'pricePoint': addon.premium.price.pk,
            'id': make_ext_id(addon.pk),
            'postbackURL': absolutify(reverse('webpay.postback')),
            'chargebackURL': absolutify(reverse('webpay.chargeback')),
            'productData': urlencode({'contrib_uuid': uuid_,
                                      'seller_uuid': seller_uuid,
                                      'addon_id': addon.pk}),
        }
    }

    jwt_ = sign_webpay_jwt(req)
    log.debug('Preparing webpay JWT for addon %s: %s' % (addon, jwt_))
    app_pay_cef.log(request, 'Preparing JWT', 'preparing_jwt',
                    'Preparing JWT for: %s' % (addon.pk), severity=3)
    return {'webpayJWT': jwt_,
            'contribStatusURL': reverse('webpay.pay_status',
                                        args=[addon.app_slug, uuid_])}
Example #10
0
def prepare_pay(request, addon):
    """Prepare a BlueVia JWT to pass into navigator.pay()"""
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug("Storing contrib for uuid: %s" % uuid_)
    Contribution.objects.create(
        addon_id=addon.id,
        amount=amount,
        source=request.REQUEST.get("src", ""),
        source_locale=request.LANG,
        uuid=str(uuid_),
        type=amo.CONTRIB_PENDING,
        paykey=None,
        user=request.amo_user,
        price_tier=addon.premium.price,
        client_data=ClientData.get_or_create(request),
    )

    # Until atob() supports encoded HTML we are stripping all tags.
    # See bug 831524
    app_summary = bleach.clean(unicode(addon.summary), strip=True, tags=[])

    acct = addon.app_payment_account.payment_account
    seller_uuid = acct.solitude_seller.uuid
    issued_at = calendar.timegm(time.gmtime())
    req = {
        "iss": settings.APP_PURCHASE_KEY,
        "typ": settings.APP_PURCHASE_TYP,
        "aud": settings.APP_PURCHASE_AUD,
        "iat": issued_at,
        "exp": issued_at + 3600,  # expires in 1 hour
        "request": {
            "name": unicode(addon.name),
            "description": app_summary,
            "pricePoint": addon.premium.price.pk,
            "id": make_ext_id(addon.pk),
            "postbackURL": absolutify(reverse("webpay.postback")),
            "chargebackURL": absolutify(reverse("webpay.chargeback")),
            "productData": urlencode({"contrib_uuid": uuid_, "seller_uuid": seller_uuid, "addon_id": addon.pk}),
        },
    }

    jwt_ = sign_webpay_jwt(req)
    log.debug("Preparing webpay JWT for addon %s: %s" % (addon, jwt_))
    app_pay_cef.log(request, "Preparing JWT", "preparing_jwt", "Preparing JWT for: %s" % (addon.pk), severity=3)
    return {"webpayJWT": jwt_, "contribStatusURL": reverse("webpay.pay_status", args=[addon.app_slug, uuid_])}
Example #11
0
    def test_get_or_create(self):
        download_source = DownloadSource.objects.create(name='mkt-home')
        device_type = 'desktop'
        user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0)'
        client = RequestFactory()
        request = client.post('/somewhere',
                              data={'src': download_source.name,
                                    'device_type': device_type,
                                    'is_chromeless': False},
                              **{'HTTP_USER_AGENT': user_agent})

        cli = ClientData.get_or_create(request)
        eq_(cli.download_source, download_source)
        eq_(cli.device_type, device_type)
        eq_(cli.user_agent, user_agent)
        eq_(cli.is_chromeless, False)
        eq_(cli.language, 'en-us')
        eq_(cli.region, None)
Example #12
0
def prepare_pay(request, addon):
    """Prepare a BlueVia JWT to pass into navigator.pay()"""
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug('Storing contrib for uuid: %s' % uuid_)
    Contribution.objects.create(addon_id=addon.id, amount=amount,
                                source=request.REQUEST.get('src', ''),
                                source_locale=request.LANG,
                                uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                                paykey=None, user=request.amo_user,
                                price_tier=addon.premium.price,
                                client_data=ClientData.get_or_create(request))

    # Until atob() supports encoded HTML we are stripping all tags.
    # See bug 831524
    app_summary = bleach.clean(unicode(addon.summary), strip=True, tags=[])

    acct = addon.app_payment_account.payment_account
    seller_uuid = acct.solitude_seller.uuid
    issued_at = calendar.timegm(time.gmtime())
    req = {
        'iss': settings.APP_PURCHASE_KEY,
        'typ': settings.APP_PURCHASE_TYP,
        'aud': settings.APP_PURCHASE_AUD,
        'iat': issued_at,
        'exp': issued_at + 3600,  # expires in 1 hour
        'request': {
            'name': unicode(addon.name),
            'description': app_summary,
            'pricePoint': addon.premium.price.pk,
            'id': make_ext_id(addon.pk),
            'postbackURL': absolutify(reverse('webpay.postback')),
            'chargebackURL': absolutify(reverse('webpay.chargeback')),
            'productData': urlencode({'contrib_uuid': uuid_,
                                      'seller_uuid': seller_uuid,
                                      'addon_id': addon.pk}),
        }
    }

    jwt_ = sign_webpay_jwt(req)
    log.debug('Preparing webpay JWT for addon %s: %s' % (addon, jwt_))
    return {'webpayJWT': jwt_,
            'contribStatusURL': reverse('webpay.pay_status',
                                        args=[addon.app_slug, uuid_])}
Example #13
0
def prepare_pay(request, addon):
    if addon.is_premium() and addon.has_purchased(request.amo_user):
        log.info('Already purchased: %d' % addon.pk)
        raise AlreadyPurchased

    app_pay_cef.log(request,
                    'Preparing JWT',
                    'preparing_jwt',
                    'Preparing JWT for: %s' % (addon.pk),
                    severity=3)

    return get_product_jwt(
        WebAppProduct(addon),
        user=request.amo_user,
        region=request.REGION,
        source=request.REQUEST.get('src', ''),
        lang=request.LANG,
        client_data=ClientData.get_or_create(request),
    )
Example #14
0
    def test_get_or_create(self):
        download_source = DownloadSource.objects.create(name='mkt-home')
        device_type = 'desktop'
        user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:16.0)'
        client = RequestFactory()
        request = client.post('/somewhere',
                              data={
                                  'src': download_source.name,
                                  'device_type': device_type,
                                  'is_chromeless': False
                              },
                              **{'HTTP_USER_AGENT': user_agent})

        cli = ClientData.get_or_create(request)
        eq_(cli.download_source, download_source)
        eq_(cli.device_type, device_type)
        eq_(cli.user_agent, user_agent)
        eq_(cli.is_chromeless, False)
        eq_(cli.language, 'en-us')
        eq_(cli.region, None)
Example #15
0
def debug(request, addon):
    if not settings.DEBUG:
        raise http.Http404

    data = {
        'urls': {'es': '%s/apps/webapp/%s' % (settings.ES_URLS[0], addon.pk)},
        'pay_request': ''
    }
    if addon.is_premium():
        data['pay_request'] = get_product_jwt(
            WebAppProduct(addon),
            user=request.amo_user,
            region=request.REGION,
            source=request.REQUEST.get('src', ''),
            lang=request.LANG,
            client_data=ClientData.get_or_create(request),
        )['webpayJWT']

    return render(request, 'developers/debug.html',
                  {'app': addon, 'data': data})
Example #16
0
def prepare_pay(request, addon):
    """Prepare a BlueVia JWT to pass into navigator.pay()"""
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug('Storing contrib for uuid: %s' % uuid_)
    Contribution.objects.create(addon_id=addon.id, amount=amount,
                                source=request.REQUEST.get('src', ''),
                                source_locale=request.LANG,
                                uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                                paykey=None, user=request.amo_user,
                                price_tier=addon.premium.price,
                                client_data=ClientData.get_or_create(request))
    data = {'amount': amount, 'currency': currency,
            'app_name': unicode(addon.name),
            'app_description': unicode(addon.description),
            'postback_url': absolutify(reverse('bluevia.postback')),
            'chargeback_url': absolutify(reverse('bluevia.chargeback')),
            'seller': addon,
            'contrib_uuid': uuid_,
            'memo': contrib_for}

    return {'bluevia_jwt': client.prepare_bluevia_pay(data),
            'contrib_uuid': uuid_}
Example #17
0
def debug(request, addon):
    if not settings.DEBUG:
        raise http.Http404

    data = {
        'urls': {
            'es': '%s/apps/webapp/%s' % (settings.ES_URLS[0], addon.pk)
        },
        'pay_request': ''
    }
    if addon.is_premium():
        data['pay_request'] = get_product_jwt(
            WebAppProduct(addon),
            user=request.amo_user,
            region=request.REGION,
            source=request.REQUEST.get('src', ''),
            lang=request.LANG,
            client_data=ClientData.get_or_create(request),
        )['webpayJWT']

    return render(request, 'developers/debug.html', {
        'app': addon,
        'data': data
    })
Example #18
0
def purchase(request, addon):
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)

    if not amount:
        # We won't write a contribution row for this because there
        # will not be a valid Paypal transaction. But we have to write the
        # Purchase row, something that writing to the contribution normally
        # does for us.
        AddonPurchase.objects.safer_get_or_create(addon=addon,
                                                  user=request.amo_user)
        return http.HttpResponse(json.dumps({
            'url': '',
            'paykey': '',
            'error': '',
            'status': 'COMPLETED'
        }),
                                 content_type='application/json')

    paykey, status, error = '', '', ''

    # TODO(solitude): remove this, pre-approval and currency will be
    # stored in solitude.
    preapproval = None
    if (not waffle.flag_is_active(request, 'solitude-payments')
            and request.amo_user):
        preapproval = request.amo_user.get_preapproval()
        # User the users default currency.
        if currency == 'USD' and preapproval and preapproval.currency:
            currency = preapproval.currency

    if waffle.flag_is_active(request, 'solitude-payments'):
        # Now call the client.
        result = {}
        try:
            result = client.pay({
                'amount': amount,
                'currency': currency,
                'buyer': request.amo_user,
                'seller': addon,
                'memo': contrib_for
            })
        except client.Error as error:
            # Note that by assigning this to error, it will go into the return
            # value for the json. General solitude errors will then be
            # reported back to the user.
            paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure',
                                  'PAYKEYFAIL',
                                  'There was an error getting the paykey')
            log.error('Error getting paykey: %s' % addon.pk, exc_info=True)

        # TODO(solitude): just use the dictionary when solitude is live.
        paykey = result.get('pay_key', '')
        status = result.get('status', '')
        uuid_ = result.get('uuid', '')

    else:
        # TODO(solitude): remove this when solitude goes live.
        try:
            paykey, status = paypal.get_paykey(
                dict(amount=amount,
                     chains=settings.PAYPAL_CHAINS,
                     currency=currency,
                     email=addon.paypal_id,
                     ip=request.META.get('REMOTE_ADDR'),
                     memo=contrib_for,
                     pattern='purchase.done',
                     preapproval=preapproval,
                     qs={'realurl': request.POST.get('realurl')},
                     slug=addon.app_slug,
                     uuid=uuid_))
        except paypal.PaypalError as error:
            paypal.paypal_log_cef(request, addon, uuid_, 'PayKey Failure',
                                  'PAYKEYFAIL',
                                  'There was an error getting the paykey')
            log.error('Error getting paykey, purchase of addon: %s' % addon.pk,
                      exc_info=True)

    if paykey:
        # TODO(solitude): at some point we'll have to see what to do with
        # contributions.
        download_source = request.REQUEST.get('src', '')
        contrib = Contribution(addon_id=addon.id,
                               amount=amount,
                               source=download_source,
                               source_locale=request.LANG,
                               uuid=str(uuid_),
                               type=amo.CONTRIB_PENDING,
                               paykey=paykey,
                               user=request.amo_user,
                               price_tier=addon.premium.price,
                               client_data=ClientData.get_or_create(request))

        log.debug('Storing contrib for uuid: %s' % uuid_)

        # If this was a pre-approval, it's completed already, we'll
        # double check this with PayPal, just to be sure nothing went wrong.
        if status == 'COMPLETED':
            paypal.paypal_log_cef(request, addon, uuid_, 'Purchase',
                                  'PURCHASE',
                                  'A user purchased using pre-approval')

            log.debug('Status completed for uuid: %s' % uuid_)
            if waffle.flag_is_active(request, 'solitude-payments'):
                result = client.post_pay_check(data={'pay_key': paykey})
                if result['status'] == 'COMPLETED':
                    contrib.type = amo.CONTRIB_PURCHASE
                else:
                    log.error('Check purchase failed on uuid: %s' % uuid_)
                    status = 'NOT-COMPLETED'

            else:
                #TODO(solitude): remove this when solitude goes live.
                if paypal.check_purchase(paykey) == 'COMPLETED':
                    log.debug('Check purchase completed for uuid: %s' % uuid_)
                    contrib.type = amo.CONTRIB_PURCHASE
                else:
                    # In this case PayPal disagreed, we should not be trusting
                    # what get_paykey said. Which is a worry.
                    log.error('Check purchase failed on uuid: %s' % uuid_)
                    status = 'NOT-COMPLETED'

        contrib.save()

    else:
        log.error('No paykey present for uuid: %s' % uuid_)

    log.debug('Got paykey for addon: %s by user: %s' %
              (addon.pk, request.amo_user.pk))
    url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey)
    if request.POST.get('result_type') == 'json' or request.is_ajax():
        return http.HttpResponse(json.dumps({
            'url': url,
            'paykey': paykey,
            'error': str(error),
            'status': status
        }),
                                 content_type='application/json')

    # This is the non-Ajax fallback.
    if status != 'COMPLETED':
        return http.HttpResponseRedirect(url)

    messages.success(request, _('Purchase complete'))
    return http.HttpResponseRedirect(addon.get_detail_url())
Example #19
0
def purchase(request, addon):
    amount, currency, uuid_, contrib_for = start_purchase(request, addon)

    if not amount:
        # We won't write a contribution row for this because there
        # will not be a valid Paypal transaction. But we have to write the
        # Purchase row, something that writing to the contribution normally
        # does for us.
        AddonPurchase.objects.safer_get_or_create(addon=addon,
                                                  user=request.amo_user)
        return http.HttpResponse(json.dumps({'url': '', 'paykey': '',
                                             'error': '',
                                             'status': 'COMPLETED'}),
                                 content_type='application/json')

    paykey, status, error = '', '', ''

    # TODO(solitude): remove this, pre-approval and currency will be
    # stored in solitude.
    preapproval = None
    if (not waffle.flag_is_active(request, 'solitude-payments')
        and request.amo_user):
        preapproval = request.amo_user.get_preapproval()
        # User the users default currency.
        if currency == 'USD' and preapproval and preapproval.currency:
            currency = preapproval.currency

    if waffle.flag_is_active(request, 'solitude-payments'):
        # Now call the client.
        result = {}
        try:
            result = client.pay({'amount': amount, 'currency': currency,
                                 'buyer': request.amo_user, 'seller': addon,
                                 'memo': contrib_for})
        except client.Error as error:
            # Note that by assigning this to error, it will go into the return
            # value for the json. General solitude errors will then be
            # reported back to the user.
            paypal.paypal_log_cef(request, addon, uuid_,
                                  'PayKey Failure', 'PAYKEYFAIL',
                                  'There was an error getting the paykey')
            log.error('Error getting paykey: %s' % addon.pk, exc_info=True)

        # TODO(solitude): just use the dictionary when solitude is live.
        paykey = result.get('pay_key', '')
        status = result.get('status', '')
        uuid_ = result.get('uuid', '')

    else:
        # TODO(solitude): remove this when solitude goes live.
        try:
            paykey, status = paypal.get_paykey(dict(
                amount=amount,
                chains=settings.PAYPAL_CHAINS,
                currency=currency,
                email=addon.paypal_id,
                ip=request.META.get('REMOTE_ADDR'),
                memo=contrib_for,
                pattern='purchase.done',
                preapproval=preapproval,
                qs={'realurl': request.POST.get('realurl')},
                slug=addon.app_slug,
                uuid=uuid_
            ))
        except paypal.PaypalError as error:
            paypal.paypal_log_cef(request, addon, uuid_,
                                  'PayKey Failure', 'PAYKEYFAIL',
                                  'There was an error getting the paykey')
            log.error('Error getting paykey, purchase of addon: %s' % addon.pk,
                      exc_info=True)

    if paykey:
        # TODO(solitude): at some point we'll have to see what to do with
        # contributions.
        download_source = request.REQUEST.get('src', '')
        contrib = Contribution(addon_id=addon.id, amount=amount,
                               source=download_source,
                               source_locale=request.LANG,
                               uuid=str(uuid_), type=amo.CONTRIB_PENDING,
                               paykey=paykey, user=request.amo_user,
                               price_tier=addon.premium.price,
                               client_data=ClientData.get_or_create(request))

        log.debug('Storing contrib for uuid: %s' % uuid_)

        # If this was a pre-approval, it's completed already, we'll
        # double check this with PayPal, just to be sure nothing went wrong.
        if status == 'COMPLETED':
            paypal.paypal_log_cef(request, addon, uuid_,
                                  'Purchase', 'PURCHASE',
                                  'A user purchased using pre-approval')

            log.debug('Status completed for uuid: %s' % uuid_)
            if waffle.flag_is_active(request, 'solitude-payments'):
                result = client.post_pay_check(data={'pay_key': paykey})
                if result['status'] == 'COMPLETED':
                    contrib.type = amo.CONTRIB_PURCHASE
                else:
                    log.error('Check purchase failed on uuid: %s' % uuid_)
                    status = 'NOT-COMPLETED'

            else:
                #TODO(solitude): remove this when solitude goes live.
                if paypal.check_purchase(paykey) == 'COMPLETED':
                    log.debug('Check purchase completed for uuid: %s' % uuid_)
                    contrib.type = amo.CONTRIB_PURCHASE
                else:
                    # In this case PayPal disagreed, we should not be trusting
                    # what get_paykey said. Which is a worry.
                    log.error('Check purchase failed on uuid: %s' % uuid_)
                    status = 'NOT-COMPLETED'

        contrib.save()

    else:
        log.error('No paykey present for uuid: %s' % uuid_)

    log.debug('Got paykey for addon: %s by user: %s'
              % (addon.pk, request.amo_user.pk))
    url = '%s?paykey=%s' % (settings.PAYPAL_FLOW_URL, paykey)
    if request.POST.get('result_type') == 'json' or request.is_ajax():
        return http.HttpResponse(json.dumps({'url': url,
                                             'paykey': paykey,
                                             'error': str(error),
                                             'status': status}),
                                 content_type='application/json')

    # This is the non-Ajax fallback.
    if status != 'COMPLETED':
        return http.HttpResponseRedirect(url)

    messages.success(request, _('Purchase complete'))
    return http.HttpResponseRedirect(addon.get_detail_url())
Example #20
0
def _prepare_pay(request, addon):
    """Prepare a JWT to pass into navigator.pay()"""
    if addon.is_premium() and addon.has_purchased(request.amo_user):
        log.info('Already purchased: %d' % addon.pk)
        raise AlreadyPurchased

    amount, currency, uuid_, contrib_for = start_purchase(request, addon)
    log.debug('Storing contrib for uuid: %s' % uuid_)
    Contribution.objects.create(addon_id=addon.id,
                                amount=amount,
                                source=request.REQUEST.get('src', ''),
                                source_locale=request.LANG,
                                uuid=str(uuid_),
                                type=amo.CONTRIB_PENDING,
                                paykey=None,
                                user=request.amo_user,
                                price_tier=addon.premium.price,
                                client_data=ClientData.get_or_create(request))

    # Until atob() supports encoded HTML we are stripping all tags.
    # See bug 831524
    app_description = bleach.clean(unicode(addon.description),
                                   strip=True,
                                   tags=[])

    acct = addon.app_payment_account.payment_account
    seller_uuid = acct.solitude_seller.uuid
    application_size = addon.current_version.all_files[0].size
    issued_at = calendar.timegm(time.gmtime())
    icons = {}
    for size in amo.ADDON_ICON_SIZES:
        icons[str(size)] = absolutify(addon.get_icon_url(size))
    req = {
        'iss': settings.APP_PURCHASE_KEY,
        'typ': settings.APP_PURCHASE_TYP,
        'aud': settings.APP_PURCHASE_AUD,
        'iat': issued_at,
        'exp': issued_at + 3600,  # expires in 1 hour
        'request': {
            'name':
            unicode(addon.name),
            'description':
            app_description,
            'pricePoint':
            addon.premium.price.name,
            'id':
            make_ext_id(addon.pk),
            'postbackURL':
            absolutify(reverse('webpay.postback')),
            'chargebackURL':
            absolutify(reverse('webpay.chargeback')),
            'productData':
            urlencode({
                'contrib_uuid': uuid_,
                'seller_uuid': seller_uuid,
                'addon_id': addon.pk,
                'application_size': application_size
            }),
            'icons':
            icons,
        }
    }

    jwt_ = sign_webpay_jwt(req)
    log.debug('Preparing webpay JWT for addon %s: %s' % (addon, jwt_))
    app_pay_cef.log(request,
                    'Preparing JWT',
                    'preparing_jwt',
                    'Preparing JWT for: %s' % (addon.pk),
                    severity=3)

    if request.API:
        url = reverse('api_dispatch_detail',
                      kwargs={
                          'resource_name': 'status',
                          'api_name': 'webpay',
                          'uuid': uuid_
                      })
    else:
        url = reverse('webpay.pay_status', args=[addon.app_slug, uuid_])
    return {'webpayJWT': jwt_, 'contribStatusURL': url}