diff --git a/CHANGES.md b/CHANGES.md index 0945f220..f9b845e7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ Features: - Docket reports from ACMS are now uploaded to CourtListener.([#372](https://github.com/freelawproject/recap-chrome/pull/372)) - Adds logic to upload ACMS PDF documents to CourtListener. ([#373](https://github.com/freelawproject/recap-chrome/pull/373)) - Inserts the RECAP button and [R] icons to the ACMS Docket report. ([#374](https://github.com/freelawproject/recap-chrome/pull/374)) + - Introduces logic to upload ACMS attachment pages to CourtListener([#375](https://github.com/freelawproject/recap-chrome/pull/375)) Changes: - None yet diff --git a/src/appellate/appellate.js b/src/appellate/appellate.js index f2d16187..fe1e8847 100644 --- a/src/appellate/appellate.js +++ b/src/appellate/appellate.js @@ -53,6 +53,8 @@ AppellateDelegate.prototype.regularAppellatePageHandler = function () { AppellateDelegate.prototype.ACMSPageHandler = function () { if (this.path.startsWith('/download-confirmation/')) { this.handleAcmsDownloadPage(); + } else if (this.path.startsWith('/documents-list/')) { + this.handleAcmsAttachmentPage(); } else if (this.path.match(/^\/[0-9\-]+$/)) { this.handleAcmsDocket(); } @@ -67,6 +69,155 @@ AppellateDelegate.prototype.dispatchPageHandler = function () { } }; +AppellateDelegate.prototype.handleAcmsAttachmentPage = async function () { + const processAttachmentPage = async () => { + let caseSummary = JSON.parse(sessionStorage.caseSummary); + this.pacer_case_id = caseSummary.caseDetails.caseId; + + const options = await getItemsFromStorage('options'); + if (options['recap_enabled']) { + let vueData = JSON.parse(sessionStorage.recapVueData); + let requestBody = { + caseDetails: caseSummary.caseDetails, + docketEntry: vueData.docketEntry, + docketEntryDocuments: vueData.docketEntryDocuments, + }; + this.recap.uploadDocket( + this.court, + this.pacer_case_id, + JSON.stringify(requestBody), + 'ACMS_ATTACHMENT_PAGE', + (ok) => { + if (ok) { + history.replaceState({ uploaded: true }, ''); + this.notifier.showUpload( + 'Attachment page uploaded to the public RECAP Archive.', + () => {} + ); + }else { + this.notifier.showUpload( + 'Error: The Attachment page was not uploaded to the public' + + 'RECAP Archive', + () => {} + ); + } + } + ); + } else { + console.info('RECAP: Not uploading docket json. RECAP is disabled.'); + } + }; + + const attachLinkToDocs = async () => { + // This function attaches links to available RECAP documents for each entry + // on the current page. It performs the following steps: + // + // 1. Retrieves docket entry and document data from session storage. + // 2. Selects all elements with the class "entry-link" on the page. + // 3. Loops through each link: + // - Extracts the document number from the previous sibling element. + // - Finds the corresponding document data object using the document + // number. + // - Embeds the document's `docketDocumentDetailsId` as a + // `data-document-guid` attribute in the link. + // 4. Queries the server for the availability of these documents from RECAP. + // 5. Iterates through the response: + // - Extracts the `acms_document_guid` for each available document. + // - Finds the corresponding link element using the previously attached + // `data-document-guid` attribute. + // - Creates a link element + // - Inserts the RECAP icon element next to the original entry link. + const attachmentsData = JSON.parse(sessionStorage.recapVueData); + const documentsData = attachmentsData.docketEntryDocuments; + + // Get all the entry links on the page. We use the "entry-link" + // class as a selector because all rows on the page + // consistently use this class. + this.links = document.body.querySelectorAll('.entry-link'); + if (!links.length) { + return; + } + + // Go through the array of links and embed the document_guid + for (link of this.links) { + // The document number and the link are enclosed within the + // same span tag and are located adjacent to each other. + // Therefore, to retrieve the document number, we need to use + // the previousSibling property. + let documentNumberText = link.previousSibling.innerHTML.trim(); + const docData = documentsData.find( + (document) => document.documentNumber == documentNumberText + ); + + // Embed the document_guid as a data attribute within the anchor tag + // to facilitate subsequent retrieval based on this identifier. + link.dataset.documentGuid = docData.docketDocumentDetailsId; + } + + let docIds = [attachmentsData.docketEntry.docketEntryId]; + + // Ask the server whether any of these documents are available from RECAP. + this.recap.getAvailabilityForDocuments(docIds, this.court, (response) => { + for (result of response.results) { + let doc_guid = result.acms_document_guid; + // Query the docket entry link using the data attribute + // attached previously + let anchor = document.querySelector( + `[data-document-guid="${doc_guid}"]` + ); + // Create the RECAP icon + let href = `https://storage.courtlistener.com/${result.filepath_local}`; + let recap_link = $('', { + title: 'Available for free from the RECAP Archive.', + href: href, + }); + recap_link.append( + $('').attr({ + src: chrome.extension.getURL('assets/images/icon-16.png'), + }) + ); + let recap_div = $('