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), )
def view_docket(request, pk, slug): docket = get_object_or_404(Docket, pk=pk) if not is_bot(request): with suppress_autotime(docket, ['date_modified']): cached_count = docket.view_count docket.view_count = F('view_count') + 1 docket.save() docket.view_count = cached_count + 1 try: fave = Favorite.objects.get(docket_id=docket.pk, user=request.user) except (ObjectDoesNotExist, TypeError): # Not favorited or anonymous user favorite_form = FavoriteForm( initial={ 'docket_id': docket.pk, 'name': trunc(best_case_name(docket), 100, ellipsis='...'), }) else: favorite_form = FavoriteForm(instance=fave) de_list = docket.docket_entries.all().prefetch_related('recap_documents') form = DocketEntryFilterForm(request.GET) if form.is_valid(): cd = form.cleaned_data if cd.get('entry_gte'): de_list = de_list.filter(entry_number__gte=cd['entry_gte']) if cd.get('entry_lte'): de_list = de_list.filter(entry_number__lte=cd['entry_lte']) if cd.get('filed_after'): de_list = de_list.filter(date_filed__gte=cd['filed_after']) if cd.get('filed_before'): de_list = de_list.filter(date_filed__lte=cd['filed_before']) if cd.get('order_by') == DocketEntryFilterForm.DESCENDING: de_list = de_list.order_by('-entry_number') paginator = Paginator(de_list, 100, orphans=5) page = request.GET.get('page') try: docket_entries = paginator.page(page) except PageNotAnInteger: docket_entries = paginator.page(1) except EmptyPage: docket_entries = paginator.page(paginator.num_pages) return render( request, 'view_docket.html', { 'docket': docket, 'parties': docket.parties.exists(), # Needed to show/hide parties tab. 'docket_entries': docket_entries, 'form': form, 'favorite_form': favorite_form, 'get_string': make_get_string(request), 'timezone': COURT_TIMEZONES.get(docket.court_id, 'US/Eastern'), 'private': docket.blocked, })
def view_opinion(request, pk, _): """Using the cluster ID, return the cluster of opinions. We also test if the cluster ID is a favorite for the user, and send data if needed. If it's a favorite, we send the bound form for the favorite so it can populate the form on the page. If it is not a favorite, we send the unbound form. """ # Look up the court, cluster, title and favorite information cluster = get_object_or_404(OpinionCluster, pk=pk) title = ", ".join([ s for s in [ trunc(best_case_name(cluster), 100, ellipsis="..."), cluster.citation_string, ] if s.strip() ]) has_downloads = False for sub_opinion in cluster.sub_opinions.all(): if sub_opinion.local_path or sub_opinion.download_url: has_downloads = True break get_string = make_get_string(request) try: fave = Favorite.objects.get(cluster_id=cluster.pk, user=request.user) except (ObjectDoesNotExist, TypeError): # Not favorited or anonymous user favorite_form = FavoriteForm( initial={ "cluster_id": cluster.pk, "name": trunc(best_case_name(cluster), 100, ellipsis="..."), }) else: favorite_form = FavoriteForm(instance=fave) citing_clusters = get_citing_clusters_with_cache(cluster, is_bot(request)) return render( request, "view_opinion.html", { "title": title, "cluster": cluster, "has_downloads": has_downloads, "favorite_form": favorite_form, "get_string": get_string, "private": cluster.blocked, "citing_clusters": citing_clusters, "top_authorities": cluster.authorities_with_data[:5], "authorities_count": len(cluster.authorities_with_data), }, )
def view_docket(request, pk, _): docket = get_object_or_404(Docket, pk=pk) if not is_bot(request): docket.view_count = F('view_count') + 1 docket.save() try: fave = Favorite.objects.get(docket_id=docket.pk, user=request.user) except (ObjectDoesNotExist, TypeError): # Not favorited or anonymous user favorite_form = FavoriteForm( initial={ 'docket_id': docket.pk, 'name': trunc(best_case_name(docket), 100, ellipsis='...'), }) else: favorite_form = FavoriteForm(instance=fave) de_list = docket.docket_entries.all() form = DocketEntryFilterForm(request.GET) if form.is_valid(): cd = form.cleaned_data if cd.get('entry_gte'): de_list = de_list.filter(entry_number__gte=cd['entry_gte']) if cd.get('entry_lte'): de_list = de_list.filter(entry_number__lte=cd['entry_lte']) if cd.get('filed_after'): de_list = de_list.filter(date_filed__gte=cd['filed_after']) if cd.get('filed_before'): de_list = de_list.filter(date_filed__lte=cd['filed_before']) if cd.get('order_by') == DocketEntryFilterForm.DESCENDING: de_list = de_list.order_by('-entry_number') paginator = Paginator(de_list, 500, orphans=25) page = request.GET.get('page') try: docket_entries = paginator.page(page) except PageNotAnInteger: docket_entries = paginator.page(1) except EmptyPage: docket_entries = paginator.page(paginator.num_pages) return render( request, 'view_docket.html', { 'docket': docket, 'docket_entries': docket_entries, 'form': form, 'favorite_form': favorite_form, 'get_string': make_get_string(request), 'private': docket.blocked, })
def view_docket(request, pk, _): docket = get_object_or_404(Docket, pk=pk) if not is_bot(request): docket.view_count = F('view_count') + 1 docket.save() try: fave = Favorite.objects.get(docket_id=docket.pk, user=request.user) except (ObjectDoesNotExist, TypeError): # Not favorited or anonymous user favorite_form = FavoriteForm(initial={ 'docket_id': docket.pk, 'name': trunc(best_case_name(docket), 100, ellipsis='...'), }) else: favorite_form = FavoriteForm(instance=fave) de_list = docket.docket_entries.all() form = DocketEntryFilterForm(request.GET) if form.is_valid(): cd = form.cleaned_data if cd.get('entry_gte'): de_list = de_list.filter(entry_number__gte=cd['entry_gte']) if cd.get('entry_lte'): de_list = de_list.filter(entry_number__lte=cd['entry_lte']) if cd.get('filed_after'): de_list = de_list.filter(date_filed__gte=cd['filed_after']) if cd.get('filed_before'): de_list = de_list.filter(date_filed__lte=cd['filed_before']) if cd.get('order_by') == DocketEntryFilterForm.DESCENDING: de_list = de_list.order_by('-entry_number') paginator = Paginator(de_list, 500, orphans=25) page = request.GET.get('page') try: docket_entries = paginator.page(page) except PageNotAnInteger: docket_entries = paginator.page(1) except EmptyPage: docket_entries = paginator.page(paginator.num_pages) return render(request, 'view_docket.html', { 'docket': docket, 'docket_entries': docket_entries, 'form': form, 'favorite_form': favorite_form, 'get_string': make_get_string(request), 'private': docket.blocked, })
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
def wrapper(*args, **kwargs): t1 = time.time() result = f(*args, **kwargs) # Run the view t2 = time.time() if settings.DEVELOPMENT: # Disable tracking during development. return result request = args[0] # Request is always first arg. if check_bots and is_bot(request): return result url = request.build_absolute_uri() referer = request.META.get("HTTP_REFERER", "") url_domain = tldextract.extract(url) ref_domain = tldextract.extract(referer) if url_domain == ref_domain: # Referer domain is same as current. Don't count b/c it'll be # caught by client-side Matomo tracker already. return result try: # See: https://developer.matomo.org/api-reference/tracking-api requests.get( settings.MATOMO_URL, timeout=timeout, params={ "idsite": settings.MATOMO_SITE_ID, "rec": 1, # Required but unexplained in docs. "url": url, "download": url, "apiv": 1, "urlref": referer, "ua": request.META.get("HTTP_USER_AGENT", ""), "gt_ms": int((t2 - t1) * 1000), # Milliseconds "send_image": 0, }, ) except RequestException: logger.debug( "Matomo tracking request had an error (likely " "timeout?) out for URL: %s" % url ) return result
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
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
def wrapper(*args, **kwargs): t1 = time.time() result = func(*args, **kwargs) # Run the view t2 = time.time() if settings.DEVELOPMENT: # Disable tracking during development. return result request = args[0] # Request is always first arg. if check_bots and is_bot(request): return result url = request.build_absolute_uri() referer = request.META.get('HTTP_REFERER', '') url_domain = tldextract.extract(url) ref_domain = tldextract.extract(referer) if url_domain == ref_domain: # Referer domain is same as current. Don't count b/c it'll be # caught by client-side Piwik tracker already. return result try: # See: https://developer.matomo.org/api-reference/tracking-api requests.get( settings.PIWIK_URL, timeout=timeout, verify=False, # Our Piwik has self-signed cert. params={ 'idsite': settings.PIWIK_SITE_ID, 'rec': 1, # Required but unexplained in docs. 'url': url, 'download': url, 'apiv': 1, 'urlref': referer, 'ua': request.META.get('HTTP_USER_AGENT', ''), 'gt_ms': int((t2 - t1) * 1000), # Milliseconds 'send_image': 0, }, ) except RequestException: logger.info("Piwik tracking request had an error (likely " "timeout?) out for URL: %s" % url) return result
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, })
def render_visualization_page(request, pk, embed): viz = get_object_or_404(SCOTUSMap, pk=pk) if not is_bot(request): cached_value = viz.view_count with suppress_autotime(viz, ["date_modified"]): viz.view_count = F("view_count") + 1 viz.save() # To get the new value, you either need to get the item from the DB a # second time, or just manipulate it manually.... viz.view_count = cached_value + 1 status = None if viz.deleted: status = statuses.HTTP_410_GONE else: if viz.published is False and viz.user != request.user: # Not deleted, private and not the owner status = statuses.HTTP_401_UNAUTHORIZED if embed: if all([viz.published is True, viz.deleted is False]): # Log the referer if it's set, and the item is live. referer_url = request.META.get("HTTP_REFERER") if referer_url is not None: referer, created = Referer.objects.get_or_create( url=referer_url, map_id=viz.pk, ) if created: # Spawn a task to try to get the title of the page. get_title.delay(referer.pk) template = "visualization_embedded.html" else: template = "visualization.html" return render(request, template, { "viz": viz, "private": True }, status=status)
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}, )
def view_docket(request, pk, slug): docket, context = core_docket_data(request, pk) if not is_bot(request): with suppress_autotime(docket, ['date_modified']): cached_count = docket.view_count docket.view_count = F('view_count') + 1 docket.save() docket.view_count = cached_count + 1 de_list = docket.docket_entries.all().prefetch_related('recap_documents') form = DocketEntryFilterForm(request.GET) if form.is_valid(): cd = form.cleaned_data if cd.get('entry_gte'): de_list = de_list.filter(entry_number__gte=cd['entry_gte']) if cd.get('entry_lte'): de_list = de_list.filter(entry_number__lte=cd['entry_lte']) if cd.get('filed_after'): de_list = de_list.filter(date_filed__gte=cd['filed_after']) if cd.get('filed_before'): de_list = de_list.filter(date_filed__lte=cd['filed_before']) if cd.get('order_by') == DocketEntryFilterForm.DESCENDING: de_list = de_list.order_by('-recap_sequence_number', '-entry_number') paginator = Paginator(de_list, 200, orphans=10) page = request.GET.get('page') try: docket_entries = paginator.page(page) except PageNotAnInteger: docket_entries = paginator.page(1) except EmptyPage: docket_entries = paginator.page(paginator.num_pages) context.update({ 'parties': docket.parties.exists(), # Needed to show/hide parties tab. 'docket_entries': docket_entries, 'form': form, 'get_string': search_utils.make_get_string(request), }) return render(request, 'view_docket.html', context)
def view_docket(request, pk, slug): docket, context = core_docket_data(request, pk) if not is_bot(request): with suppress_autotime(docket, ["date_modified"]): cached_count = docket.view_count docket.view_count = F("view_count") + 1 docket.save() docket.view_count = cached_count + 1 de_list = docket.docket_entries.all().prefetch_related("recap_documents") form = DocketEntryFilterForm(request.GET) if form.is_valid(): cd = form.cleaned_data if cd.get("entry_gte"): de_list = de_list.filter(entry_number__gte=cd["entry_gte"]) if cd.get("entry_lte"): de_list = de_list.filter(entry_number__lte=cd["entry_lte"]) if cd.get("filed_after"): de_list = de_list.filter(date_filed__gte=cd["filed_after"]) if cd.get("filed_before"): de_list = de_list.filter(date_filed__lte=cd["filed_before"]) if cd.get("order_by") == DocketEntryFilterForm.DESCENDING: de_list = de_list.order_by("-recap_sequence_number", "-entry_number") paginator = Paginator(de_list, 200, orphans=10) page = request.GET.get("page") try: docket_entries = paginator.page(page) except PageNotAnInteger: docket_entries = paginator.page(1) except EmptyPage: docket_entries = paginator.page(paginator.num_pages) context.update({ "parties": docket.parties.exists(), # Needed to show/hide parties tab. "docket_entries": docket_entries, "form": form, "get_string": make_get_string(request), }) return render(request, "view_docket.html", context)
def render_visualization_page(request, pk, embed): viz = get_object_or_404(SCOTUSMap, pk=pk) if not is_bot(request): cached_value = viz.view_count with suppress_autotime(viz, ['date_modified']): viz.view_count = F('view_count') + 1 viz.save() # To get the new value, you either need to get the item from the DB a # second time, or just manipulate it manually.... viz.view_count = cached_value + 1 status = None if viz.deleted: status = statuses.HTTP_410_GONE else: if viz.published is False and viz.user != request.user: # Not deleted, private and not the owner status = statuses.HTTP_401_UNAUTHORIZED if embed: if all([viz.published is True, viz.deleted is False]): # Log the referer if it's set, and the item is live. referer_url = request.META.get('HTTP_REFERER') if referer_url is not None: referer, created = Referer.objects.get_or_create( url=referer_url, map_id=viz.pk, ) if created: # Spawn a task to try to get the title of the page. get_title.delay(referer.pk) template = 'visualization_embedded.html' else: template = 'visualization.html' return render(request, template, { 'viz': viz, 'private': True }, status=status)
def increment_view_count(obj, request): """Increment the view count of an object in the DB Three tricks in this simple function: 1. If it's a robot viewing the page, don't increment. 2. Make sure not to update the "date_modified" fields. 3. Do this using an atomic DB query for performance and don't reload from the database after the increment (which would take another query). :param obj: A django object containing a view_count parameter :param request: A django request so we can detect if it's a bot :return: Nothing. The obj is passed by reference """ if not is_bot(request): cached_value = obj.view_count with suppress_autotime(obj, ["date_modified"]): obj.view_count = F("view_count") + 1 obj.save() # To get the new value, you either need to get the item from the DB a # second time, or just manipulate it manually.... obj.view_count = cached_value + 1
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)
def get_related_clusters_with_cache(cluster, request): """Use Solr to get related opinions with Solr-MoreLikeThis query :param cluster: The cluster we're targeting :param request: Request object for checking if user is permitted :return: Tuple[List, List, Dict] Related clusters, sub-opinion IDs and URL parameters """ # By default all statuses are included available_statuses = dict(DOCUMENT_STATUSES).values() url_search_params = {"stat_" + v: "on" for v in available_statuses} if is_bot(request): # If it is a bot or is not beta tester, return empty results return [], [], url_search_params conn = sunburnt.SolrInterface(settings.SOLR_OPINION_URL, mode="r") # Opinions that belong to the targeted cluster sub_opinion_ids = cluster.sub_opinions.values_list("pk", flat=True) # Use cache if enabled mlt_cache_key = "mlt-cluster:%s" % cluster.pk related_clusters = (caches["db_cache"].get(mlt_cache_key) if settings.RELATED_USE_CACHE else None) if related_clusters is None: # Cache is empty # Turn list of opinion IDs into list of Q objects sub_opinion_queries = [conn.Q(id=sub_id) for sub_id in sub_opinion_ids] # Take one Q object from the list sub_opinion_query = sub_opinion_queries.pop() # OR the Q object with the ones remaining in the list for item in sub_opinion_queries: sub_opinion_query |= item # Set MoreLikeThis parameters # (see https://lucene.apache.org/solr/guide/6_6/other-parsers.html#OtherParsers-MoreLikeThisQueryParser) mlt_params = { "fields": "text", "count": settings.RELATED_COUNT, "maxqt": settings.RELATED_MLT_MAXQT, "mintf": settings.RELATED_MLT_MINTF, "minwl": settings.RELATED_MLT_MINWL, "maxwl": settings.RELATED_MLT_MAXWL, "maxdf": settings.RELATED_MLT_MAXDF, } mlt_query = (conn.query(sub_opinion_query).mlt( **mlt_params).field_limit( fields=["id", "caseName", "absolute_url"])) if settings.RELATED_FILTER_BY_STATUS: # Filter results by status (e.g., Precedential) mlt_query = mlt_query.filter( status_exact=settings.RELATED_FILTER_BY_STATUS) # Update URL parameters accordingly url_search_params = { "stat_" + settings.RELATED_FILTER_BY_STATUS: "on" } mlt_res = mlt_query.execute() if mlt_res.more_like_this is not None: # Only a single sub opinion related_clusters = mlt_res.more_like_this.docs elif mlt_res.more_like_these is not None: # Multiple sub opinions # Get result list for each sub opinion sub_docs = [ sub_res.docs for sub_id, sub_res in mlt_res.more_like_these.items() ] # Merge sub results by interleaving # - exclude items that are sub opinions related_clusters = [ item for pair in zip(*sub_docs) for item in pair if item["id"] not in sub_opinion_ids ] # Limit number of results related_clusters = related_clusters[:settings.RELATED_COUNT] else: # No MLT results are available (this should not happen) related_clusters = [] cache.set(mlt_cache_key, related_clusters, settings.RELATED_CACHE_TIMEOUT) return related_clusters, sub_opinion_ids, url_search_params
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), )
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)
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), )
def view_opinion(request, pk, _): """Using the cluster ID, return the cluster of opinions. We also test if the cluster ID is a favorite for the user, and send data if needed. If it's a favorite, we send the bound form for the favorite so it can populate the form on the page. If it is not a favorite, we send the unbound form. """ # Look up the court, cluster, title and favorite information cluster = get_object_or_404(OpinionCluster, pk=pk) title = ', '.join([s for s in [ trunc(best_case_name(cluster), 100, ellipsis="..."), cluster.citation_string, ] if s.strip()]) has_downloads = False for sub_opinion in cluster.sub_opinions.all(): if sub_opinion.local_path or sub_opinion.download_url: has_downloads = True break get_string = search_utils.make_get_string(request) try: fave = Favorite.objects.get(cluster_id=cluster.pk, user=request.user) except (ObjectDoesNotExist, TypeError): # Not favorited or anonymous user favorite_form = FavoriteForm(initial={ 'cluster_id': cluster.pk, 'name': trunc(best_case_name(cluster), 100, ellipsis='...'), }) else: favorite_form = FavoriteForm(instance=fave) if not is_bot(request): # Get the citing results from Solr for speed. Only do this for humans # to save on disk usage. conn = sunburnt.SolrInterface(settings.SOLR_OPINION_URL, mode='r') q = { 'q': 'cites:({ids})'.format( ids=' OR '.join([str(pk) for pk in (cluster.sub_opinions .values_list('pk', flat=True))]) ), 'rows': 5, 'start': 0, 'sort': 'citeCount desc', 'caller': 'view_opinion', } citing_clusters = conn.raw_query(**q).execute() else: citing_clusters = None return render(request, 'view_opinion.html', { 'title': title, 'cluster': cluster, 'has_downloads': has_downloads, 'favorite_form': favorite_form, 'get_string': get_string, 'private': cluster.blocked, 'citing_clusters': citing_clusters, 'top_authorities': cluster.authorities[:5], })
def view_opinion(request, pk, _): """Using the cluster ID, return the cluster of opinions. We also test if the cluster ID is a favorite for the user, and send data if needed. If it's a favorite, we send the bound form for the favorite so it can populate the form on the page. If it is not a favorite, we send the unbound form. """ # Look up the court, cluster, title and favorite information cluster = get_object_or_404(OpinionCluster, pk=pk) title = ", ".join([ s for s in [ trunc(best_case_name(cluster), 100, ellipsis="..."), cluster.citation_string, ] if s.strip() ]) has_downloads = False for sub_opinion in cluster.sub_opinions.all(): if sub_opinion.local_path or sub_opinion.download_url: has_downloads = True break get_string = search_utils.make_get_string(request) try: fave = Favorite.objects.get(cluster_id=cluster.pk, user=request.user) except (ObjectDoesNotExist, TypeError): # Not favorited or anonymous user favorite_form = FavoriteForm( initial={ "cluster_id": cluster.pk, "name": trunc(best_case_name(cluster), 100, ellipsis="..."), }) else: favorite_form = FavoriteForm(instance=fave) if not is_bot(request): # Get the citing results from Solr for speed. Only do this for humans # to save on disk usage. conn = sunburnt.SolrInterface(settings.SOLR_OPINION_URL, mode="r") q = { "q": "cites:({ids})".format(ids=" OR ".join([ str(pk) for pk in (cluster.sub_opinions.values_list("pk", flat=True)) ])), "rows": 5, "start": 0, "sort": "citeCount desc", "caller": "view_opinion", } citing_clusters = conn.raw_query(**q).execute() else: citing_clusters = None return render( request, "view_opinion.html", { "title": title, "cluster": cluster, "has_downloads": has_downloads, "favorite_form": favorite_form, "get_string": get_string, "private": cluster.blocked, "citing_clusters": citing_clusters, "top_authorities": cluster.authorities_with_data[:5], "authorities_count": len(cluster.authorities_with_data), }, )
def view_opinion(request, pk, _): """Using the cluster ID, return the cluster of opinions. We also test if the cluster ID is a favorite for the user, and send data if needed. If it's a favorite, we send the bound form for the favorite so it can populate the form on the page. If it is not a favorite, we send the unbound form. """ # Look up the court, cluster, title and favorite information cluster = get_object_or_404(OpinionCluster, pk=pk) title = ', '.join([ s for s in [ trunc(best_case_name(cluster), 100, ellipsis="..."), cluster.citation_string, ] if s.strip() ]) has_downloads = False for sub_opinion in cluster.sub_opinions.all(): if sub_opinion.local_path or sub_opinion.download_url: has_downloads = True break get_string = search_utils.make_get_string(request) try: fave = Favorite.objects.get(cluster_id=cluster.pk, user=request.user) except (ObjectDoesNotExist, TypeError): # Not favorited or anonymous user favorite_form = FavoriteForm( initial={ 'cluster_id': cluster.pk, 'name': trunc(best_case_name(cluster), 100, ellipsis='...'), }) else: favorite_form = FavoriteForm(instance=fave) if not is_bot(request): # Get the citing results from Solr for speed. Only do this for humans # to save on disk usage. conn = sunburnt.SolrInterface(settings.SOLR_OPINION_URL, mode='r') q = { 'q': 'cites:({ids})'.format(ids=' OR '.join([ str(pk) for pk in (cluster.sub_opinions.values_list('pk', flat=True)) ])), 'rows': 5, 'start': 0, 'sort': 'citeCount desc', 'caller': 'view_opinion', } citing_clusters = conn.raw_query(**q).execute() else: citing_clusters = None return render( request, 'view_opinion.html', { 'title': title, 'cluster': cluster, 'has_downloads': has_downloads, 'favorite_form': favorite_form, 'get_string': get_string, 'private': cluster.blocked, 'citing_clusters': citing_clusters, 'top_authorities': cluster.authorities[:5], })
def get_related_clusters_with_cache(cluster, request): """Use Solr to get related opinions with Solr-MoreLikeThis query :param cluster: The cluster we're targeting :param request: Request object for checking if user is permitted :return: Tuple[List, List] Related clusters and sub-opinion IDs """ if is_bot(request) or not is_related_beta_user(request): # If it is a bot or is not beta tester, return empty results return [], [] conn = sunburnt.SolrInterface(settings.SOLR_OPINION_URL, mode="r") # Opinions that belong to the targeted cluster sub_opinion_ids = cluster.sub_opinions.values_list("pk", flat=True) # Use cache if enabled mlt_cache_key = "mlt-cluster:%s" % cluster.pk related_clusters = ( caches["db_cache"].get(mlt_cache_key) if settings.RELATED_USE_CACHE else None ) if related_clusters is None: # Cache is empty # Turn list of opinion IDs into list of Q objects sub_opinion_queries = [conn.Q(id=sub_id) for sub_id in sub_opinion_ids] # Take one Q object from the list sub_opinion_query = sub_opinion_queries.pop() # OR the Q object with the ones remaining in the list for item in sub_opinion_queries: sub_opinion_query |= item mlt_query = ( conn.query(sub_opinion_query) .mlt( "text", count=settings.RELATED_COUNT, maxqt=settings.RELATED_MLT_MAXQT, mintf=settings.RELATED_MLT_MINTF, minwl=settings.RELATED_MLT_MINWL, maxwl=settings.RELATED_MLT_MAXWL, ) .field_limit(fields=["id", "caseName", "absolute_url"]) ) mlt_res = mlt_query.execute() if mlt_res.more_like_this is not None: # Only a single sub opinion related_clusters = mlt_res.more_like_this.docs elif mlt_res.more_like_these is not None: # Multiple sub opinions # Get result list for each sub opinion sub_docs = [ sub_res.docs for sub_id, sub_res in mlt_res.more_like_these.items() ] # Merge sub results by interleaving # - exclude items that are sub opinions related_clusters = [ item for pair in zip(*sub_docs) for item in pair if item["id"] not in sub_opinion_ids ] # Limit number of results related_clusters = related_clusters[: settings.RELATED_COUNT] else: # No MLT results are available (this should not happen) related_clusters = [] cache.set( mlt_cache_key, related_clusters, settings.RELATED_CACHE_TIMEOUT ) return related_clusters, sub_opinion_ids
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)