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)
Пример #2
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)
Пример #3
0
def send_docket_alert(d_pk: int, since: datetime) -> None:
    """Send an alert for a given docket

    :param d_pk: The docket PK that was modified
    :param since: If we run alerts, notify users about items *since* this time.
    :return: None
    """
    email_addresses = (User.objects.filter(
        docket_alerts__docket_id=d_pk).distinct().values_list("email",
                                                              flat=True))
    if not email_addresses:
        # Nobody subscribed to the docket.
        delete_redis_semaphore("ALERTS", make_alert_key(d_pk))
        return

    d = Docket.objects.get(pk=d_pk)
    new_des = DocketEntry.objects.filter(date_created__gte=since, docket=d)
    if new_des.count() == 0:
        # No new docket entries.
        delete_redis_semaphore("ALERTS", make_alert_key(d_pk))
        return

    # Notify every user that's subscribed to this alert.
    messages = make_alert_messages(d, new_des, email_addresses)
    connection = get_connection()
    connection.send_messages(messages)

    # Work completed. Tally, log, and clean up
    tally_stat("alerts.docket.alerts.sent", inc=len(email_addresses))
    DocketAlert.objects.filter(docket=d).update(date_last_hit=now())
    delete_redis_semaphore("ALERTS", make_alert_key(d_pk))
Пример #4
0
def send_docket_alert(d_pk, since):
    """Send an alert for a given docket

    :param d_pk: The docket PK that was modified
    :param since: If we run alerts, notify users about items *since* this time.
    :return: The dict that was passed in as data is simply passed through. The
    next task in the chain needs the same information.
    """
    email_addresses = User.objects.filter(
        docket_alerts__docket_id=d_pk, ).distinct().values_list('email',
                                                                flat=True)
    if email_addresses:
        # We have an alert for this docket. Proceed.
        docket = Docket.objects.get(pk=d_pk)
        new_des = DocketEntry.objects.filter(date_created__gte=since,
                                             docket=docket)

        if new_des.count() > 0:
            # Notify every user that's subscribed to this alert.
            case_name = trunc(best_case_name(docket), 100, ellipsis='...')
            subject_template = loader.get_template('docket_alert_subject.txt')
            subject = subject_template.render({
                'docket': docket,
                'count': new_des.count(),
                'case_name': case_name,
            }).strip()  # Remove newlines that editors can insist on adding.
            email_context = {'new_des': new_des, 'docket': docket}
            txt_template = loader.get_template('docket_alert_email.txt')
            html_template = loader.get_template('docket_alert_email.html')
            messages = []
            for email_address in email_addresses:
                msg = EmailMultiAlternatives(
                    subject=subject,
                    body=txt_template.render(email_context),
                    from_email=settings.DEFAULT_ALERTS_EMAIL,
                    to=[email_address],
                    headers={'X-Entity-Ref-ID': 'docket.alert:%s' % d_pk})
                html = html_template.render(email_context)
                msg.attach_alternative(html, "text/html")
                messages.append(msg)

            # Add a bcc to the first message in the list so that we get a copy.
            messages[0].bcc = ['*****@*****.**']
            connection = get_connection()
            connection.send_messages(messages)
            tally_stat('alerts.docket.alerts.sent', inc=len(email_addresses))

        DocketAlert.objects.filter(docket=docket).update(date_last_hit=now())

    # Work completed, clear the semaphor
    r = redis.StrictRedis(host=settings.REDIS_HOST,
                          port=settings.REDIS_PORT,
                          db=settings.REDIS_DATABASES['ALERTS'])
    r.delete(make_alert_key(d_pk))
Пример #5
0
def send_docket_alert(d_pk, since):
    """Send an alert for a given docket

    :param d_pk: The docket PK that was modified
    :param since: If we run alerts, notify users about items *since* this time.
    :return: None
    """
    email_addresses = (User.objects.filter(
        docket_alerts__docket_id=d_pk).distinct().values_list("email",
                                                              flat=True))
    if email_addresses:
        # We have an alert for this docket. Proceed.
        docket = Docket.objects.get(pk=d_pk)
        new_des = DocketEntry.objects.filter(date_created__gte=since,
                                             docket=docket)

        if new_des.count() > 0:
            # Notify every user that's subscribed to this alert.
            case_name = trunc(best_case_name(docket), 100, ellipsis="...")
            subject_template = loader.get_template("docket_alert_subject.txt")
            subject = subject_template.render({
                "docket": docket,
                "count": new_des.count(),
                "case_name": case_name,
            }).strip()  # Remove newlines that editors can insist on adding.
            email_context = {"new_des": new_des, "docket": docket}
            txt_template = loader.get_template("docket_alert_email.txt")
            html_template = loader.get_template("docket_alert_email.html")
            messages = []
            for email_address in email_addresses:
                msg = EmailMultiAlternatives(
                    subject=subject,
                    body=txt_template.render(email_context),
                    from_email=settings.DEFAULT_ALERTS_EMAIL,
                    to=[email_address],
                    headers={"X-Entity-Ref-ID": "docket.alert:%s" % d_pk},
                )
                html = html_template.render(email_context)
                msg.attach_alternative(html, "text/html")
                messages.append(msg)

            # Add a bcc to the first message in the list so that we get a copy.
            messages[0].bcc = ["*****@*****.**"]
            connection = get_connection()
            connection.send_messages(messages)
            tally_stat("alerts.docket.alerts.sent", inc=len(email_addresses))

        DocketAlert.objects.filter(docket=docket).update(date_last_hit=now())

    # Work completed, clear the semaphore
    r = make_redis_interface("ALERTS")
    r.delete(make_alert_key(d_pk))
Пример #6
0
    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("Running alerts for user '%s': %s" % (user, alerts))

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

            hits = []
            for alert in alerts:
                try:
                    qd, results = self.run_query(alert, rate)
                except:
                    traceback.print_exc()
                    logger.info(
                        "Search for this alert failed: %s\n" % alert.query
                    )
                    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, ...]]
                if len(results) > 0:
                    hits.append(
                        [alert, qd.get("type", SEARCH_TYPES.OPINION), results]
                    )
                    alert.query_run = qd.urlencode()
                    alert.date_last_hit = now()
                    alert.save()

            if len(hits) > 0:
                alerts_sent_count += 1
                send_alert(user.profile, hits)

        tally_stat("alerts.sent.%s" % rate, inc=alerts_sent_count)
        logger.info("Sent %s %s email alerts." % (alerts_sent_count, rate))
Пример #7
0
    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()
                except Exception as 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))
Пример #8
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
    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()
                except Exception as 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))
Пример #10
0
def financial_disclosures_fileserver(request, pk, slug, filepath):
    """Serve up the financial disclosure files."""
    response = HttpResponse()
    file_loc = os.path.join(settings.MEDIA_ROOT, filepath.encode('utf-8'))
    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
    filename = filepath.split('/')[-1]
    response['Content-Disposition'] = 'inline; filename="%s"' % \
                                      filename.encode('utf-8')
    response['Content-Type'] = magic.from_file(file_loc, mime=True)
    if not is_bot(request):
        tally_stat('financial_reports.static_file.served')
    return response
Пример #11
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
Пример #12
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'] = 'inline; 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
Пример #13
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(request, 'visualization_home.html', {
        'visualizations': visualizations,
        'private': False,
    })
Пример #14
0
    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("Running alerts for user '%s': %s" % (user, alerts))

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

            hits = []
            for alert in alerts:
                try:
                    qd, results = self.run_query(alert, rate)
                except:
                    traceback.print_exc()
                    logger.info("Search for this alert failed: %s\n" %
                                alert.query)
                    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, ...]]
                if len(results) > 0:
                    hits.append([alert, qd.get('type', 'o'), results])
                    alert.query_run = qd.urlencode()
                    alert.date_last_hit = now()
                    alert.save()

            if len(hits) > 0:
                alerts_sent_count += 1
                send_alert(user.profile, hits)

        tally_stat('alerts.sent.%s' % rate, inc=alerts_sent_count)
        logger.info("Sent %s %s email alerts." % (alerts_sent_count, rate))
Пример #15
0
def mapper_homepage(request: HttpRequest) -> HttpResponse:
    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(
        request,
        "visualization_home.html",
        {"visualizations": visualizations, "private": False},
    )
Пример #16
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(request, 'visualization_home.html', {
        'visualizations': visualizations,
        'private': False,
    })
Пример #17
0
def build_visualization(viz):
    """Use the start and end points to generate a visualization

    :param viz: A Visualization object to work on
    :return: A tuple of (status<str>, viz)
    """
    build_kwargs = {
        "parent_authority": viz.cluster_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)
        except TooManyNodes:
            # Still too many hops. Abort.
            tally_stat("visualization.too_many_nodes_failure")
            return "too_many_nodes", viz

    if len(g.edges()) == 0:
        tally_stat("visualization.too_few_nodes_failure")
        return "too_few_nodes", viz

    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 "success", viz
Пример #18
0
 def test_tally_a_stat(self):
     count = tally_stat("test")
     self.assertEqual(count, 1)
Пример #19
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(request, 'new_visualization.html', context)

            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(request, 'new_visualization.html', {
                    'form': form,
                    'private': True
                })

            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(request, 'new_visualization.html', context)
Пример #20
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(request, 'search.html', render_dict)

    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')

            # Ensure we get nothing from the future.
            request.GET = request.GET.copy()  # Makes it mutable
            request.GET['filed_before'] = date.today()

            # 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',
                                         facet=False))
            # Get the results from the oral arguments as well
            oa_dict = do_search(request, rows=5, order_by='dateArgued desc',
                                type='oa', facet=False)
            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(request, 'homepage.html', render_dict)
        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(request, 'search.html', render_dict)
Пример #21
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)

            consent_form = OptInConsentForm(request.POST)
            if form.is_valid() and consent_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')
                get_str = '?next=%s&email=%s' % (urlencode(redirect_to),
                                                 urlencode(user.email))
                return HttpResponseRedirect(reverse('register_success') +
                                            get_str)
        else:
            form = UserCreationFormExtended()
            consent_form = OptInConsentForm()
        return render(request, "register/register.html", {
            'form': form,
            'consent_form': consent_form,
            'private': False
        })
    else:
        # The user is already logged in. Direct them to their settings page as
        # a logical fallback
        return HttpResponseRedirect(reverse('view_settings'))
Пример #22
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(request, 'new_visualization.html', context)

            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(request, 'new_visualization.html', {
                    'form': form,
                    'private': True
                })

            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(request, 'new_visualization.html', context)
Пример #23
0
def register(request):
    """allow only an anonymous user to register"""
    redirect_to = sanitize_redirection(request)
    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)

            consent_form = OptInConsentForm(request.POST)
            if form.is_valid() and consent_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
                up.activation_key = sha1_activation_key(user.username)
                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')
                get_str = '?next=%s&email=%s' % (urlencode(redirect_to),
                                                 urlencode(user.email))
                return HttpResponseRedirect(reverse('register_success') +
                                            get_str)
        else:
            form = UserCreationFormExtended()
            consent_form = OptInConsentForm()
        return render(request, "register/register.html", {
            'form': form,
            'consent_form': consent_form,
            'private': False
        })
    else:
        # The user is already logged in. Direct them to their settings page as
        # a logical fallback
        return HttpResponseRedirect(reverse('view_settings'))
Пример #24
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", "show_alert_modal"])
    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.GET.copy()))
            render_dict.update({"alert_form": alert_form})
            return render(request, "search.html", render_dict)

    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")

            # Ensure we get nothing from the future.
            mutable_GET = request.GET.copy()  # Makes it mutable
            mutable_GET["filed_before"] = date.today()

            # Load the render_dict with good results that can be shown in the
            # "Latest Cases" section
            render_dict.update(
                do_search(
                    mutable_GET,
                    rows=5,
                    override_params={"order_by": "dateFiled desc"},
                    facet=False,
                    cache_key="homepage-data-o",
                ))
            # Get the results from the oral arguments as well
            render_dict.update({
                "results_oa":
                do_search(
                    mutable_GET,
                    rows=5,
                    override_params={
                        "order_by": "dateArgued desc",
                        "type": SEARCH_TYPES.ORAL_ARGUMENT,
                    },
                    facet=False,
                    cache_key="homepage-data-oa",
                )["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.
            stats = get_homepage_stats()
            render_dict.update(stats)

            return render(request, "homepage.html", render_dict)
        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.GET.copy()))
            # Set the value to the query as a convenience
            alert_form.fields["name"].widget.attrs["value"] = render_dict[
                "search_summary_str"]
            render_dict.update({"alert_form": alert_form})
            return render(request, "search.html", render_dict)
Пример #25
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(request, 'search.html', render_dict)

    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')

            # Ensure we get nothing from the future.
            request.GET = request.GET.copy()  # Makes it mutable
            request.GET['filed_before'] = date.today()

            homepage_cache_key = 'homepage-data'
            homepage_dict = cache.get(homepage_cache_key)
            if homepage_dict is not None:
                return render(request, 'homepage.html', homepage_dict)

            # 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',
                          facet=False))
            # Get the results from the oral arguments as well
            oa_dict = do_search(request,
                                rows=5,
                                order_by='dateArgued desc',
                                type='oa',
                                facet=False)
            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())

            six_hours = 60 * 60 * 6
            cache.set(homepage_cache_key, render_dict, six_hours)
            return render(request, 'homepage.html', render_dict)
        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))
            # Set the value to the query as a convenience
            alert_form.fields['name'].widget.attrs['value'] = \
                render_dict['search_summary_str']
            render_dict.update({'alert_form': alert_form})
            return render(request, 'search.html', render_dict)
Пример #26
0
 def test_increment_by_two(self):
     count = tally_stat('test3', inc=2)
     self.assertEqual(count, 2)
     count = tally_stat('test3', inc=2)
     self.assertEqual(count, 4)
Пример #27
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(request, "register/register.html", {
            'form': form,
            'private': False
        })
    else:
        # The user is already logged in. Direct them to their settings page as
        # a logical fallback
        return HttpResponseRedirect(reverse('view_settings'))
Пример #28
0
 def test_increment_a_stat(self):
     count = tally_stat('test2')
     self.assertEqual(count, 1)
     count = tally_stat('test2')
     self.assertEqual(count, 2)
Пример #29
0
 def test_tally_a_stat(self):
     count = tally_stat('test')
     self.assertEqual(count, 1)
Пример #30
0
def register(request: HttpRequest) -> HttpResponse:
    """allow only an anonymous user to register"""
    redirect_to = get_redirect_or_login_url(request, "next")
    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)

            consent_form = OptInConsentForm(request.POST)
            if form.is_valid() and consent_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
                up.activation_key = sha1_activation_key(user.username)
                up.key_expires = now() + timedelta(days=5)
                up.save()

                email: EmailType = emails["confirm_your_new_account"]
                send_mail(
                    email["subject"],
                    email["body"] % (user.username, up.activation_key),
                    email["from_email"],
                    [user.email],
                )
                email: EmailType = 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"],
                    email["to"],
                )
                tally_stat("user.created")
                get_str = "?next=%s&email=%s" % (
                    urlencode(redirect_to),
                    urlencode(user.email),
                )
                return HttpResponseRedirect(
                    reverse("register_success") + get_str)
        else:
            form = UserCreationFormExtended()
            consent_form = OptInConsentForm()
        return render(
            request,
            "register/register.html",
            {
                "form": form,
                "consent_form": consent_form,
                "private": False
            },
        )
    else:
        # The user is already logged in. Direct them to their settings page as
        # a logical fallback
        return HttpResponseRedirect(reverse("view_settings"))
Пример #31
0
 def test_increment_a_stat(self):
     count = tally_stat("test2")
     self.assertEqual(count, 1)
     count = tally_stat("test2")
     self.assertEqual(count, 2)
Пример #32
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(request, "new_visualization.html", context)

            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(
                    request,
                    "new_visualization.html",
                    {
                        "form": form,
                        "private": True
                    },
                )

            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(request, "new_visualization.html", context)
Пример #33
0
 def test_increment_by_two(self):
     count = tally_stat("test3", inc=2)
     self.assertEqual(count, 2)
     count = tally_stat("test3", inc=2)
     self.assertEqual(count, 4)
Пример #34
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': ExtraSolrInterface(settings.SOLR_OPINION_URL, mode='r'),
            'oa': ExtraSolrInterface(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, facet=False)
                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']].query().add_extra(
                    **main_params).execute()
                regroup_snippets(results)

            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()
                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))