Ejemplo n.º 1
0
 def test_email_is_blocked(self, BlockedEmailMock):
     """Asking if blocked should only hit the DB once."""
     BlockedEmailMock.objects.values_list.return_value = ['.ninja', 'stuff.web']
     self.assertTrue(email_is_blocked('*****@*****.**'))
     self.assertTrue(email_is_blocked('*****@*****.**'))
     self.assertFalse(email_is_blocked('*****@*****.**'))
     self.assertEqual(BlockedEmailMock.objects.values_list.call_count, 1)
Ejemplo n.º 2
0
 def test_email_is_blocked(self, BlockedEmailMock):
     """Asking if blocked should only hit the DB once."""
     BlockedEmailMock.objects.values_list.return_value = [".ninja", "stuff.web"]
     self.assertTrue(email_is_blocked("*****@*****.**"))
     self.assertTrue(email_is_blocked("*****@*****.**"))
     self.assertFalse(email_is_blocked("*****@*****.**"))
     self.assertEqual(BlockedEmailMock.objects.values_list.call_count, 1)
Ejemplo n.º 3
0
def send_recovery_message(request):
    """
    Send a recovery message to an email address.

    required form parameter: email

    If email not provided or not syntactically correct, returns 400.
    If email not known, returns 404.
    Otherwise, queues a task to send the message and returns 200.
    """
    email = process_email(request.POST.get("email"))
    if not email:
        return invalid_email_response()

    if email_is_blocked(email):
        # don't let on there's a problem
        return HttpResponseJSON({"status": "ok"})

    try:
        user_data = get_user_data(email=email)
    except NewsletterException as e:
        return newsletter_exception_response(e)

    if not user_data:
        return HttpResponseJSON(
            {
                "status": "error",
                "desc": "Email address not known",
                "code": errors.BASKET_UNKNOWN_EMAIL,
            },
            404,
        )  # Note: Bedrock looks for this 404

    send_recovery_message_task.delay(email)
    return HttpResponseJSON({"status": "ok"})
Ejemplo n.º 4
0
Archivo: views.py Proyecto: pmac/basket
def send_recovery_message(request):
    """
    Send a recovery message to an email address.

    required form parameter: email

    If email not provided or not syntactically correct, returns 400.
    If email not known, returns 404.
    Otherwise, queues a task to send the message and returns 200.
    """
    email = process_email(request.POST.get('email'))
    if not email:
        return invalid_email_response()

    if email_is_blocked(email):
        # don't let on there's a problem
        return HttpResponseJSON({'status': 'ok'})

    try:
        user_data = get_user_data(email=email)
    except NewsletterException as e:
        return newsletter_exception_response(e)

    if not user_data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'Email address not known',
            'code': errors.BASKET_UNKNOWN_EMAIL,
        }, 404)  # Note: Bedrock looks for this 404

    send_recovery_message_task.delay(email)
    return HttpResponseJSON({'status': 'ok'})
Ejemplo n.º 5
0
def subscribe_main(request):
    """Subscription view for use with client side JS"""
    form = SubscribeForm(request.POST)
    if form.is_valid():
        data = form.cleaned_data

        if email_is_blocked(data['email']):
            statsd.incr('news.views.subscribe_main.email_blocked')
            # don't let on there's a problem
            return respond_ok(request, data)

        data['format'] = data.pop('fmt') or 'H'

        if data['lang']:
            if not language_code_is_valid(data['lang']):
                data['lang'] = 'en'
        # if lang not provided get the best one from the accept-language header
        else:
            lang = get_best_request_lang(request)
            if lang:
                data['lang'] = lang
            else:
                del data['lang']

        # now ensure that if we do have a lang that it's a supported one
        if 'lang' in data:
            data['lang'] = get_best_supported_lang(data['lang'])

        # if source_url not provided we should store the referrer header
        # NOTE this is not a typo; Referrer is misspelled in the HTTP spec
        # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36
        if not data['source_url'] and request.META.get('HTTP_REFERER'):
            referrer = request.META['HTTP_REFERER']
            if SOURCE_URL_RE.match(referrer):
                statsd.incr('news.views.subscribe_main.use_referrer')
                data['source_url'] = referrer

        if is_ratelimited(request, group='basket.news.views.subscribe_main',
                          key=lambda x, y: '%s-%s' % (':'.join(data['newsletters']), data['email']),
                          rate=EMAIL_SUBSCRIBE_RATE_LIMIT, increment=True):
            statsd.incr('subscribe.ratelimited')
            return respond_error(request, form, 'Rate limit reached', 429)

        try:
            upsert_user.delay(SUBSCRIBE, data, start_time=time())
        except Exception:
            return respond_error(request, form, 'Unknown error', 500)

        return respond_ok(request, data)

    else:
        # form is invalid
        if request.is_ajax():
            return HttpResponseJSON({
                'status': 'error',
                'errors': format_form_errors(form.errors),
                'errors_by_field': form.errors,
            }, 400)
        else:
            return render(request, 'news/formerror.html', {'form': form}, status=400)
Ejemplo n.º 6
0
def subscribe_main(request):
    """Subscription view for use with client side JS"""
    form = SubscribeForm(request.POST)
    if form.is_valid():
        data = form.cleaned_data

        if email_is_blocked(data['email']):
            statsd.incr('news.views.subscribe_main.email_blocked')
            # don't let on there's a problem
            return respond_ok(request, data)

        data['format'] = data.pop('fmt') or 'H'

        if data['lang']:
            if not language_code_is_valid(data['lang']):
                data['lang'] = 'en'
        # if lang not provided get the best one from the accept-language header
        else:
            lang = get_best_request_lang(request)
            if lang:
                data['lang'] = lang
            else:
                del data['lang']

        # if source_url not provided we should store the referrer header
        # NOTE this is not a typo; Referrer is misspelled in the HTTP spec
        # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36
        if not data['source_url'] and request.META.get('HTTP_REFERER'):
            referrer = request.META['HTTP_REFERER']
            if SOURCE_URL_RE.match(referrer):
                statsd.incr('news.views.subscribe_main.use_referrer')
                data['source_url'] = referrer

        if is_ratelimited(request, group='basket.news.views.subscribe_main',
                          key=lambda x, y: '%s-%s' % (':'.join(data['newsletters']), data['email']),
                          rate=EMAIL_SUBSCRIBE_RATE_LIMIT, increment=True):
            statsd.incr('subscribe.ratelimited')
            return respond_error(request, form, 'Rate limit reached', 429)

        try:
            upsert_user.delay(SUBSCRIBE, data, start_time=time())
        except Exception:
            return respond_error(request, form, 'Unknown error', 500)

        return respond_ok(request, data)

    else:
        # form is invalid
        if request.is_ajax():
            return HttpResponseJSON({
                'status': 'error',
                'errors': format_form_errors(form.errors),
                'errors_by_field': form.errors,
            }, 400)
        else:
            return render(request, 'news/formerror.html', {'form': form}, status=400)
Ejemplo n.º 7
0
def subscribe(request):
    data = request.POST.dict()
    newsletters = data.get("newsletters", None)
    if not newsletters:
        # request.body causes tests to raise exceptions
        # while request.read() works.
        raw_request = request.read().decode()
        if "newsletters=" in raw_request:
            # malformed request from FxOS
            # Can't use QueryDict since the string is not url-encoded.
            # It will convert '+' to ' ' for example.
            data = dict(
                pair.split("=") for pair in raw_request.split("&")
                if "=" in pair)
            statsd.incr("news.views.subscribe.fxos-workaround")
        else:
            return HttpResponseJSON(
                {
                    "status": "error",
                    "desc": "newsletters is missing",
                    "code": errors.BASKET_USAGE_ERROR,
                },
                400,
            )

    if "email" not in data:
        return HttpResponseJSON(
            {
                "status": "error",
                "desc": "email is required",
                "code": errors.BASKET_USAGE_ERROR,
            },
            401,
        )

    email = process_email(data["email"])
    if not email:
        return invalid_email_response()

    data["email"] = email

    if email_is_blocked(data["email"]):
        statsd.incr("news.views.subscribe.email_blocked")
        # don't let on there's a problem
        return HttpResponseJSON({"status": "ok"})

    optin = data.pop("optin", "N").upper() == "Y"
    sync = data.pop("sync", "N").upper() == "Y"

    authorized = False
    if optin or sync:
        if is_authorized(request, email):
            authorized = True

    if optin and not authorized:
        # for backward compat we just ignore the optin if
        # no valid API key is sent.
        optin = False

    if sync:
        if not authorized:
            return HttpResponseJSON(
                {
                    "status": "error",
                    "desc": "Using subscribe with sync=Y, you need to pass a "
                    "valid `api-key` or FxA OAuth Authorization.",
                    "code": errors.BASKET_AUTH_ERROR,
                },
                401,
            )

    # NOTE this is not a typo; Referrer is misspelled in the HTTP spec
    # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36
    if not data.get("source_url") and request.META.get("HTTP_REFERER"):
        # try to get it from referrer
        statsd.incr("news.views.subscribe.use_referrer")
        data["source_url"] = request.META["HTTP_REFERER"]

    return update_user_task(request,
                            SUBSCRIBE,
                            data=data,
                            optin=optin,
                            sync=sync)
Ejemplo n.º 8
0
def subscribe_main(request):
    """Subscription view for use with client side JS"""
    form = SubscribeForm(request.POST)
    if form.is_valid():
        data = form.cleaned_data

        if email_is_blocked(data["email"]):
            statsd.incr("news.views.subscribe_main.email_blocked")
            # don't let on there's a problem
            return respond_ok(request, data)

        data["format"] = data.pop("fmt") or "H"

        if data["lang"]:
            if not language_code_is_valid(data["lang"]):
                data["lang"] = "en"
        # if lang not provided get the best one from the accept-language header
        else:
            lang = get_best_request_lang(request)
            if lang:
                data["lang"] = lang
            else:
                del data["lang"]

        # now ensure that if we do have a lang that it's a supported one
        if "lang" in data:
            data["lang"] = get_best_supported_lang(data["lang"])

        # if source_url not provided we should store the referrer header
        # NOTE this is not a typo; Referrer is misspelled in the HTTP spec
        # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36
        if not data["source_url"] and request.META.get("HTTP_REFERER"):
            referrer = request.META["HTTP_REFERER"]
            if SOURCE_URL_RE.match(referrer):
                statsd.incr("news.views.subscribe_main.use_referrer")
                data["source_url"] = referrer

        if is_ratelimited(
                request,
                group="basket.news.views.subscribe_main",
                key=lambda x, y: "%s-%s" %
            (":".join(data["newsletters"]), data["email"]),
                rate=EMAIL_SUBSCRIBE_RATE_LIMIT,
                increment=True,
        ):
            statsd.incr("subscribe.ratelimited")
            return respond_error(request, form, "Rate limit reached", 429)

        try:
            upsert_user.delay(SUBSCRIBE, data, start_time=time())
        except Exception:
            return respond_error(request, form, "Unknown error", 500)

        return respond_ok(request, data)

    else:
        # form is invalid
        if request.is_ajax():
            return HttpResponseJSON(
                {
                    "status": "error",
                    "errors": format_form_errors(form.errors),
                    "errors_by_field": form.errors,
                },
                400,
            )
        else:
            return render(request,
                          "news/formerror.html", {"form": form},
                          status=400)
Ejemplo n.º 9
0
def get_involved(request):
    data = request.POST.dict()
    if "email" not in data:
        return HttpResponseJSON(
            {
                "status": "error",
                "desc": "email is required",
                "code": errors.BASKET_USAGE_ERROR,
            },
            401,
        )
    if email_is_blocked(data["email"]):
        # don't let on there's a problem
        return HttpResponseJSON({"status": "ok"})
    if "interest_id" not in data:
        return HttpResponseJSON(
            {
                "status": "error",
                "desc": "interest_id is required",
                "code": errors.BASKET_USAGE_ERROR,
            },
            401,
        )

    try:
        Interest.objects.get(interest_id=data["interest_id"])
    except Interest.DoesNotExist:
        return HttpResponseJSON(
            {
                "status": "error",
                "desc": "invalid interest_id",
                "code": errors.BASKET_USAGE_ERROR,
            },
            401,
        )

    if "lang" not in data:
        return HttpResponseJSON(
            {
                "status": "error",
                "desc": "lang is required",
                "code": errors.BASKET_USAGE_ERROR,
            },
            401,
        )
    if not language_code_is_valid(data["lang"]):
        return HttpResponseJSON(
            {
                "status": "error",
                "desc": "invalid language",
                "code": errors.BASKET_INVALID_LANGUAGE,
            },
            400,
        )
    if "name" not in data:
        return HttpResponseJSON(
            {
                "status": "error",
                "desc": "name is required",
                "code": errors.BASKET_USAGE_ERROR,
            },
            401,
        )
    if "country" not in data:
        return HttpResponseJSON(
            {
                "status": "error",
                "desc": "country is required",
                "code": errors.BASKET_USAGE_ERROR,
            },
            401,
        )

    email = process_email(data.get("email"))
    if not email:
        return invalid_email_response()

    update_get_involved.delay(
        data["interest_id"],
        data["lang"],
        data["name"],
        email,
        data["country"],
        data.get("format", "H"),
        data.get("subscribe", False),
        data.get("message", None),
        data.get("source_url", None),
    )
    return HttpResponseJSON({"status": "ok"})
Ejemplo n.º 10
0
Archivo: views.py Proyecto: pmac/basket
def subscribe(request):
    data = request.POST.dict()
    newsletters = data.get('newsletters', None)
    if not newsletters:
        # request.body causes tests to raise exceptions
        # while request.read() works.
        raw_request = request.read()
        if 'newsletters=' in raw_request:
            # malformed request from FxOS
            # Can't use QueryDict since the string is not url-encoded.
            # It will convert '+' to ' ' for example.
            data = dict(pair.split('=') for pair in raw_request.split('&') if '=' in pair)
            statsd.incr('news.views.subscribe.fxos-workaround')
        else:
            return HttpResponseJSON({
                'status': 'error',
                'desc': 'newsletters is missing',
                'code': errors.BASKET_USAGE_ERROR,
            }, 400)

    if 'email' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'email is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)

    email = process_email(data['email'])
    if not email:
        return invalid_email_response()

    data['email'] = email

    if email_is_blocked(data['email']):
        statsd.incr('news.views.subscribe.email_blocked')
        # don't let on there's a problem
        return HttpResponseJSON({'status': 'ok'})

    optin = data.pop('optin', 'N').upper() == 'Y'
    sync = data.pop('sync', 'N').upper() == 'Y'

    if optin and not has_valid_api_key(request):
        # for backward compat we just ignore the optin if
        # no valid API key is sent.
        optin = False

    if sync:
        if not has_valid_api_key(request):
            return HttpResponseJSON({
                'status': 'error',
                'desc': 'Using subscribe with sync=Y, you need to pass a '
                        'valid `api-key` GET or POST parameter or X-api-key header',
                'code': errors.BASKET_AUTH_ERROR,
            }, 401)

    # NOTE this is not a typo; Referrer is misspelled in the HTTP spec
    # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36
    if not data.get('source_url') and request.META.get('HTTP_REFERER'):
        # try to get it from referrer
        statsd.incr('news.views.subscribe.use_referrer')
        data['source_url'] = request.META['HTTP_REFERER']

    return update_user_task(request, SUBSCRIBE, data=data, optin=optin, sync=sync)
Ejemplo n.º 11
0
Archivo: views.py Proyecto: pmac/basket
def get_involved(request):
    data = request.POST.dict()
    if 'email' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'email is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)
    if email_is_blocked(data['email']):
        # don't let on there's a problem
        return HttpResponseJSON({'status': 'ok'})
    if 'interest_id' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'interest_id is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)

    try:
        Interest.objects.get(interest_id=data['interest_id'])
    except Interest.DoesNotExist:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'invalid interest_id',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)

    if 'lang' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'lang is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)
    if not language_code_is_valid(data['lang']):
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'invalid language',
            'code': errors.BASKET_INVALID_LANGUAGE,
        }, 400)
    if 'name' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'name is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)
    if 'country' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'country is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)

    email = process_email(data.get('email'))
    if not email:
        return invalid_email_response()

    update_get_involved.delay(
        data['interest_id'],
        data['lang'],
        data['name'],
        email,
        data['country'],
        data.get('format', 'H'),
        data.get('subscribe', False),
        data.get('message', None),
        data.get('source_url', None),
    )
    return HttpResponseJSON({'status': 'ok'})
Ejemplo n.º 12
0
def subscribe(request):
    data = request.POST.dict()
    newsletters = data.get('newsletters', None)
    if not newsletters:
        # request.body causes tests to raise exceptions
        # while request.read() works.
        raw_request = request.read()
        if 'newsletters=' in raw_request:
            # malformed request from FxOS
            # Can't use QueryDict since the string is not url-encoded.
            # It will convert '+' to ' ' for example.
            data = dict(pair.split('=') for pair in raw_request.split('&') if '=' in pair)
            statsd.incr('news.views.subscribe.fxos-workaround')
        else:
            return HttpResponseJSON({
                'status': 'error',
                'desc': 'newsletters is missing',
                'code': errors.BASKET_USAGE_ERROR,
            }, 400)

    if 'email' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'email is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)

    email = process_email(data['email'])
    if not email:
        return invalid_email_response()

    data['email'] = email

    if email_is_blocked(data['email']):
        statsd.incr('news.views.subscribe.email_blocked')
        # don't let on there's a problem
        return HttpResponseJSON({'status': 'ok'})

    optin = data.pop('optin', 'N').upper() == 'Y'
    sync = data.pop('sync', 'N').upper() == 'Y'

    authorized = False
    if optin or sync:
        if is_authorized(request, email):
            authorized = True

    if optin and not authorized:
        # for backward compat we just ignore the optin if
        # no valid API key is sent.
        optin = False

    if sync:
        if not authorized:
            return HttpResponseJSON({
                'status': 'error',
                'desc': 'Using subscribe with sync=Y, you need to pass a '
                        'valid `api-key` or FxA OAuth Authorization.',
                'code': errors.BASKET_AUTH_ERROR,
            }, 401)

    # NOTE this is not a typo; Referrer is misspelled in the HTTP spec
    # https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.36
    if not data.get('source_url') and request.META.get('HTTP_REFERER'):
        # try to get it from referrer
        statsd.incr('news.views.subscribe.use_referrer')
        data['source_url'] = request.META['HTTP_REFERER']

    return update_user_task(request, SUBSCRIBE, data=data, optin=optin, sync=sync)
Ejemplo n.º 13
0
def get_involved(request):
    data = request.POST.dict()
    if 'email' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'email is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)
    if email_is_blocked(data['email']):
        # don't let on there's a problem
        return HttpResponseJSON({'status': 'ok'})
    if 'interest_id' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'interest_id is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)

    try:
        Interest.objects.get(interest_id=data['interest_id'])
    except Interest.DoesNotExist:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'invalid interest_id',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)

    if 'lang' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'lang is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)
    if not language_code_is_valid(data['lang']):
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'invalid language',
            'code': errors.BASKET_INVALID_LANGUAGE,
        }, 400)
    if 'name' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'name is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)
    if 'country' not in data:
        return HttpResponseJSON({
            'status': 'error',
            'desc': 'country is required',
            'code': errors.BASKET_USAGE_ERROR,
        }, 401)

    email = process_email(data.get('email'))
    if not email:
        return invalid_email_response()

    update_get_involved.delay(
        data['interest_id'],
        data['lang'],
        data['name'],
        email,
        data['country'],
        data.get('format', 'H'),
        data.get('subscribe', False),
        data.get('message', None),
        data.get('source_url', None),
    )
    return HttpResponseJSON({'status': 'ok'})