def send_emails(self, recipients):
        """Send the emails using the templates and contexts requested."""
        email_subject = self.options['subject']
        email_sender = self.options['sender']
        txt_template = loader.get_template(self.options['template'])
        context = ast.literal_eval(self.options['context'])
        email_txt = txt_template.render(context)

        emails_sent_count = 0
        messages = []
        for recipient in recipients:
            messages.append((
                email_subject,
                email_txt,
                email_sender,
                [recipient],
            ))
            emails_sent_count += 1

        if not self.options['simulate']:
            send_mass_mail(messages, fail_silently=False)
            tally_stat('pr.emails.sent', inc=emails_sent_count)
            logger.info("Sent %s pr emails." % emails_sent_count)
        else:
            sys.stdout.write('Simulation mode. Imagine that we just sent %s '
                             'emails!\n' % emails_sent_count)
Exemple #2
0
def mapper_homepage(request):
    if not is_bot(request):
        tally_stat('visualization.scotus_homepage_loaded')

    visualizations = SCOTUSMap.objects.filter(
        published=True,
        deleted=False,
    ).annotate(
        Count('clusters'),
    ).filter(
        # Ensures that we only show good stuff on homepage
        clusters__count__gt=10,
    ).order_by(
        '-date_published',
        '-date_modified',
        '-date_created',
    )[:2]

    return render_to_response(
        'visualization_home.html',
        {
            'visualizations': visualizations,
            'private': False,
        },
        RequestContext(request),
    )
Exemple #3
0
    def send_emails(self, recipients):
        """Send the emails using the templates and contexts requested."""
        email_subject = self.options['subject']
        email_sender = self.options['sender']
        txt_template = loader.get_template(self.options['template'])
        context = ast.literal_eval(self.options['context'])
        email_txt = txt_template.render(context)

        emails_sent_count = 0
        messages = []
        for recipient in recipients:
            messages.append((
                email_subject,
                email_txt,
                email_sender,
                [recipient],
            ))
            emails_sent_count += 1

        if not self.options['simulate']:
            send_mass_mail(messages, fail_silently=False)
            tally_stat('pr.emails.sent', inc=emails_sent_count)
            logger.info("Sent %s pr emails." % emails_sent_count)
        else:
            sys.stdout.write('Simulation mode. Imagine that we just sent %s '
                             'emails!\n' % emails_sent_count)
Exemple #4
0
def serve_pagerank_file(request):
    """Serves the bulk pagerank file from the bulk data directory."""
    file_loc = settings.BULK_DATA_DIR + "external_pagerank"
    file_name = file_loc.split('/')[-1]
    try:
        mimetype = magic.from_file(file_loc, mime=True)
    except IOError:
        raise Http404('Unable to locate external_pagerank file in %s' % settings.BULK_DATA_DIR)
    response = HttpResponse()
    response['X-Sendfile'] = os.path.join(file_loc)
    response['Content-Disposition'] = 'attachment; filename="%s"' % file_name.encode('utf-8')
    response['Content-Type'] = mimetype
    tally_stat('bulk_data.pagerank.served')
    return response
Exemple #5
0
def serve_pagerank_file(request):
    """Serves the bulk pagerank file from the bulk data directory."""
    file_loc = settings.BULK_DATA_DIR + "external_pagerank"
    file_name = file_loc.split('/')[-1]
    try:
        mimetype = magic.from_file(file_loc, mime=True)
    except IOError:
        raise Http404('Unable to locate external_pagerank file in %s' %
                      settings.BULK_DATA_DIR)
    response = HttpResponse()
    response['X-Sendfile'] = os.path.join(file_loc)
    response[
        'Content-Disposition'] = 'attachment; filename="%s"' % file_name.encode(
            'utf-8')
    response['Content-Type'] = mimetype
    tally_stat('bulk_data.pagerank.served')
    return response
Exemple #6
0
def serve_static_file(request, file_path=''):
    """Sends a static file to a user.

    This serves up the static case files such as the PDFs in a way that can be
    blocked from search engines if necessary. We do four things:
     - Look up the document  or audio file associated with the filepath
     - Check if it's blocked
     - If blocked, we set the x-robots-tag HTTP header
     - Serve up the file using Apache2's xsendfile
    """
    response = HttpResponse()
    file_loc = os.path.join(settings.MEDIA_ROOT, file_path.encode('utf-8'))
    if file_path.startswith('mp3'):
        item = get_object_or_404(Audio, local_path_mp3=file_path)
        mimetype = 'audio/mpeg'
    elif file_path.startswith('recap'):
        # Create an empty object, and set it to blocked. No need to hit the DB
        # since all RECAP documents are blocked.
        item = RECAPDocument()
        item.blocked = True
        mimetype = 'application/pdf'
    else:
        item = get_object_or_404(Opinion, local_path=file_path)
        item.blocked = item.cluster.blocked
        try:
            mimetype = magic.from_file(file_loc, mime=True)
        except IOError:
            raise Http404

    if item.blocked:
        response['X-Robots-Tag'] = 'noindex, noodp, noarchive, noimageindex'

    if settings.DEVELOPMENT:
        # X-Sendfile will only confuse you in a dev env.
        response.content = open(file_loc, 'r').read()
    else:
        response['X-Sendfile'] = file_loc
    file_name = file_path.split('/')[-1]
    response['Content-Disposition'] = 'attachment; filename="%s"' % \
                                      file_name.encode('utf-8')
    response['Content-Type'] = mimetype
    if not is_bot(request):
        tally_stat('case_page.static_file.served')
    return response
Exemple #7
0
class Command(BaseCommand):
    help = 'Sends the alert emails on a real time, daily, weekly or monthly ' \
           'basis.'

    def __init__(self, *args, **kwargs):
        super(Command, self).__init__(*args, **kwargs)
        self.connections = {
            'o': sunburnt.SolrInterface(settings.SOLR_OPINION_URL, mode='r'),
            'oa': sunburnt.SolrInterface(settings.SOLR_AUDIO_URL, mode='r'),
        }
        self.options = {}
        self.valid_ids = {}

    def add_arguments(self, parser):
        parser.add_argument(
            '--rate',
            required=True,
            choices=dict(FREQUENCY).keys(),
            help="The rate to send emails (%s)" %
            ', '.join(dict(FREQUENCY).keys()),
        )
        parser.add_argument(
            '--simulate',
            action='store_true',
            default=False,
            help='Simulate the emails that would be sent using the console '
            'backend.',
        )

    def run_query(self, alert, rate):
        results = []
        error = False
        cd = {}
        try:
            logger.info("Now running the query: %s\n" % alert.query)

            # Set up the data
            data = search_utils.get_string_to_dict(alert.query)
            try:
                del data['filed_before']
            except KeyError:
                pass
            data['order_by'] = 'score desc'
            logger.info("  Data sent to SearchForm is: %s\n" % data)
            search_form = SearchForm(data)
            if search_form.is_valid():
                cd = search_form.cleaned_data

                if rate == 'rt' and len(self.valid_ids[cd['type']]) == 0:
                    # Bail out. No results will be found if no valid_ids.
                    return error, cd['type'], results

                cut_off_date = get_cut_off_date(rate)
                if cd['type'] == 'o':
                    cd['filed_after'] = cut_off_date
                elif cd['type'] == 'oa':
                    cd['argued_after'] = cut_off_date
                main_params = search_utils.build_main_query(cd)
                main_params.update({
                    'rows': '20',
                    'start': '0',
                    'hl.tag.pre': '<em><strong>',
                    'hl.tag.post': '</strong></em>',
                    'caller': 'cl_send_alerts',
                })
                if rate == 'rt':
                    main_params['fq'].append(
                        'id:(%s)' % ' OR '.join(
                            [str(i) for i in self.valid_ids[cd['type']]]), )
                results = self.connections[cd['type']].raw_query(
                    **main_params).execute()
            else:
                logger.info("  Query for alert %s was invalid\n"
                            "  Errors from the SearchForm: %s\n" %
                            (alert.query, search_form.errors))
                error = True
        except:
            traceback.print_exc()
            logger.info("  Search for this alert failed: %s\n" % alert.query)
            error = True

        logger.info("  There were %s results\n" % len(results))

        return error, cd.get('type'), results

    def send_emails(self, rate):
        """Send out an email to every user whose alert has a new hit for a
        rate.
        """
        users = User.objects.filter(alerts__rate=rate, ).distinct()

        alerts_sent_count = 0
        for user in users:
            alerts = user.alerts.filter(rate=rate)
            logger.info("\n\nAlerts for user '%s': %s\n"
                        "%s\n" % (user, alerts, '*' * 40))

            not_donated_enough = user.profile.total_donated_last_year < \
                settings.MIN_DONATION['rt_alerts']
            if not_donated_enough and rate == 'rt':
                logger.info('\n\nUser: %s has not donated enough for their %s '
                            'RT alerts to be sent.\n' % (user, len(alerts)))
                continue

            hits = []
            for alert in alerts:
                error, alert_type, results = self.run_query(alert, rate)
                if error:
                    continue

                # hits is a multi-dimensional array. It consists of alerts,
                # paired with a list of document dicts, of the form:
                # [[alert1, [{hit1}, {hit2}, {hit3}]], [alert2, ...]]
                try:
                    if len(results) > 0:
                        hits.append([alert, alert_type, results])
                        alert.date_last_hit = now()
                        alert.save()
                    # elif len(results) == 0 and alert.always_send_email:
                    #     hits.append([alert, alert_type, None])
                    #     logger.info("  Sending results for negative alert "
                    #                 "'%s'\n" % alert.name)
                except Exception, e:
                    traceback.print_exc()
                    logger.info("  Search failed on this alert: %s\n%s\n" %
                                (alert.query, e))

            if len(hits) > 0:
                alerts_sent_count += 1
                send_alert(user.profile, hits, self.options['simulate'])
            elif self.options['verbosity'] >= 1:
                logger.info("  No hits. Not sending mail for this cl.\n")

        if not self.options['simulate']:
            tally_stat('alerts.sent.%s' % rate, inc=alerts_sent_count)
            logger.info("Sent %s %s email alerts." % (alerts_sent_count, rate))
Exemple #8
0
def show_results(request):
    """
    This view can vary significantly, depending on how it is called:
     - In its most simple form, it is called via GET and without any
       parameters.
        --> This loads the homepage.
     - It might also be called with GET *with* parameters.
        --> This loads search results.
     - It might be called with a POST.
        --> This attempts to save an alert.

    It also has a few failure modes it needs to support:
     - It must react properly to an invalid alert form.
     - It must react properly to an invalid or failing search form.

    All of these paths have tests.
    """
    # Create a search string that does not contain the page numbers
    get_string = search_utils.make_get_string(request)
    get_string_sans_alert = search_utils.make_get_string(
        request, ['page', 'edit_alert'])
    render_dict = {
        'private': True,
        'get_string': get_string,
        'get_string_sans_alert': get_string_sans_alert,
    }

    if request.method == 'POST':
        # The user is trying to save an alert.
        alert_form = CreateAlertForm(request.POST, user=request.user)
        if alert_form.is_valid():
            cd = alert_form.cleaned_data

            # save the alert
            if request.POST.get('edit_alert'):
                # check if the user can edit this, or if they are url hacking
                alert = get_object_or_404(
                    Alert,
                    pk=request.POST.get('edit_alert'),
                    user=request.user,
                )
                alert_form = CreateAlertForm(cd,
                                             instance=alert,
                                             user=request.user)
                alert_form.save()
                action = "edited"
            else:
                alert_form = CreateAlertForm(cd, user=request.user)
                alert = alert_form.save(commit=False)
                alert.user = request.user
                alert.save()

                action = "created"
            messages.add_message(request, messages.SUCCESS,
                                 'Your alert was %s successfully.' % action)

            # and redirect to the alerts page
            return HttpResponseRedirect(reverse("profile_alerts"))
        else:
            # Invalid form. Do the search again and show them the alert form
            # with the errors
            render_dict.update(do_search(request))
            render_dict.update({'alert_form': alert_form})
            return render_to_response(
                'search.html',
                render_dict,
                RequestContext(request),
            )

    else:
        # Either a search or the homepage
        if len(request.GET) == 0:
            # No parameters --> Homepage.
            if not is_bot(request):
                tally_stat('search.homepage_loaded')

            # Load the render_dict with good results that can be shown in the
            # "Latest Cases" section
            render_dict.update(
                do_search(request, rows=5, order_by='dateFiled desc'))
            # Get the results from the oral arguments as well
            oa_dict = do_search(request,
                                rows=5,
                                order_by='dateArgued desc',
                                type='oa')
            render_dict.update({'results_oa': oa_dict['results']})
            # But give it a fresh form for the advanced search section
            render_dict.update({'search_form': SearchForm(request.GET)})
            ten_days_ago = make_aware(datetime.today() - timedelta(days=10),
                                      utc)
            alerts_in_last_ten = Stat.objects.filter(
                name__contains='alerts.sent',
                date_logged__gte=ten_days_ago).aggregate(
                    Sum('count'))['count__sum']
            queries_in_last_ten = Stat.objects.filter(
                name='search.results',
                date_logged__gte=ten_days_ago).aggregate(
                    Sum('count'))['count__sum']
            bulk_in_last_ten = Stat.objects.filter(
                name__contains='bulk_data',
                date_logged__gte=ten_days_ago).aggregate(
                    Sum('count'))['count__sum']
            r = redis.StrictRedis(
                host=settings.REDIS_HOST,
                port=settings.REDIS_PORT,
                db=settings.REDIS_DATABASES['STATS'],
            )
            last_ten_days = [
                'api:v3.d:%s.count' %
                (date.today() - timedelta(days=x)).isoformat()
                for x in range(0, 10)
            ]
            api_in_last_ten = sum([
                int(result) for result in r.mget(*last_ten_days)
                if result is not None
            ])
            users_in_last_ten = User.objects.filter(
                date_joined__gte=ten_days_ago).count()
            opinions_in_last_ten = Opinion.objects.filter(
                date_created__gte=ten_days_ago).count()
            oral_arguments_in_last_ten = Audio.objects.filter(
                date_created__gte=ten_days_ago).count()
            days_of_oa = naturalduration(
                Audio.objects.aggregate(Sum('duration'))['duration__sum'],
                as_dict=True,
            )['d']
            viz_in_last_ten = SCOTUSMap.objects.filter(
                date_published__gte=ten_days_ago,
                published=True,
            ).count()
            visualizations = SCOTUSMap.objects.filter(
                published=True,
                deleted=False,
            ).annotate(Count('clusters'), ).filter(
                # Ensures that we only show good stuff on homepage
                clusters__count__gt=10, ).order_by(
                    '-date_published',
                    '-date_modified',
                    '-date_created',
                )[:1]
            render_dict.update({
                'alerts_in_last_ten': alerts_in_last_ten,
                'queries_in_last_ten': queries_in_last_ten,
                'opinions_in_last_ten': opinions_in_last_ten,
                'oral_arguments_in_last_ten': oral_arguments_in_last_ten,
                'bulk_in_last_ten': bulk_in_last_ten,
                'api_in_last_ten': api_in_last_ten,
                'users_in_last_ten': users_in_last_ten,
                'days_of_oa': days_of_oa,
                'viz_in_last_ten': viz_in_last_ten,
                'visualizations': visualizations,
                'private': False,  # VERY IMPORTANT!
            })
            return render_to_response('homepage.html', render_dict,
                                      RequestContext(request))
        else:
            # User placed a search or is trying to edit an alert
            if request.GET.get('edit_alert'):
                # They're editing an alert
                if request.user.is_anonymous():
                    return HttpResponseRedirect(
                        "{path}?next={next}{encoded_params}".format(
                            path=reverse('sign-in'),
                            next=request.path,
                            encoded_params=quote("?" +
                                                 request.GET.urlencode())))
                else:
                    alert = get_object_or_404(Alert,
                                              pk=request.GET.get('edit_alert'),
                                              user=request.user)
                    alert_form = CreateAlertForm(
                        instance=alert,
                        initial={'query': get_string_sans_alert},
                        user=request.user,
                    )
            else:
                # Just a regular search
                if not is_bot(request):
                    tally_stat('search.results')

                # Create bare-bones alert form.
                alert_form = CreateAlertForm(initial={
                    'query': get_string,
                    'rate': "dly"
                },
                                             user=request.user)
            render_dict.update(do_search(request))
            render_dict.update({'alert_form': alert_form})
            return render_to_response(
                'search.html',
                render_dict,
                RequestContext(request),
            )
Exemple #9
0
def register(request):
    """allow only an anonymous user to register"""
    redirect_to = request.GET.get('next', '')
    if 'sign-in' in redirect_to:
        # thus, we don't redirect people back to the sign-in form
        redirect_to = ''

    # security checks:
    # Light security check -- make sure redirect_to isn't garbage.
    if not redirect_to or ' ' in redirect_to:
        redirect_to = settings.LOGIN_REDIRECT_URL

    # Heavier security check -- redirects to http://example.com should
    # not be allowed, but things like /view/?param=http://example.com
    # should be allowed. This regex checks if there is a '//' *before* a
    # question mark.
    elif '//' in redirect_to and re.match(r'[^\?]*//', redirect_to):
        redirect_to = settings.LOGIN_REDIRECT_URL

    if request.user.is_anonymous():
        if request.method == 'POST':
            try:
                stub_account = User.objects.filter(
                    profile__stub_account=True, ).get(
                        email__iexact=request.POST.get('email'), )
            except User.DoesNotExist:
                stub_account = False

            if stub_account:
                form = UserCreationFormExtended(request.POST,
                                                instance=stub_account)
            else:
                form = UserCreationFormExtended(request.POST)

            if form.is_valid():
                cd = form.cleaned_data
                if not stub_account:
                    # make a new user that is active, but has not confirmed
                    # their email address
                    user = User.objects.create_user(cd['username'],
                                                    cd['email'],
                                                    cd['password1'])
                    up = UserProfile(user=user)
                else:
                    # Upgrade the stub account to make it a regular account.
                    user = stub_account
                    user.set_password(cd['password1'])
                    user.username = cd['username']
                    up = stub_account.profile
                    up.stub_account = False

                if cd['first_name']:
                    user.first_name = cd['first_name']
                if cd['last_name']:
                    user.last_name = cd['last_name']
                user.save()

                # Build and assign the activation key
                salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
                up.activation_key = hashlib.sha1(salt +
                                                 user.username).hexdigest()
                up.key_expires = now() + timedelta(days=5)
                up.save()

                email = emails['confirm_your_new_account']
                send_mail(email['subject'],
                          email['body'] % (user.username, up.activation_key),
                          email['from'], [user.email])
                email = emails['new_account_created']
                send_mail(
                    email['subject'] % up.user.username,
                    email['body'] %
                    (up.user.get_full_name() or "Not provided", up.user.email),
                    email['from'],
                    email['to'],
                )
                tally_stat('user.created')
                return HttpResponseRedirect(
                    reverse('register_success') + '?next=%s' % redirect_to)
        else:
            form = UserCreationFormExtended()
        return render_to_response("register/register.html", {
            'form': form,
            'private': False
        }, RequestContext(request))
    else:
        # The user is already logged in. Direct them to their settings page as
        # a logical fallback
        return HttpResponseRedirect(reverse('view_settings'))
Exemple #10
0
def register(request):
    """allow only an anonymous user to register"""
    redirect_to = request.GET.get('next', '')
    if 'sign-in' in redirect_to:
        # thus, we don't redirect people back to the sign-in form
        redirect_to = ''

    # security checks:
    # Light security check -- make sure redirect_to isn't garbage.
    if not redirect_to or ' ' in redirect_to:
        redirect_to = settings.LOGIN_REDIRECT_URL

    # Heavier security check -- redirects to http://example.com should
    # not be allowed, but things like /view/?param=http://example.com
    # should be allowed. This regex checks if there is a '//' *before* a
    # question mark.
    elif '//' in redirect_to and re.match(r'[^\?]*//', redirect_to):
        redirect_to = settings.LOGIN_REDIRECT_URL

    if request.user.is_anonymous():
        if request.method == 'POST':
            try:
                stub_account = User.objects.filter(
                    profile__stub_account=True,
                ).get(
                    email__iexact=request.POST.get('email'),
                )
            except User.DoesNotExist:
                stub_account = False

            if stub_account:
                form = UserCreationFormExtended(
                    request.POST,
                    instance=stub_account
                )
            else:
                form = UserCreationFormExtended(request.POST)

            if form.is_valid():
                cd = form.cleaned_data
                if not stub_account:
                    # make a new user that is active, but has not confirmed
                    # their email address
                    user = User.objects.create_user(
                        cd['username'],
                        cd['email'],
                        cd['password1']
                    )
                    up = UserProfile(user=user)
                else:
                    # Upgrade the stub account to make it a regular account.
                    user = stub_account
                    user.set_password(cd['password1'])
                    user.username = cd['username']
                    up = stub_account.profile
                    up.stub_account = False

                if cd['first_name']:
                    user.first_name = cd['first_name']
                if cd['last_name']:
                    user.last_name = cd['last_name']
                user.save()

                # Build and assign the activation key
                salt = hashlib.sha1(str(random.random())).hexdigest()[:5]
                up.activation_key = hashlib.sha1(
                    salt + user.username).hexdigest()
                up.key_expires = now() + timedelta(days=5)
                up.save()

                email = emails['confirm_your_new_account']
                send_mail(
                    email['subject'],
                    email['body'] % (user.username, up.activation_key),
                    email['from'],
                    [user.email]
                )
                email = emails['new_account_created']
                send_mail(
                    email['subject'] % up.user.username,
                    email['body'] % (
                        up.user.get_full_name() or "Not provided",
                        up.user.email
                    ),
                    email['from'],
                    email['to'],
                )
                tally_stat('user.created')
                return HttpResponseRedirect(reverse('register_success') +
                                            '?next=%s' % redirect_to)
        else:
            form = UserCreationFormExtended()
        return render_to_response("register/register.html",
                                  {'form': form, 'private': False},
                                  RequestContext(request))
    else:
        # The user is already logged in. Direct them to their settings page as
        # a logical fallback
        return HttpResponseRedirect(reverse('view_settings'))
Exemple #11
0
def new_visualization(request):
    demo_viz = SCOTUSMap.objects.filter(
        published=True,
        deleted=False,
    ).annotate(
        Count('clusters'),
    ).filter(
        # Ensures that we only show good stuff on homepage
        clusters__count__gt=5,
        clusters__count__lt=15,
    ).order_by(
        '-date_published',
        '-date_modified',
        '-date_created',
    )[:1]

    context = {
        'SCDB_LATEST_CASE': settings.SCDB_LATEST_CASE.isoformat(),
        'demo_viz': demo_viz,
        'private': True,
    }
    if request.method == 'POST':
        form = VizForm(request.POST)
        context['form'] = form
        if form.is_valid():
            # Process the data in form.cleaned_data
            cd = form.cleaned_data
            start, end = reverse_endpoints_if_needed(cd['cluster_start'],
                                                     cd['cluster_end'])

            viz = SCOTUSMap(
                user=request.user,
                cluster_start=start,
                cluster_end=end,
                title=cd['title'],
                notes=cd['notes'],
            )

            build_kwargs = {
                'parent_authority': end,
                'visited_nodes': {},
                'good_nodes': {},
                'max_hops': 3,
            }
            t1 = time.time()
            try:
                g = viz.build_nx_digraph(**build_kwargs)
            except TooManyNodes:
                try:
                    # Try with fewer hops.
                    build_kwargs['max_hops'] = 2
                    g = viz.build_nx_digraph(**build_kwargs)
                    msg = message_dict['fewer_hops_delivered']
                    messages.add_message(request, msg['level'], msg['message'])
                except TooManyNodes:
                    # Still too many hops. Abort.
                    tally_stat('visualization.too_many_nodes_failure')
                    msg = message_dict['too_many_nodes']
                    messages.add_message(request, msg['level'], msg['message'])
                    return render_to_response(
                        'new_visualization.html',
                        context,
                        RequestContext(request),
                    )

            if len(g.edges()) == 0:
                tally_stat('visualization.too_few_nodes_failure')
                msg = message_dict['too_few_nodes']
                messages.add_message(request, msg['level'], msg['message'])
                return render_to_response(
                    'new_visualization.html',
                    {'form': form, 'private': True},
                    RequestContext(request),
                )

            t2 = time.time()
            viz.generation_time = t2 - t1

            viz.save()
            viz.add_clusters(g)
            j = viz.to_json(g)
            jv = JSONVersion(map=viz, json_data=j)
            jv.save()

            return HttpResponseRedirect(reverse(
                'view_visualization',
                kwargs={'pk': viz.pk, 'slug': viz.slug}
            ))
    else:
        context['form'] = VizForm()
    return render_to_response(
        'new_visualization.html',
        context,
        RequestContext(request),
    )
Exemple #12
0
def show_results(request):
    """
    This view can vary significantly, depending on how it is called:
     - In its most simple form, it is called via GET and without any
       parameters.
        --> This loads the homepage.
     - It might also be called with GET *with* parameters.
        --> This loads search results.
     - It might be called with a POST.
        --> This attempts to save an alert.

    It also has a few failure modes it needs to support:
     - It must react properly to an invalid alert form.
     - It must react properly to an invalid or failing search form.

    All of these paths have tests.
    """
    # Create a search string that does not contain the page numbers
    get_string = make_get_string(request)
    get_string_sans_alert = make_get_string(request, ['page', 'edit_alert'])
    render_dict = {
        'private': True,
        'get_string': get_string,
        'get_string_sans_alert': get_string_sans_alert,
    }

    if request.method == 'POST':
        # The user is trying to save an alert.
        alert_form = CreateAlertForm(request.POST, user=request.user)
        if alert_form.is_valid():
            cd = alert_form.cleaned_data

            # save the alert
            if request.POST.get('edit_alert'):
                # check if the user can edit this, or if they are url hacking
                alert = get_object_or_404(
                    Alert,
                    pk=request.POST.get('edit_alert'),
                    user=request.user,
                )
                alert_form = CreateAlertForm(cd, instance=alert,
                                             user=request.user)
                alert_form.save()
                action = "edited"
            else:
                alert_form = CreateAlertForm(cd, user=request.user)
                alert = alert_form.save(commit=False)
                alert.user = request.user
                alert.save()

                action = "created"
            messages.add_message(request, messages.SUCCESS,
                                 'Your alert was %s successfully.' % action)

            # and redirect to the alerts page
            return HttpResponseRedirect(reverse("profile_alerts"))
        else:
            # Invalid form. Do the search again and show them the alert form
            # with the errors
            render_dict.update(do_search(request))
            render_dict.update({'alert_form': alert_form})
            return render_to_response(
                'search.html',
                render_dict,
                RequestContext(request),
            )

    else:
        # Either a search or the homepage
        if len(request.GET) == 0:
            # No parameters --> Homepage.
            if not is_bot(request):
                tally_stat('search.homepage_loaded')

            # Load the render_dict with good results that can be shown in the
            # "Latest Cases" section
            render_dict.update(do_search(request, rows=5,
                                         order_by='dateFiled desc'))
            # Get the results from the oral arguments as well
            oa_dict = do_search(request, rows=5, order_by='dateArgued desc',
                                type='oa')
            render_dict.update({'results_oa': oa_dict['results']})
            # But give it a fresh form for the advanced search section
            render_dict.update({'search_form': SearchForm(request.GET)})

            # Get a bunch of stats.
            render_dict.update(get_homepage_stats())

            return render_to_response(
                'homepage.html',
                render_dict,
                RequestContext(request)
            )
        else:
            # User placed a search or is trying to edit an alert
            if request.GET.get('edit_alert'):
                # They're editing an alert
                if request.user.is_anonymous():
                    return HttpResponseRedirect(
                        "{path}?next={next}{encoded_params}".format(
                            path=reverse('sign-in'),
                            next=request.path,
                            encoded_params=quote("?" + request.GET.urlencode())
                        ))
                else:
                    alert = get_object_or_404(
                        Alert,
                        pk=request.GET.get('edit_alert'),
                        user=request.user
                    )
                    alert_form = CreateAlertForm(
                        instance=alert,
                        initial={'query': get_string_sans_alert},
                        user=request.user,
                    )
            else:
                # Just a regular search
                if not is_bot(request):
                    tally_stat('search.results')

                # Create bare-bones alert form.
                alert_form = CreateAlertForm(
                    initial={'query': get_string,
                             'rate': "dly"},
                    user=request.user
                )
            render_dict.update(do_search(request))
            render_dict.update({'alert_form': alert_form})
            return render_to_response(
                'search.html',
                render_dict,
                RequestContext(request),
            )
Exemple #13
0
def show_results(request):
    """
    This view can vary significantly, depending on how it is called:
     - In its most simple form, it is called via GET and without any
       parameters.
        --> This loads the homepage.
     - It might also be called with GET *with* parameters.
        --> This loads search results.
     - It might be called with a POST.
        --> This attempts to save an alert.

    It also has a few failure modes it needs to support:
     - It must react properly to an invalid alert form.
     - It must react properly to an invalid or failing search form.

    All of these paths have tests.
    """
    # Create a search string that does not contain the page numbers
    get_string = search_utils.make_get_string(request)
    get_string_sans_alert = search_utils.make_get_string(request, ['page', 'edit_alert'])
    render_dict = {
        'private': True,
        'get_string': get_string,
        'get_string_sans_alert': get_string_sans_alert,
    }

    if request.method == 'POST':
        # The user is trying to save an alert.
        alert_form = CreateAlertForm(request.POST, user=request.user)
        if alert_form.is_valid():
            cd = alert_form.cleaned_data

            # save the alert
            if request.POST.get('edit_alert'):
                # check if the user can edit this, or if they are url hacking
                alert = get_object_or_404(
                    Alert,
                    pk=request.POST.get('edit_alert'),
                    user=request.user,
                )
                alert_form = CreateAlertForm(cd, instance=alert,
                                             user=request.user)
                alert_form.save()
                action = "edited"
            else:
                alert_form = CreateAlertForm(cd, user=request.user)
                alert = alert_form.save(commit=False)
                alert.user = request.user
                alert.save()

                action = "created"
            messages.add_message(request, messages.SUCCESS,
                                 'Your alert was %s successfully.' % action)

            # and redirect to the alerts page
            return HttpResponseRedirect(reverse("profile_alerts"))
        else:
            # Invalid form. Do the search again and show them the alert form
            # with the errors
            render_dict.update(do_search(request))
            render_dict.update({'alert_form': alert_form})
            return render_to_response(
                'search.html',
                render_dict,
                RequestContext(request),
            )

    else:
        # Either a search or the homepage
        if len(request.GET) == 0:
            # No parameters --> Homepage.
            if not is_bot(request):
                tally_stat('search.homepage_loaded')

            # Load the render_dict with good results that can be shown in the
            # "Latest Cases" section
            render_dict.update(do_search(request, rows=5,
                                         order_by='dateFiled desc'))
            # Get the results from the oral arguments as well
            oa_dict = do_search(request, rows=5, order_by='dateArgued desc',
                                type='oa')
            render_dict.update({'results_oa': oa_dict['results']})
            # But give it a fresh form for the advanced search section
            render_dict.update({'search_form': SearchForm(request.GET)})
            ten_days_ago = make_aware(datetime.today() - timedelta(days=10), utc)
            alerts_in_last_ten = Stat.objects.filter(
                    name__contains='alerts.sent',
                    date_logged__gte=ten_days_ago
                ).aggregate(Sum('count'))['count__sum']
            queries_in_last_ten = Stat.objects.filter(
                    name='search.results',
                    date_logged__gte=ten_days_ago
                ).aggregate(Sum('count'))['count__sum']
            bulk_in_last_ten = Stat.objects.filter(
                    name__contains='bulk_data',
                    date_logged__gte=ten_days_ago
                ).aggregate(Sum('count'))['count__sum']
            r = redis.StrictRedis(
                host=settings.REDIS_HOST,
                port=settings.REDIS_PORT,
                db=settings.REDIS_DATABASES['STATS'],
            )
            last_ten_days = ['api:v3.d:%s.count' %
                             (date.today() - timedelta(days=x)).isoformat()
                             for x in range(0, 10)]
            api_in_last_ten = sum(
                [int(result) for result in
                 r.mget(*last_ten_days) if result is not None]
            )
            users_in_last_ten = User.objects.filter(
                    date_joined__gte=ten_days_ago
                ).count()
            opinions_in_last_ten = Opinion.objects.filter(
                    date_created__gte=ten_days_ago
                ).count()
            oral_arguments_in_last_ten = Audio.objects.filter(
                    date_created__gte=ten_days_ago
                ).count()
            days_of_oa = naturalduration(
                    Audio.objects.aggregate(
                        Sum('duration')
                    )['duration__sum'],
                    as_dict=True,
                )['d']
            viz_in_last_ten = SCOTUSMap.objects.filter(
                    date_published__gte=ten_days_ago,
                    published=True,
                ).count()
            visualizations = SCOTUSMap.objects.filter(
                published=True,
                deleted=False,
            ).annotate(
                Count('clusters'),
            ).filter(
                # Ensures that we only show good stuff on homepage
                clusters__count__gt=10,
            ).order_by(
                '-date_published',
                '-date_modified',
                '-date_created',
            )[:1]
            render_dict.update({
                'alerts_in_last_ten': alerts_in_last_ten,
                'queries_in_last_ten': queries_in_last_ten,
                'opinions_in_last_ten': opinions_in_last_ten,
                'oral_arguments_in_last_ten': oral_arguments_in_last_ten,
                'bulk_in_last_ten': bulk_in_last_ten,
                'api_in_last_ten': api_in_last_ten,
                'users_in_last_ten': users_in_last_ten,
                'days_of_oa': days_of_oa,
                'viz_in_last_ten': viz_in_last_ten,
                'visualizations': visualizations,
                'private': False,  # VERY IMPORTANT!
            })
            return render_to_response(
                'homepage.html',
                render_dict,
                RequestContext(request)
            )
        else:
            # User placed a search or is trying to edit an alert
            if request.GET.get('edit_alert'):
                # They're editing an alert
                if request.user.is_anonymous():
                    return HttpResponseRedirect(
                        "{path}?next={next}{encoded_params}".format(
                            path=reverse('sign-in'),
                            next=request.path,
                            encoded_params=quote("?" + request.GET.urlencode())
                        ))
                else:
                    alert = get_object_or_404(
                        Alert,
                        pk=request.GET.get('edit_alert'),
                        user=request.user
                    )
                    alert_form = CreateAlertForm(
                        instance=alert,
                        initial={'query': get_string_sans_alert},
                        user=request.user,
                    )
            else:
                # Just a regular search
                if not is_bot(request):
                    tally_stat('search.results')

                # Create bare-bones alert form.
                alert_form = CreateAlertForm(
                    initial={'query': get_string,
                             'rate': "dly"},
                    user=request.user
                )
            render_dict.update(do_search(request))
            render_dict.update({'alert_form': alert_form})
            return render_to_response(
                'search.html',
                render_dict,
                RequestContext(request),
            )