Skip to content

Commit

Permalink
Merge branch 'main' into 3874-v4-api-documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
albertisfu committed Sep 18, 2024
2 parents 6ad4278 + ece5ea5 commit 1d671a4
Show file tree
Hide file tree
Showing 178 changed files with 8,672 additions and 2,869 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ jobs:

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: python
config-file: ./.github/codeql-config.yml
setup-python-dependencies: true

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3
4 changes: 2 additions & 2 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
Expand All @@ -33,7 +33,7 @@ jobs:
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/flp-dependencies-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
poetry update courts-db eyecite juriscraper reporters-db
- name: Create Pull Request
uses: peter-evans/create-pull-request@v3
uses: peter-evans/create-pull-request@v7
with:
commit-message: Update freelawproject dependencies
title: Update freelawproject dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
# Build and cache docker images so tests are always run on the latest
# dependencies
- name: Set up docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
with:
driver-opts: network=host
- name: Prebuild docker images
Expand Down
2 changes: 1 addition & 1 deletion cl/alerts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ async def new_docket_alert(request: AuthenticatedHttpRequest) -> HttpResponse:
).aearliest("date_created")

title = f"New Docket Alert for {make_docket_title(docket)}"
has_alert = await user_has_alert(await request.auser(), docket) # type: ignore[attr-defined]
has_alert = await user_has_alert(await request.auser(), docket) # type: ignore[arg-type]
return TemplateResponse(
request,
"docket_alert_new.html",
Expand Down
32 changes: 16 additions & 16 deletions cl/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,28 @@ class WebhookEventType(models.IntegerChoices):
AfterUpdateOrDeleteSnapshot(), model_name="WebhookHistoryEvent"
)
class Webhook(AbstractDateTimeModel):
user = models.ForeignKey(
user: models.ForeignKey = models.ForeignKey(
User,
help_text="The user that has provisioned the webhook.",
related_name="webhooks",
on_delete=models.CASCADE,
)
event_type = models.IntegerField(
event_type: models.IntegerField = models.IntegerField(
help_text="The event type that triggers the webhook.",
choices=WebhookEventType.choices,
)
url = models.URLField(
url: models.URLField = models.URLField(
help_text="The URL that receives a POST request from the webhook.",
max_length=2000,
validators=[URLValidator(schemes=["https"])],
)
enabled = models.BooleanField(
enabled: models.BooleanField = models.BooleanField(
help_text="An on/off switch for the webhook.", default=False
)
version = models.IntegerField(
version: models.IntegerField = models.IntegerField(
help_text="The specific version of the webhook provisioned.", default=1
)
failure_count = models.IntegerField(
failure_count: models.IntegerField = models.IntegerField(
help_text="The number of failures (400+ status) responses the webhook "
"has received.",
default=0,
Expand Down Expand Up @@ -75,51 +75,51 @@ class WEBHOOK_EVENT_STATUS:


class WebhookEvent(AbstractDateTimeModel):
webhook = models.ForeignKey(
webhook: models.ForeignKey = models.ForeignKey(
Webhook,
help_text="The Webhook this event is associated with.",
related_name="webhook_events",
on_delete=models.CASCADE,
)
event_id = models.UUIDField(
event_id: models.UUIDField = models.UUIDField(
help_text="Unique event identifier",
default=uuid.uuid4,
editable=False,
)
event_status = models.SmallIntegerField(
event_status: models.SmallIntegerField = models.SmallIntegerField(
help_text="The webhook event status.",
default=WEBHOOK_EVENT_STATUS.IN_PROGRESS,
choices=WEBHOOK_EVENT_STATUS.STATUS,
)
content = models.JSONField( # type: ignore
content: models.JSONField = models.JSONField(
help_text="The content of the outgoing body in the POST request.",
blank=True,
null=True,
)
next_retry_date = models.DateTimeField(
next_retry_date: models.DateTimeField = models.DateTimeField(
help_text="The scheduled datetime to retry the webhook event.",
blank=True,
null=True,
)
error_message = models.TextField(
error_message: models.TextField = models.TextField(
help_text="The error raised by a failed POST request.",
blank=True,
)
response = models.TextField(
response: models.TextField = models.TextField(
help_text="The response received from the POST request.",
blank=True,
)
retry_counter = models.SmallIntegerField(
retry_counter: models.SmallIntegerField = models.SmallIntegerField(
help_text="The retry counter for the exponential backoff event.",
default=0,
)
status_code = models.SmallIntegerField(
status_code: models.SmallIntegerField = models.SmallIntegerField(
help_text="The HTTP status code received from the POST request.",
choices=HttpStatusCodes.choices, # type: ignore[attr-defined]
blank=True,
null=True,
)
debug = models.BooleanField(
debug: models.BooleanField = models.BooleanField(
help_text="Enabled if this is a test event for debugging purposes.",
default=False,
)
Expand Down
6 changes: 6 additions & 0 deletions cl/api/templates/bulk-data.html
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ <h3 id="contributing">Adding Features and Fixing Bugs</h3>
</p>

<h3 id="old">Release Notes</h3>
<p>
<strong>2024-08-07</strong>: Added <code>filepath_pdf_harvard</code> field to OpinionCluster data in bulk exports. This field contains the path to the PDF file from the Harvard Caselaw Access Project for the given case.
</p>
<p>
<strong>2024-08-02</strong>: Add new fields to the bulk data files for the Docket object: federal_dn_case_type, federal_dn_office_code, federal_dn_judge_initials_assigned, federal_dn_judge_initials_referred, federal_defendant_number, parent_docket_id.
</p>
<p>
<strong>2023-09-26</strong>: Bulk script refactored to make it easier to maintain. Courthouse table added to bulk script. Court appeals_to through table added to bulk script. Bulk script now automatically generates a shell script to load bulk data and stream the script to S3.
</p>
Expand Down
2 changes: 1 addition & 1 deletion cl/api/templates/citation-api-docs-vlatest.html
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ <h2 id="cites-endpoint">Opinions Cited/Citing API<br><small><code>{% url "opinio
}
}</pre>
<p>To understand <code>RelatedFilters</code>, see our <a href="{% url "rest_docs" version=version %}">filtering documentation</a>.</p>
<p>These filters allow you to filter to the opinions that an opinion cites (it's "Authorities") or the opinions that cite it.
<p>These filters allow you to filter to the opinions that an opinion cites (its "Authorities" or backward citations) or the later opinions that cite it (forward citations).
</p>
<p>For example, opinion <code>2812209</code> is the decision in <em>Obergefell v. Hodges</em>. To see what it cites:</p>
<pre class="pre-scrollable tall">curl -v \
Expand Down
17 changes: 17 additions & 0 deletions cl/api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
SchoolViewSet,
SourceViewSet,
)
from cl.people_db.factories import PartyFactory, PartyTypeFactory
from cl.people_db.models import Attorney
from cl.recap.factories import ProcessingQueueFactory
from cl.recap.views import (
EmailProcessingQueueViewSet,
Expand Down Expand Up @@ -759,6 +761,21 @@ async def test_attorney_filters(self) -> None:
self.q = {"parties_represented__name__contains": "Honker-Nope"}
await self.assertCountInResults(0)

# Adds extra role to the existing attorney
docket = await Docket.objects.afirst()
attorney = await Attorney.objects.afirst()
await sync_to_async(PartyTypeFactory.create)(
party=await sync_to_async(PartyFactory)(
docket=docket,
attorneys=[attorney],
),
docket=docket,
)
self.q = {"docket__date_created__range": "2017-04-14,2017-04-15"}
await self.assertCountInResults(1)
self.q = {"docket__date_created__range": "2017-04-15,2017-04-16"}
await self.assertCountInResults(0)

async def test_party_filters(self) -> None:
self.path = reverse("party-list", kwargs={"version": "v3"})

Expand Down
3 changes: 2 additions & 1 deletion cl/api/webhooks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import random

import requests
from django.conf import settings
Expand Down Expand Up @@ -38,7 +39,7 @@ def send_webhook_event(
the webhook is sent.
"""
proxy_server = {
"http": settings.EGRESS_PROXY_HOST, # type: ignore
"http": random.choice(settings.EGRESS_PROXY_HOSTS), # type: ignore
}
headers = {
"Content-type": "application/json",
Expand Down
44 changes: 43 additions & 1 deletion cl/assets/static-global/css/override.css
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,6 @@ div.shown ul {
padding: 3px 0 5px 0;
}


#summaries ul {
padding-inline-start: 15px;
border-bottom: 1pt solid #DDD;
Expand Down Expand Up @@ -893,6 +892,20 @@ input.court-checkbox, input.status-checkbox {
border-bottom: 1px solid #dddddd;
}

.description-header,
.export-csv {
padding: 0px;
}

#export-csv-error {
padding: 5px 0px;
}

@media (min-width: 767px) {
.export-csv {
padding: 5px 10px;
}
}
#docket-entry-table .recap-documents.row {
padding-top: 0px;
border-bottom: none;
Expand Down Expand Up @@ -1681,3 +1694,32 @@ rect.series-segment {
.ml-1 {
margin-left: 0.25rem !important;
}

.htmx-indicator {
opacity: 0;
transition: opacity 200ms ease-in;
}

.htmx-hidden-indicator {
display:none;
}
.htmx-request .htmx-hidden-indicator {
display:inline;
}
.htmx-request.htmx-hidden-indicator {
display:inline;
}

.turbo-progress-bar {
position: fixed;
display: block;
top: 0;
left: 0;
height: 3px;
background: #B53C2C;
z-index: 2147483647;
transition:
width 300ms ease-out,
opacity 150ms 150ms ease-in;
transform: translate3d(0, 0, 0);
}
2 changes: 2 additions & 0 deletions cl/assets/static-global/js/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ $(document).ready(function () {
.val(el.val())
.appendTo('#search-form');
});
installProgressBar();
disableAllSubmitButtons();
document.location = '/?' + $('#search-form').serialize();
}

Expand Down
55 changes: 55 additions & 0 deletions cl/assets/static-global/js/export-csv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
document.addEventListener('htmx:beforeRequest', function () {
// If the mobile error message is currently visible, adds the 'hidden' class
// to hide it.
let mobileErrorMessage = document.getElementById('mobile-export-csv-error');
if (!mobileErrorMessage.classList.contains('hidden')) {
mobileErrorMessage.classList.add('hidden');
}

// If the desktop error message is currently visible, adds the 'hidden' class
// to hide it.
let desktopErrorMessage = document.getElementById('export-csv-error');
if (!desktopErrorMessage.classList.contains('hidden')) {
desktopErrorMessage.classList.add('hidden');
}
});

document.addEventListener('htmx:beforeOnLoad', function (event) {
// Get the XMLHttpRequest object from the event details
const xhr = event.detail.xhr;
if (xhr.status == 200) {
const response = xhr.response;
// Extract the filename from the Content-Disposition header and get
//the MIME type from the Content-Type header
const filename = xhr.getResponseHeader('Content-Disposition').split('=')[1];
const mimetype = xhr.getResponseHeader('Content-Type');

// Prepare a link element for a file download
// Create a hidden link element for download
const link = document.createElement('a');
link.style.display = 'none';

// Create a Blob object containing the response data with the correct
// MIME type and generate a temporary URL for it
const blob = new Blob([response], { type: mimetype });
const url = window.URL.createObjectURL(blob);

// Set the link's attributes for download
link.href = url;
link.download = filename.replaceAll('"', '');

// It needs to be added to the DOM so it can be clicked
document.body.appendChild(link);
link.click();

// Release the temporary URL after download (for memory management)
window.URL.revokeObjectURL(url);
} else {
// If the request failed, show the error messages
let mobileErrorMessage = document.getElementById('mobile-export-csv-error');
mobileErrorMessage.classList.remove('hidden');

let desktopErrorMessage = document.getElementById('export-csv-error');
desktopErrorMessage.classList.remove('hidden');
}
});
32 changes: 32 additions & 0 deletions cl/assets/static-global/js/progress-bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
let trickleInterval = null;

function updateProgressBar() {
let progressElement = document.getElementById('progress-bar');
let oldValue = 0;
if ('value' in progressElement.dataset) {
oldValue = parseFloat(progressElement.dataset.value);
}
let newValue = oldValue + Math.random() / 10;
if (newValue >= 1) newValue = 1;
progressElement.style.width = `${10 + newValue * 75}%`;
progressElement.dataset.value = newValue;
}

function installProgressBar() {
let progressElement = document.createElement('div');
progressElement.id = 'progress-bar';
progressElement.classList.add('turbo-progress-bar');
progressElement.style.width = '0';
progressElement.style.opacity = '1';
document.body.prepend(progressElement);
trickleInterval = window.setInterval(updateProgressBar, 300);
}

function disableAllSubmitButtons() {
// Get all submit buttons on the page
const submitButtons = document.querySelectorAll('input[type="submit"],button[type="submit"]');
// Disable each element
submitButtons.forEach((button) => {
button.disabled = true;
});
}
2 changes: 0 additions & 2 deletions cl/assets/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ <h1>You did not supply the "private" variable to your template.
{% include 'includes/dismissible_nav_banner.html' with link="https://free.law/2024/01/18/new-recap-archive-search-is-live" text="A year in the making, today we are launching a huge new search engine for the RECAP Archive" emoji="&#127873;" cookie_name="no_banner"%}
{% endif %}

{% include 'includes/dismissible_nav_banner.html' with link="https://free.law/2024/07/05/new-branding-rip-flip" text="CourtListener, RECAP, and Free Law Project are getting some new logos and new branding!" emoji="&#128276;" cookie_name="no_branding_banner"%}

<!-- Broken Email Banner -->
{% if EMAIL_BAN_REASON %}
<div class="navbar navbar-default subnav alert-danger alert-dismissible broken-email-banner" role="navigation">
Expand Down
Loading

0 comments on commit 1d671a4

Please sign in to comment.