Ejemplo n.º 1
0
def new_user_view(request, template=None):
    if request.user.is_anonymous():
        # This is the AnonymousUser and they shouldn't be here
        # so push them to the dashboard.
        return HttpResponseRedirect(reverse('dashboard'))

    try:
        # If they have a profile, then this doesn't throw an error
        # and we can let them see the new user view again, but it's
        # not particularly interesting.
        request.user.profile
    except Profile.DoesNotExist:
        # They aren't anonymous and don't have a profile, so create
        # a profile for them.
        #
        # We could do more with this, but we're not at the moment.
        Profile.objects.create(user=request.user)

    next_url = request.GET.get('next', reverse('dashboard'))
    if not is_safe_url(next_url):
        next_url = reverse('dashboard')

    return render(request, template, {
        'next_url': next_url,
    })
Ejemplo n.º 2
0
    def login_success(self):
        """Send to new-user-view if new user, otherwise send on their way"""
        response = super(FjordVerify, self).login_success()
        # If this user has never logged in before, send them to our
        # super secret "Welcome!" page.
        try:
            self.user.profile
            return response

        except Profile.DoesNotExist:
            url = reverse('new-user-view')

            redirect_to = self.request.REQUEST.get('next')

            # Do not accept redirect URLs pointing to a different host.
            if redirect_to:
                netloc = urlparse.urlparse(redirect_to).netloc
                if netloc and netloc != self.request.get_host():
                    redirect_to = None

            if redirect_to:
                url = url + '?next=' + redirect_to

            return JSONResponse({
                'email': self.user.email,
                'redirect': url,
            })
Ejemplo n.º 3
0
 def _requires_firefox(request, *args, **kwargs):
     # Note: This is sort of a lie. What's going on here is that
     # parse_ua only parses Firefox-y browsers. So if it's UNKNOWN
     # at this point, then it's not Firefox-y. If parse_ua ever
     # changes, then this will cease to be true.
     if request.BROWSER.browser == UNKNOWN:
         return HttpResponseRedirect(reverse('download-firefox'))
     return func(request, *args, **kwargs)
Ejemplo n.º 4
0
 def _requires_firefox(request, *args, **kwargs):
     # Note: This is sort of a lie. What's going on here is that
     # parse_ua only parses Firefox-y browsers. So if it's UNKNOWN
     # at this point, then it's not Firefox-y. If parse_ua ever
     # changes, then this will cease to be true.
     if request.BROWSER.browser == UNKNOWN:
         return HttpResponseRedirect(reverse('download-firefox'))
     return func(request, *args, **kwargs)
Ejemplo n.º 5
0
    def _wrapped_view(request, *args, **kwargs):
        # Do this here to avoid circular imports
        from fjord.base.models import Profile

        try:
            request.user.profile
        except AttributeError:
            pass
        except Profile.DoesNotExist:
            url = reverse('new-user-view') + '?next=' + request.path
            return HttpResponseRedirect(url)

        return fun(request, *args, **kwargs)
Ejemplo n.º 6
0
    def _wrapped_view(request, *args, **kwargs):
        # Do this here to avoid circular imports
        from fjord.base.models import Profile

        try:
            request.user.profile
        except AttributeError:
            pass
        except Profile.DoesNotExist:
            url = reverse('new-user-view') + '?next=' + request.path
            return HttpResponseRedirect(url)

        return fun(request, *args, **kwargs)
Ejemplo n.º 7
0
def generate_dashboard_url(request, output_format='atom',
                                viewname='dashboard'):
    """For a given request, generates the dashboard url for the given format"""
    qd = request.GET.copy()

    # Remove anything from the querystring that isn't good for a feed:
    # page, start_date, end_date, etc.
    for mem in qd.keys():
        if mem not in ('happy', 'locale', 'platform', 'product',
                       'version', 'q'):
            del qd[mem]

    qd['format'] = output_format

    return reverse(viewname) + '?' + qd.urlencode()
Ejemplo n.º 8
0
def spot_translate(request, responseid):
    # FIXME: This is gengo-machine specific for now.
    resp = get_object_or_404(Response, id=responseid)
    system = request.POST.get('system', None)
    total_jobs = 0
    if system and system in get_translation_systems():
        total_jobs += len(create_translation_tasks(resp, system=system))

    # FIXME: If there's no system specified, we should tell the user
    # something. I'm going to defer fixing that for now since the user
    # would have to be doing "sneaky" things to hit that situation.

    messages.success(request,
                     '%s %s translation jobs added' % (total_jobs, system))
    return HttpResponseRedirect(reverse('response_view', args=(responseid, )))
Ejemplo n.º 9
0
def spot_translate(request, responseid):
    # FIXME: This is gengo-machine specific for now.
    resp = get_object_or_404(Response, id=responseid)
    system = request.POST.get('system', None)
    total_jobs = 0
    if system and system in get_translation_systems():
        total_jobs += len(create_translation_tasks(resp, system=system))

    # FIXME: If there's no system specified, we should tell the user
    # something. I'm going to defer fixing that for now since the user
    # would have to be doing "sneaky" things to hit that situation.

    messages.success(request, '%s %s translation jobs added' % (
        total_jobs, system))
    return HttpResponseRedirect(
        reverse('response_view', args=(responseid,)))
Ejemplo n.º 10
0
def generate_dashboard_url(request, output_format='atom',
                           viewname='dashboard'):
    """For a given request, generates the dashboard url for the given format

    """
    qd = request.GET.copy()

    # Remove anything from the querystring that isn't good for a feed:
    # page, start_date, end_date, etc.
    for mem in qd.keys():
        if mem not in ('happy', 'locale', 'platform', 'product',
                       'version', 'q'):
            del qd[mem]

    qd['format'] = output_format

    return reverse(viewname) + '?' + qd.urlencode()
Ejemplo n.º 11
0
def generate_atom_feed(request, search):
    """Generates ATOM feed for first 100 results"""
    search_query = request.GET.get('q', None)

    if search_query:
        title = _(u'Firefox Input: {query}').format(query=search_query)
    else:
        title = _(u'Firefox Input')

    # Build the non-atom dashboard url and maintain all the
    # querystring stuff we have
    dashboard_url = request.build_absolute_uri()
    dashboard_url = dashboard_url.replace('format=atom', '')
    dashboard_url = dashboard_url.replace('&&', '&')
    if dashboard_url.endswith(('?', '&')):
        dashboard_url = dashboard_url[:-1]

    feed = Atom1FeedWithRelatedLinks(
        title=title,
        link=dashboard_url,
        description=_('Search Results From Firefox Input'),
        author_name=_('Firefox Input'),
    )
    for response in search[:100]:
        categories = {
            'sentiment': _('Happy') if response.happy else _('Sad'),
            'platform': response.platform,
            'locale': response.locale
        }
        categories = (':'.join(item) for item in categories.items())

        link_url = reverse('response_view', args=(response.id,))
        link_url = request.build_absolute_uri(link_url)

        feed.add_item(
            title=_('Response id: {id}').format(id=response.id),
            description=response.description,
            link=link_url,
            pubdate=response.created,
            categories=categories,
            link_related=response.url_domain,
        )
    return HttpResponse(
        feed.writeString('utf-8'), content_type='application/atom+xml')
Ejemplo n.º 12
0
def generate_atom_feed(request, search):
    """Generates ATOM feed for first 100 results"""
    search_query = request.GET.get('q', None)

    if search_query:
        title = _(u'Firefox Input: {query}').format(query=search_query)
    else:
        title = _(u'Firefox Input')

    # Build the non-atom dashboard url and maintain all the
    # querystring stuff we have
    dashboard_url = request.build_absolute_uri()
    dashboard_url = dashboard_url.replace('format=atom', '')
    dashboard_url = dashboard_url.replace('&&', '&')
    if dashboard_url.endswith(('?', '&')):
        dashboard_url = dashboard_url[:-1]

    feed = Atom1FeedWithRelatedLinks(
        title=title,
        link=dashboard_url,
        description=_('Search Results From Firefox Input'),
        author_name=_('Firefox Input'),
    )
    for response in search[:100]:
        categories = {
            'sentiment': _('Happy') if response.happy else _('Sad'),
            'platform': response.platform,
            'locale': response.locale
        }
        categories = (':'.join(item) for item in categories.items())

        link_url = reverse('response_view', args=(response.id, ))
        link_url = request.build_absolute_uri(link_url)

        feed.add_item(
            title=_('Response id: {id}').format(id=response.id),
            description=response.description,
            link=link_url,
            pubdate=response.created,
            categories=categories,
            link_related=response.url_domain,
        )
    return HttpResponse(feed.writeString('utf-8'),
                        content_type='application/atom+xml')
Ejemplo n.º 13
0
def feedback_router(request, product_slug=None, version=None, channel=None,
                    *args, **kwargs):
    """Figure out which flow to use for a product and route accordingly

    .. Note::

       1. We never want to cache this view

       2. Pages returned from this view will get an::

              X-Frame-Options: DENY

          HTTP header. That's important because these pages have magic
          powers and should never be used in frames. Please do not
          change this!

    """
    # The old Firefox for Android would POST form data to /feedback/. If we see
    # that, we fix the request up and then handle it as a feedback post.
    if '_type' in request.POST:
        request = fix_oldandroid(request)
        return _handle_feedback_post(request, request.locale)

    # FIXME - validate these better
    product_slug = smart_str(product_slug, fallback=None)
    version = smart_str(version)
    channel = smart_str(channel).lower()

    view_fun = get_config(product_slug)['view']

    if product_slug not in models.Product.objects.get_product_map():
        # If the product doesn't exist, redirect them to the picker.
        return HttpResponseRedirect(reverse('picker'))

    # Convert the product_slug to a product and send them on their way.
    product = models.Product.objects.from_slug(product_slug)
    return view_fun(request, request.locale, product, version, channel,
                    *args, **kwargs)
Ejemplo n.º 14
0
def feedback_router(request, product_slug=None, version=None, channel=None,
                    *args, **kwargs):
    """Figure out which flow to use for a product and route accordingly

    .. Note::

       1. We never want to cache this view

       2. Pages returned from this view will get an::

              X-Frame-Options: DENY

          HTTP header. That's important because these pages have magic
          powers and should never be used in frames. Please do not
          change this!

    """
    # The old Firefox for Android would POST form data to /feedback/. If we see
    # that, we fix the request up and then handle it as a feedback post.
    if '_type' in request.POST:
        request = fix_oldandroid(request)
        return _handle_feedback_post(request, request.locale)

    # FIXME - validate these better
    product_slug = smart_str(product_slug, fallback=None)
    version = smart_str(version)
    channel = smart_str(channel).lower()

    view_fun = get_config(product_slug)['view']

    if product_slug not in models.Product.objects.get_product_map():
        # If the product doesn't exist, redirect them to the picker.
        return HttpResponseRedirect(reverse('picker'))

    # Convert the product_slug to a product and send them on their way.
    product = models.Product.objects.from_slug(product_slug)
    return view_fun(request, request.locale, product, version, channel,
                    *args, **kwargs)
Ejemplo n.º 15
0
def url(viewname, *args, **kwargs):
    """Performs our localized reverse"""
    return reverse(viewname, args=args, kwargs=kwargs)
Ejemplo n.º 16
0
def sad_redirect(request):
    """Support older redirects from Input v1 era"""
    return HttpResponseRedirect(reverse('picker') + '?happy=0')
Ejemplo n.º 17
0
def _handle_feedback_post(request, locale=None, product=None,
                          version=None, channel=None):
    """Saves feedback post to db accounting for throttling

    :arg request: request we're handling the post for
    :arg locale: locale specified in the url
    :arg product: None or the Product
    :arg version: validated and sanitized version specified in the url
    :arg channel: validated and sanitized channel specified in the url

    """
    if getattr(request, 'limited', False):
        # If we're throttled, then return the thanks page, but don't
        # add the response to the db.
        return HttpResponseRedirect(reverse('thanks'))

    # Get the form and run is_valid() so it goes through the
    # validation and cleaning machinery. We don't really care if it's
    # valid, though, since we will take what we got and do the best we
    # can with it. Error validation is now in JS.
    form = ResponseForm(request.POST)
    form.is_valid()

    get_data = request.GET.copy()

    data = form.cleaned_data

    description = data.get('description', u'').strip()
    if not description:
        # If there's no description, then there's nothing to do here,
        # so thank the user and move on.
        return HttpResponseRedirect(reverse('thanks'))

    opinion = models.Response(
        # Data coming from the user
        happy=data['happy'],
        url=clean_url(data.get('url', u'').strip()),
        description=description,

        # Pulled from the form data or the url
        locale=data.get('locale', locale),

        # Data from mobile devices which is probably only
        # applicable to mobile devices
        manufacturer=data.get('manufacturer', ''),
        device=data.get('device', ''),
    )

    # Add user_agent and inferred data.
    user_agent = request.META.get('HTTP_USER_AGENT', '')
    if user_agent:
        browser = request.BROWSER

        opinion.user_agent = user_agent
        opinion.browser = browser.browser
        opinion.browser_version = browser.browser_version
        opinion.browser_platform = browser.platform
        if browser.platform == 'Windows':
            opinion.browser_platform += ' ' + browser.platform_version

    # source is src or utm_source
    source = (
        get_data.pop('src', [u''])[0] or
        get_data.pop('utm_source', [u''])[0]
    )
    if source:
        opinion.source = source[:100]

    campaign = get_data.pop('utm_campaign', [u''])[0]
    if campaign:
        opinion.campaign = campaign[:100]

    # If they sent "happy=1"/"happy=0" in the querystring, it will get
    # picked up by the javascript in the form and we can just drop it
    # here.
    get_data.pop('happy', None)

    platform = u''

    if product:
        # If we have a product at this point, then it came from the
        # url and it's a Product instance and we need to turn it into
        # the product.db_name which is a string.
        product_db_name = product.db_name
    else:
        # Check the POST data for the product.
        product_db_name = data.get('product', '')

    # For the version, we try the url data, then the POST data.
    version = version or data.get('version', '')

    # At this point, we have a bunch of values, but we might be
    # missing some values, too. We're going to cautiously infer data
    # from the user agent where we're very confident it's appropriate
    # to do so.
    if request.BROWSER != UNKNOWN:
        # If we don't have a product, try to infer that from the user
        # agent information.
        if not product_db_name:
            product_db_name = models.Response.infer_product(request.BROWSER)

        # If we have a product and it matches the user agent browser,
        # then we can infer the version and platform from the user
        # agent if they're missing.
        if product_db_name:
            product = models.Product.objects.get(db_name=product_db_name)
            if product.browser and product.browser == request.BROWSER.browser:
                if not version:
                    version = request.BROWSER.browser_version
                if not platform:
                    platform = models.Response.infer_platform(
                        product_db_name, request.BROWSER)

    # Make sure values are at least empty strings--no Nones.
    opinion.product = product_db_name or u''
    opinion.version = version or u''
    opinion.channel = channel or u''
    opinion.platform = platform or u''

    opinion.save()

    # If there was an email address, save that separately.
    if data.get('email_ok') and data.get('email'):
        e = models.ResponseEmail(email=data['email'], opinion=opinion)
        e.save()
        statsd.incr('feedback.emaildata.optin')

    # If there's browser data, save that separately.
    if data.get('browser_ok'):
        # This comes in as a JSON string. Because we're using
        # JSONObjectField, we need to convert it back to Python and
        # then save it. This is kind of silly, but it does guarantee
        # we have valid JSON.
        try:
            browser_data = data['browser_data']
            browser_data = json.loads(browser_data)

        except ValueError:
            # Handles empty string and any non-JSON value.
            statsd.incr('feedback.browserdata.badvalue')

        except KeyError:
            # Handles the case where it's missing from the data
            # dict. If it's missing, we don't want to do anything
            # including metrics.
            pass

        else:
            # If browser_data isn't an empty dict, then save it.
            if browser_data:
                rti = models.ResponsePI(
                    data=browser_data, opinion=opinion)
                rti.save()
                statsd.incr('feedback.browserdata.optin')

    if get_data:
        # There was extra context in the query string, so we grab that
        # with some restrictions and save it separately.
        slop = {}

        # We capture at most the first 20 key/val pairs
        get_data_items = sorted(get_data.items())[:20]

        for key, val in get_data_items:
            # Keys can be at most 20 characters long.
            key = key[:20]
            if len(val) == 1:
                val = val[0]

            # Values can be at most 20 characters long.
            val = val[:100]
            slop[key.encode('utf-8')] = val.encode('utf-8')

        context = models.ResponseContext(data=slop, opinion=opinion)
        context.save()
        statsd.incr('feedback.contextdata.optin')

    if data['happy']:
        statsd.incr('feedback.happy')
    else:
        statsd.incr('feedback.sad')

    request.session['response_id'] = opinion.id

    return HttpResponseRedirect(reverse('thanks'))
Ejemplo n.º 18
0
def sad_redirect(request):
    """Support older redirects from Input v1 era"""
    return HttpResponseRedirect(reverse('feedback') + '?happy=0')
Ejemplo n.º 19
0
 def test_locale(self):
     # Note: This depends on the 'about' view and the 'es'
     # locale. If we change those, then it breaks this test.
     assert reverse('about-view', locale='es') == '/es/about'
Ejemplo n.º 20
0
Archivo: base.py Proyecto: rlr/fjord
def build_redirect_url(redirect):
    return reverse('redirect-view') + '?' + urllib.urlencode({'r': redirect})
Ejemplo n.º 21
0
def sad_redirect(request):
    # TODO: Remove this when the addon gets fixed and is pointing to
    # the correct urls.
    return HttpResponseRedirect(reverse('feedback') + '#sad')
Ejemplo n.º 22
0
def url(viewname, *args, **kwargs):
    """Helper for Django's ``reverse`` in templates."""
    return reverse(viewname, args=args, kwargs=kwargs)
Ejemplo n.º 23
0
def build_redirect_url(redirect):
    return reverse("redirect-view") + "?" + urllib.urlencode({"r": redirect})
Ejemplo n.º 24
0
def _handle_feedback_post(request,
                          locale=None,
                          product=None,
                          version=None,
                          channel=None):
    """Saves feedback post to db accounting for throttling

    :arg request: request we're handling the post for
    :arg locale: locale specified in the url
    :arg product: None or the Product
    :arg version: validated and sanitized version specified in the url
    :arg channel: validated and sanitized channel specified in the url

    """
    if getattr(request, 'limited', False):
        # If we're throttled, then return the thanks page, but don't
        # add the response to the db.
        return HttpResponseRedirect(reverse('thanks'))

    # Get the form and run is_valid() so it goes through the
    # validation and cleaning machinery. We don't really care if it's
    # valid, though, since we will take what we got and do the best we
    # can with it. Error validation is now in JS.
    form = ResponseForm(request.POST)
    form.is_valid()

    get_data = request.GET.copy()

    data = form.cleaned_data

    description = data.get('description', u'').strip()
    if not description:
        # If there's no description, then there's nothing to do here,
        # so thank the user and move on.
        return HttpResponseRedirect(reverse('thanks'))

    opinion = models.Response(
        # Data coming from the user
        happy=data['happy'],
        url=clean_url(data.get('url', u'').strip()),
        description=description,

        # Pulled from the form data or the url
        locale=data.get('locale', locale),

        # Data from mobile devices which is probably only
        # applicable to mobile devices
        manufacturer=data.get('manufacturer', ''),
        device=data.get('device', ''),
    )

    # Add user_agent and inferred data.
    user_agent = request.META.get('HTTP_USER_AGENT', '')
    if user_agent:
        browser = request.BROWSER

        opinion.user_agent = user_agent
        opinion.browser = browser.browser
        opinion.browser_version = browser.browser_version
        opinion.browser_platform = browser.platform
        if browser.platform == 'Windows':
            opinion.browser_platform += ' ' + browser.platform_version

    # source is src or utm_source
    source = (get_data.pop('src', [u''])[0]
              or get_data.pop('utm_source', [u''])[0])
    if source:
        opinion.source = source[:100]

    campaign = get_data.pop('utm_campaign', [u''])[0]
    if campaign:
        opinion.campaign = campaign[:100]

    platform = u''

    if product:
        # If we have a product at this point, then it came from the
        # url and it's a Product instance and we need to turn it into
        # the product.db_name which is a string.
        product_db_name = product.db_name
    else:
        # Check the POST data for the product.
        product_db_name = data.get('product', '')

    # For the version, we try the url data, then the POST data.
    version = version or data.get('version', '')

    # At this point, we have a bunch of values, but we might be
    # missing some values, too. We're going to cautiously infer data
    # from the user agent where we're very confident it's appropriate
    # to do so.
    if request.BROWSER != UNKNOWN:
        # If we don't have a product, try to infer that from the user
        # agent information.
        if not product_db_name:
            product_db_name = models.Response.infer_product(request.BROWSER)

        # If we have a product and it matches the user agent browser,
        # then we can infer the version and platform from the user
        # agent if they're missing.
        if product_db_name:
            product = models.Product.objects.get(db_name=product_db_name)
            if product.browser and product.browser == request.BROWSER.browser:
                if not version:
                    version = request.BROWSER.browser_version
                if not platform:
                    platform = models.Response.infer_platform(
                        product_db_name, request.BROWSER)

    # Make sure values are at least empty strings--no Nones.
    opinion.product = product_db_name or u''
    opinion.version = version or u''
    opinion.channel = channel or u''
    opinion.platform = platform or u''

    opinion.save()

    # If there was an email address, save that separately.
    if data.get('email_ok') and data.get('email'):
        e = models.ResponseEmail(email=data['email'], opinion=opinion)
        e.save()
        statsd.incr('feedback.emaildata.optin')

    # If there's browser data, save that separately.
    if data.get('browser_ok'):
        # This comes in as a JSON string. Because we're using
        # JSONObjectField, we need to convert it back to Python and
        # then save it. This is kind of silly, but it does guarantee
        # we have valid JSON.
        try:
            browser_data = data['browser_data']
            browser_data = json.loads(browser_data)

        except ValueError:
            # Handles empty string and any non-JSON value.
            statsd.incr('feedback.browserdata.badvalue')

        except KeyError:
            # Handles the case where it's missing from the data
            # dict. If it's missing, we don't want to do anything
            # including metrics.
            pass

        else:
            # If browser_data isn't an empty dict, then save it.
            if browser_data:
                rti = models.ResponsePI(data=browser_data, opinion=opinion)
                rti.save()
                statsd.incr('feedback.browserdata.optin')

    if get_data:
        # There was extra context in the query string, so we grab that
        # with some restrictions and save it separately.
        slop = {}

        # We capture at most the first 20 key/val pairs
        get_data_items = sorted(get_data.items())[:20]

        for key, val in get_data_items:
            # Keys can be at most 20 characters long.
            key = key[:20]
            if len(val) == 1:
                val = val[0]

            # Values can be at most 20 characters long.
            val = val[:100]
            slop[key.encode('utf-8')] = val.encode('utf-8')

        context = models.ResponseContext(data=slop, opinion=opinion)
        context.save()
        statsd.incr('feedback.contextdata.optin')

    if data['happy']:
        statsd.incr('feedback.happy')
    else:
        statsd.incr('feedback.sad')

    request.session['opinion_id'] = opinion.id

    return HttpResponseRedirect(reverse('thanks'))
Ejemplo n.º 25
0
def sad_redirect(request):
    # TODO: Remove this when the addon gets fixed and is pointing to
    # the correct urls.
    return HttpResponseRedirect(reverse('feedback') + '#sad')
Ejemplo n.º 26
0
def happy_redirect(request):
    # TODO: Remove this when the addon gets fixed and is pointing to
    # the correct urls.
    return HttpResponseRedirect(reverse("feedback") + "#happy")
Ejemplo n.º 27
0
 def test_locale(self):
     # Note: This depends on the 'about' view and the 'es'
     # locale. If we change those, then it breaks this test.
     eq_(reverse('about-view', locale='es'), '/es/about')
Ejemplo n.º 28
0
def url(viewname, *args, **kwargs):
    """Helper for Django's ``reverse`` in templates."""
    return reverse(viewname, args=args, kwargs=kwargs)
Ejemplo n.º 29
0
def _handle_feedback_post(request, locale=None, product=None,
                          version=None, channel=None):
    """Saves feedback post to db accounting for throttling

    :arg request: request we're handling the post for
    :arg locale: locale specified in the url
    :arg product: validated and sanitized product slug specified in
        the url
    :arg version: validated and sanitized version specified in the url
    :arg channel: validated and sanitized channel specified in the url

    """
    if getattr(request, 'limited', False):
        # If we're throttled, then return the thanks page, but don't
        # add the response to the db.
        return HttpResponseRedirect(reverse('thanks'))

    # Get the form and run is_valid() so it goes through the
    # validation and cleaning machinery. We don't really care if it's
    # valid, though, since we will take what we got and do the best we
    # can with it. Error validation is now in JS.
    form = ResponseForm(request.POST)
    form.is_valid()

    get_data = request.GET.copy()

    data = form.cleaned_data
    description = data.get('description', u'').strip()
    if not description:
        # If there's no description, then there's nothing to do here,
        # so thank the user and move on.
        return HttpResponseRedirect(reverse('thanks'))

    # Do some data validation of product, channel and version
    # coming from the url.
    if product:
        # If there was a product in the url, that's a product slug, so
        # we map it to a db_name which is what we want to save to the
        # db.
        product = models.Product.get_product_map()[product]

    # src, then source, then utm_source
    source = get_data.pop('src', [u''])[0]
    if not source:
        source = get_data.pop('utm_source', [u''])[0]

    campaign = get_data.pop('utm_campaign', [u''])[0]

    # If the product came in on the url, then we only want to populate
    # the platfrom from the user agent data iff the product specified
    # by the url is the same as the browser product.
    platform = u''
    if product is None or product == request.BROWSER.browser:
        # Most platforms aren't different enough between versions to care.
        # Windows is.
        platform = request.BROWSER.platform
        if platform == 'Windows':
            platform += ' ' + request.BROWSER.platform_version

    product = product or u''

    opinion = models.Response(
        # Data coming from the user
        happy=data['happy'],
        url=clean_url(data.get('url', u'')),
        description=data['description'].strip(),

        # Inferred data from user agent
        user_agent=request.META.get('HTTP_USER_AGENT', ''),
        browser=request.BROWSER.browser,
        browser_version=request.BROWSER.browser_version,
        platform=platform,

        # Pulled from the form data or the url
        locale=data.get('locale', locale),

        # Data from mobile devices which is probably only
        # applicable to mobile devices
        manufacturer=data.get('manufacturer', ''),
        device=data.get('device', ''),
    )

    if source:
        opinion.source = source[:100]

    if campaign:
        opinion.campaign = campaign[:100]

    if product:
        # If we picked up the product from the url, we use url
        # bits for everything.
        product = product or u''
        version = version or u''
        channel = channel or u''

    elif opinion.browser != UNKNOWN:
        # If we didn't pick up a product from the url, then we
        # infer as much as we can from the user agent.
        product = data.get(
            'product', models.Response.infer_product(platform))
        version = data.get(
            'version', request.BROWSER.browser_version)
        # Assume everything we don't know about is stable channel.
        channel = u'stable'

    else:
        product = channel = version = u''

    opinion.product = product or u''
    opinion.version = version or u''
    opinion.channel = channel or u''

    opinion.save()

    # If there was an email address, save that separately.
    if data.get('email_ok') and data.get('email'):
        e = models.ResponseEmail(email=data['email'], opinion=opinion)
        e.save()

    if get_data:
        # There was extra context in the query string, so we grab that
        # with some restrictions and save it separately.
        slop = {}

        # We capture at most the first 20 key/val pairs
        get_data_items = sorted(get_data.items())[:20]

        for key, val in get_data_items:
            # Keys can be at most 20 characters long.
            key = key[:20]
            if len(val) == 1:
                val = val[0]

            # Values can be at most 20 characters long.
            val = val[:100]
            slop[key.encode('utf-8')] = val.encode('utf-8')

        context = models.ResponseContext(data=slop, opinion=opinion)
        context.save()

    if data['happy']:
        statsd.incr('feedback.happy')
    else:
        statsd.incr('feedback.sad')

    return HttpResponseRedirect(reverse('thanks'))
Ejemplo n.º 30
0
def happy_redirect(request):
    """Support older redirects from Input v1 era"""
    return HttpResponseRedirect(reverse('feedback') + '?happy=1')
Ejemplo n.º 31
0
def _handle_feedback_post(request, locale=None, product=None,
                          version=None, channel=None):
    """Saves feedback post to db accounting for throttling

    :arg request: request we're handling the post for
    :arg locale: locale specified in the url
    :arg product: None or the Product
    :arg version: validated and sanitized version specified in the url
    :arg channel: validated and sanitized channel specified in the url

    """
    if getattr(request, 'limited', False):
        # If we're throttled, then return the thanks page, but don't
        # add the response to the db.
        return HttpResponseRedirect(reverse('thanks'))

    # Get the form and run is_valid() so it goes through the
    # validation and cleaning machinery. We don't really care if it's
    # valid, though, since we will take what we got and do the best we
    # can with it. Error validation is now in JS.
    form = ResponseForm(request.POST)
    form.is_valid()

    get_data = request.GET.copy()

    data = form.cleaned_data

    description = data.get('description', u'').strip()
    if not description:
        # If there's no description, then there's nothing to do here,
        # so thank the user and move on.
        return HttpResponseRedirect(reverse('thanks'))

    opinion = models.Response(
        # Data coming from the user
        happy=data['happy'],
        url=clean_url(data.get('url', u'')),
        description=description,

        # Pulled from the form data or the url
        locale=data.get('locale', locale),

        # Data from mobile devices which is probably only
        # applicable to mobile devices
        manufacturer=data.get('manufacturer', ''),
        device=data.get('device', ''),
    )

    # Add user_agent and inferred data.
    user_agent = request.META.get('HTTP_USER_AGENT', '')
    if user_agent:
        browser = request.BROWSER

        opinion.user_agent = user_agent
        opinion.browser = browser.browser
        opinion.browser_version = browser.browser_version
        opinion.browser_platform = browser.platform
        if browser.platform == 'Windows':
            opinion.browser_platform += ' ' + browser.platform_version

    # source is src or utm_source
    source = (
        get_data.pop('src', [u''])[0] or
        get_data.pop('utm_source', [u''])[0]
    )
    if source:
        opinion.source = source[:100]

    campaign = get_data.pop('utm_campaign', [u''])[0]
    if campaign:
        opinion.campaign = campaign[:100]

    platform = u''

    # Figure out product, version, channel and platform. We either get
    # them from the url, from the user_agent, or we don't set them at
    # all.
    if product:
        # If there was a product in the url, then we get a Product
        # instance as an argument and we want the db_name from that.
        product = product.db_name

        # FIXME: We should be able to "match" the product with the
        # user agent browser and if they're the same, then set
        # platform == browser_platform. However, it's tricky since
        # our "products" are "interesting".

    elif opinion.browser != UNKNOWN:
        # If we didn't pick up a product from the url, then we
        # infer as much as we can from the user agent.
        product = data.get(
            'product', models.Response.infer_product(opinion.browser_platform))
        version = data.get(
            'version', request.BROWSER.browser_version)
        # Assume everything we don't know about is stable channel.
        channel = u'stable'

    # Try to infer the platform from the product.
    if product and not platform:
        platform = models.Response.infer_platform(product, request.BROWSER)

    opinion.product = product or u''
    opinion.version = version or u''
    opinion.channel = channel or u''
    opinion.platform = platform or u''

    opinion.save()

    # If there was an email address, save that separately.
    if data.get('email_ok') and data.get('email'):
        e = models.ResponseEmail(email=data['email'], opinion=opinion)
        e.save()

    if get_data:
        # There was extra context in the query string, so we grab that
        # with some restrictions and save it separately.
        slop = {}

        # We capture at most the first 20 key/val pairs
        get_data_items = sorted(get_data.items())[:20]

        for key, val in get_data_items:
            # Keys can be at most 20 characters long.
            key = key[:20]
            if len(val) == 1:
                val = val[0]

            # Values can be at most 20 characters long.
            val = val[:100]
            slop[key.encode('utf-8')] = val.encode('utf-8')

        context = models.ResponseContext(data=slop, opinion=opinion)
        context.save()

    if data['happy']:
        statsd.incr('feedback.happy')
    else:
        statsd.incr('feedback.sad')

    return HttpResponseRedirect(reverse('thanks'))
Ejemplo n.º 32
0
def build_redirect_url(redirect):
    return reverse('redirect-view') + '?' + urllib.urlencode({'r': redirect})
Ejemplo n.º 33
0
 def test_no_locale(self):
     # Note: This depends on the 'about' view. If we change that,
     # then it breaks this test. But it seems silly to do a bunch
     # of work to set up a better less fragile test plus it's
     # unlikely we'll change the 'about' view.
     assert reverse('about-view') == '/en-US/about'
Ejemplo n.º 34
0
 def test_no_locale(self):
     # Note: This depends on the 'about' view. If we change that,
     # then it breaks this test. But it seems silly to do a bunch
     # of work to set up a better less fragile test plus it's
     # unlikely we'll change the 'about' view.
     eq_(reverse('about-view'), '/en-US/about')
Ejemplo n.º 35
0
def happy_redirect(request):
    """Support older redirects from Input v1 era"""
    return HttpResponseRedirect(reverse('picker') + '?happy=1')