If there is a newsletter you would like to read in Omnivore, please let us know.
+
Omnivore Email Addresses
Omnivore allows you to create unique email addresses for subscribing to newsletters.
@@ -60,12 +58,16 @@ export default function Newsletters(): JSX.Element {
There are multiple ways to have newsletters added directly to your Omnivore library:
-
Subscribe to the newsletter with an Omnivore email address
If you are a registered iOS user and have granted push notification permission to Omnivore, you will be sent a notification when a newsletter is added to your library. Otherwise, you will be notified via your registered email address.
*/}
+
Updating your account email
+
+ If you want all your substack newsletters sent to Omnivore, you can login and change the
+ address on your account page in Substack.
+
Subscribing Directly
Create your first email address by clicking the Create New Email button on
@@ -80,11 +82,6 @@ export default function Newsletters(): JSX.Element {
/>
-
- If you want all your substack newsletters sent to Omnivore, you can login and change the
- address on your account page in Substack.
-
-
Create a Forwarding Rule
If you are a Gmail user you can create a forwarding rule to send email from your regular account to your Omnivore email address. This is useful if you have an existing paid newsletter subscription. For free newsletters we recommend subscribing directly to the newsletter with your Omnivore email address.
If there is a newsletter you would like to read in Omnivore, please let us know.
Omnivore Email Addresses
- Omnivore allows you to create unique email addresses for subscribing to newsletters.
- You can reuse one address for all your newsletters, or you can create a unique address
- for each.
+ Omnivore allows you to create unique email addresses for subscribing to newsletters.
+ You can reuse one address for all your newsletters, or you can create a unique address
+ for each.
- An Omnivore email address will receive email, detect whether the email is a newsletter,
- and add the newsletter content to your library. If the email does not appear to be a newsletter,
- it will be forwarded to the email address you used when you registered for Omnivore.
+ An Omnivore email address will receive email, detect whether the email is a newsletter,
+ and add the newsletter content to your library. If the email does not appear to be a newsletter,
+ it will be forwarded to the email address you used when you registered for Omnivore.
+
There are multiple ways to have newsletters added directly to your Omnivore library:
@@ -65,15 +68,17 @@ export default function Newsletters(): JSX.Element {
Updating your account email
- If you want all your substack newsletters sent to Omnivore, you can login and change the
- address on your account page in Substack.
+ If you want all your substack newsletters sent to Omnivore, you can login and change the
+ address on your account page in Substack.
Subscribing Directly
-
Create your first email address by clicking the Create New Email button on
- the emails page. Copy the email address to your clipboard using the
- copy button, and enter that email address into an email subscription box. If you are already logged into
- Substack you might need to logout to use your new email address.
+
+ Create your first email address by clicking the Create New Email button on
+ the emails page. Copy the email address to your clipboard using the
+ copy button, and enter that email address into an email subscription box. If you are already logged into
+ Substack you might need to logout to use your new email address.
+
Date: Thu, 31 Mar 2022 11:41:12 -0700
Subject: [PATCH 024/298] Improve wording
---
packages/web/pages/help/newsletters.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/web/pages/help/newsletters.tsx b/packages/web/pages/help/newsletters.tsx
index d1abf4954..2f50e0e98 100644
--- a/packages/web/pages/help/newsletters.tsx
+++ b/packages/web/pages/help/newsletters.tsx
@@ -59,7 +59,7 @@ export default function Newsletters(): JSX.Element {
it will be forwarded to the email address you used when you registered for Omnivore.
-
There are multiple ways to have newsletters added directly to your Omnivore library:
+
There are multiple ways to add newsletters to your Omnivore library:
From 1215735d4c38b49f98f23938ac63d006198cf84e Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Thu, 31 Mar 2022 12:04:31 -0700
Subject: [PATCH 025/298] Use buttons in the subscribe directly blocks
---
packages/web/pages/help/newsletters.tsx | 43 ++++++++++++++++++++++---
1 file changed, 39 insertions(+), 4 deletions(-)
diff --git a/packages/web/pages/help/newsletters.tsx b/packages/web/pages/help/newsletters.tsx
index 2f50e0e98..c2eaabfa7 100644
--- a/packages/web/pages/help/newsletters.tsx
+++ b/packages/web/pages/help/newsletters.tsx
@@ -5,6 +5,37 @@ import { Button } from '../../components/elements/Button'
import Link from 'next/link'
import { StyledText } from '../../components/elements/StyledText'
import { styled } from '@stitches/react'
+import { Copy, Plus } from 'phosphor-react'
+import { theme } from '../../components/tokens/stitches.config'
+
+const AddEmailButton = () => {
+ return ( {}}
+ style="ctaDarkYellow"
+ css={{
+ cursor: 'default',
+ display: 'inline-flex',
+ alignItems: 'center',
+ }}
+ >
+
+ Add Email
+ )
+}
+
+const CopyButton = () => {
+ return (
+ {}}
+ >
+
+ )
+}
export default function Newsletters(): JSX.Element {
const HighlightText = styled(SpanBox, {
@@ -74,10 +105,10 @@ export default function Newsletters(): JSX.Element {
Subscribing Directly
- Create your first email address by clicking the Create New Email button on
- the emails page. Copy the email address to your clipboard using the
- copy button, and enter that email address into an email subscription box. If you are already logged into
- Substack you might need to logout to use your new email address.
+ Create your first email address by clicking the button on
+ the emails page. Copy the email address
+ to your clipboard using the
+ copy button, and enter that email address into an email subscription box.
+ If you are already logged into Substack you might need to logout to use your new email address.
+
+
Create a Forwarding Rule
If you are a Gmail user you can create a forwarding rule to send email from your regular account to your Omnivore email address. This is useful if you have an existing paid newsletter subscription. For free newsletters we recommend subscribing directly to the newsletter with your Omnivore email address.
From 1ca6da0daa89ef4c6eb1e6ac4dd58f8bff694c6d Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Thu, 31 Mar 2022 12:43:13 -0700
Subject: [PATCH 026/298] Simplify docs on setting up forwarding rules
---
packages/web/pages/help/newsletters.tsx | 39 ++++++++++++++++++-------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/packages/web/pages/help/newsletters.tsx b/packages/web/pages/help/newsletters.tsx
index c2eaabfa7..917594cca 100644
--- a/packages/web/pages/help/newsletters.tsx
+++ b/packages/web/pages/help/newsletters.tsx
@@ -124,31 +124,48 @@ export default function Newsletters(): JSX.Element {
Create a Forwarding Rule
-
If you are a Gmail user you can create a forwarding rule to send email from your regular account to your Omnivore email address. This is useful if you have an existing paid newsletter subscription. For free newsletters we recommend subscribing directly to the newsletter with your Omnivore email address.
+
+ If you are a Gmail user you can create a forwarding rule to send email from your regular account
+ to your Omnivore email address. This is useful if you have an existing paid newsletter subscription and
+ don't want to update your account email address.
+
+
+
+ For free newsletters we recommend subscribing directly to the newsletter with your Omnivore email address
+ instead of setting up forwarding rules.
+
Before you start:
-
Create an Omnivore Email Address by clicking the Create New Email button on the emails page.
+
Create an Omnivore Email Address by clicking the button on the emails page.
Make a note of the Newsletter's sender email address. For example omnivore@substack.com.
Create a forwarding rule:
-
On a computer open your Gmail Forwarding Rules. If clicking the Gmail Forwarding Rules link does not work: click on the Gear icon in the upper right corner of Gmail and select All Settings, then click the Forwarding and POP/IMAP tab
-
In the Forwarding section click Add a forwarding address.
+
+ On a computer open your Gmail Forwarding Rules.
+ If this link does not work: click on the Gear icon in the upper right corner of Gmail
+ and select All Settings, then click the Forwarding and POP/IMAP tab.
+
+
In the Forwarding section click Add a forwarding address.
Enter your Omnivore Email Address (eg username-sdfsd@inbox.omnivore.app) and click Next.
-
Click Proceed
-
Click OK
-
Refresh the Omnivore Newsletter Emails page and you should see a code appear beside your address (eg 663421251). Copy this code to your clipboard.
-
Return to your forwarding rules section and look for the confirm code text box. Enter the confirmation code you copied and click Verify.
-
In the forwarding section of Gmail, Click on Creating a Filter
+
Click Proceed and OK
+
Refresh the Omnivore Newsletter Emails page and you should see a code appear beside your address (eg 663421251).
+ Copy this code to your clipboard (click the button).
+
+
+ Return to your forwarding rules section and look for the confirm code text box.
+ Enter the confirmation code you copied and click Verify.
+
+
In the forwarding section of Gmail, Click on Creating a Filter
Add the email address of your newsletter (eg omnivore@substack.app) in the From section.
Click Create Filter
-
Choose Forward it to and enter your Omnivore Email Address (eg username-sdfsd@inbox.omnivore.app)
+
Choose Forward it to and enter your Omnivore Email Address (eg username-sdfsd@inbox.omnivore.app)
Click Create Filter at the bottom of the dialog.
-
+
)
}
From 6d480ffe38a52bafd2ee8d116e0fe13e2d0a2712 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Thu, 31 Mar 2022 12:44:09 -0700
Subject: [PATCH 027/298] Add extra padding on bottom of help docs
---
packages/web/pages/help/saving-links.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/web/pages/help/saving-links.tsx b/packages/web/pages/help/saving-links.tsx
index bf88e6dea..ff16e56d1 100644
--- a/packages/web/pages/help/saving-links.tsx
+++ b/packages/web/pages/help/saving-links.tsx
@@ -162,6 +162,7 @@ export default function Colors(): JSX.Element {
+ An Omnivore email address will receive email, detect whether the email is a PDF document or newsletter,
+ and add the content to your library.
+
+
+ If Omnivore doesn't think the item should be added to your library,
+ it will be forwarded to the email address you used when you registered
+ for Omnivore (from msgs@omnivore.app).
+
+
+
Sending PDFs to your Omnivore Email Address
+
+ Add PDFs to your Omnivore library by sending them to your Omnivore email address. If there is a subject
+ line in the email, it will be used as the title of the PDF. If there is no subject line, the filename will
+ be used as the title.
+
+
+
Read all your newsletters in Omnivore
+
+ Subscribe to newsletters with your Omnivore email address and they
+ will be added to your library when we receive them.
+
+
+
+
+ Get Started
+
+
+
+
+
+ )
+}
From e61d030e32dd64814d7d5f8b40dd91013c0790f1 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Thu, 31 Mar 2022 13:17:07 -0700
Subject: [PATCH 030/298] Improve formatting
---
packages/web/pages/help/emails.tsx | 39 ++-----------------------
packages/web/pages/help/newsletters.tsx | 6 +---
2 files changed, 4 insertions(+), 41 deletions(-)
diff --git a/packages/web/pages/help/emails.tsx b/packages/web/pages/help/emails.tsx
index 6a77f6396..40735fb62 100644
--- a/packages/web/pages/help/emails.tsx
+++ b/packages/web/pages/help/emails.tsx
@@ -1,41 +1,8 @@
/* eslint-disable @next/next/no-img-element */
-import { Box, HStack, SpanBox } from '../../components/elements/LayoutPrimitives'
+import { Box, HStack } from '../../components/elements/LayoutPrimitives'
import { PrimaryLayout } from '../../components/templates/PrimaryLayout'
import { Button } from '../../components/elements/Button'
import Link from 'next/link'
-import { StyledText } from '../../components/elements/StyledText'
-import { styled } from '@stitches/react'
-import { Copy, Plus } from 'phosphor-react'
-import { theme } from '../../components/tokens/stitches.config'
-
-const AddEmailButton = () => {
- return ( {}}
- style="ctaDarkYellow"
- css={{
- cursor: 'default',
- display: 'inline-flex',
- alignItems: 'center',
- }}
- >
-
- Add Email
- )
-}
-
-const CopyButton = () => {
- return (
- {}}
- >
-
- )
-}
export default function Emails(): JSX.Element {
return (
@@ -68,7 +35,7 @@ export default function Emails(): JSX.Element {
and add the content to your library.
- If Omnivore doesn't think the item should be added to your library,
+ If Omnivore doesn't think the item should be added to your library,
it will be forwarded to the email address you used when you registered
for Omnivore (from msgs@omnivore.app).
@@ -86,7 +53,7 @@ export default function Emails(): JSX.Element {
will be added to your library when we receive them.
-
diff --git a/packages/web/pages/help/newsletters.tsx b/packages/web/pages/help/newsletters.tsx
index ad34e3be3..2c248f140 100644
--- a/packages/web/pages/help/newsletters.tsx
+++ b/packages/web/pages/help/newsletters.tsx
@@ -3,14 +3,11 @@ import { Box, HStack, SpanBox } from '../../components/elements/LayoutPrimitives
import { PrimaryLayout } from '../../components/templates/PrimaryLayout'
import { Button } from '../../components/elements/Button'
import Link from 'next/link'
-import { StyledText } from '../../components/elements/StyledText'
-import { styled } from '@stitches/react'
import { Copy, Plus } from 'phosphor-react'
import { theme } from '../../components/tokens/stitches.config'
const AddEmailButton = () => {
return ( {}}
style="ctaDarkYellow"
css={{
cursor: 'default',
@@ -31,7 +28,6 @@ const CopyButton = () => {
cursor: 'default',
display: 'inline-flex',
}}
- onClick={() => {}}
>
)
@@ -122,7 +118,7 @@ export default function Newsletters(): JSX.Element {
If you are a Gmail user you can create a forwarding rule to send email from your regular account
to your Omnivore email address. This is useful if you have an existing paid newsletter subscription and
- don't want to update your account email address.
+ don't want to update your account email address.
From a34cf9adfb52c0e937c1386b33213df165da9b2a Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Thu, 31 Mar 2022 10:44:35 -0700
Subject: [PATCH 031/298] Add link to Emails to main dropdown
Also remove the unused navigate-to-feedback, we directly open
intercom from the dropdown.
---
packages/web/components/patterns/DropdownMenu.tsx | 6 +++++-
packages/web/components/patterns/PrimaryHeader.tsx | 4 ++--
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/packages/web/components/patterns/DropdownMenu.tsx b/packages/web/components/patterns/DropdownMenu.tsx
index ea879282e..c63dca2ee 100644
--- a/packages/web/components/patterns/DropdownMenu.tsx
+++ b/packages/web/components/patterns/DropdownMenu.tsx
@@ -15,7 +15,7 @@ export type HeaderDropdownAction =
| 'apply-light-theme'
| 'apply-lighter-theme'
| 'navigate-to-install'
- | 'navigate-to-feedback'
+ | 'navigate-to-emails'
| 'navigate-to-profile'
| 'increaseFontSize'
| 'decreaseFontSize'
@@ -77,6 +77,10 @@ export function DropdownMenu(props: DropdownMenuProps): JSX.Element {
onSelect={() => props.actionHandler('navigate-to-install')}
title="Install"
/>
+ props.actionHandler('navigate-to-emails')}
+ title="Emails"
+ />
window.Intercom('show')}
title="Feedback"
diff --git a/packages/web/components/patterns/PrimaryHeader.tsx b/packages/web/components/patterns/PrimaryHeader.tsx
index 4cc544770..1092205b6 100644
--- a/packages/web/components/patterns/PrimaryHeader.tsx
+++ b/packages/web/components/patterns/PrimaryHeader.tsx
@@ -103,8 +103,8 @@ export function PrimaryHeader(props: HeaderProps): JSX.Element {
case 'navigate-to-install':
router.push('/settings/installation')
break
- case 'navigate-to-feedback':
- console.log('navigate to feedback - unimplemented') // TODO: implement intercom
+ case 'navigate-to-emails':
+ router.push('/settings/emails')
break
case 'navigate-to-profile':
if (props.user) {
From 13cd668cdd3644caa9ab6c40e8ae4c9f13231a4c Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Thu, 31 Mar 2022 15:04:22 -0700
Subject: [PATCH 032/298] Add invalidation when highlights are added to items
---
.../Views/WebReader/WebReaderViewModel.swift | 18 +++---
.../Sources/Models/ArticleContent.swift | 4 +-
.../Services/DataService/DataService.swift | 56 +++++++++++++------
3 files changed, 51 insertions(+), 27 deletions(-)
diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderViewModel.swift
index f111608c9..5764bac83 100644
--- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderViewModel.swift
+++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderViewModel.swift
@@ -21,20 +21,18 @@ final class WebReaderViewModel: ObservableObject {
@Published var isLoading = false
@Published var articleContent: ArticleContent?
+ var slug: String?
var subscriptions = Set()
func loadContent(dataService: DataService, slug: String) {
+ self.slug = slug
isLoading = true
guard let viewer = dataService.currentViewer else { return }
- if let content = dataService.pageCache.object(forKey: NSString(string: slug)) {
- print("RETRIEVED FORM CACHE", slug)
- isLoading = false
- articleContent = content.value
- return
- } else {
- print("MISSED CACHE", slug)
+ if let content = dataService.pageFromCache(slug: slug) {
+ articleContent = content
+ // continue to load from the web if possible
}
dataService.articleContentPublisher(username: viewer.username, slug: slug).sink(
@@ -44,7 +42,7 @@ final class WebReaderViewModel: ObservableObject {
},
receiveValue: { [weak self] articleContent in
self?.articleContent = articleContent
- dataService.pageCache.setObject(CachedPageContent(articleContent), forKey: NSString(string: slug))
+ dataService.pageCache.setObject(CachedPageContent(slug, articleContent), forKey: NSString(string: slug))
}
)
.store(in: &subscriptions)
@@ -177,12 +175,16 @@ final class WebReaderViewModel: ObservableObject {
switch actionID {
case "deleteHighlight":
+ dataService.invalidateCachedPage(slug: slug)
deleteHighlight(messageBody: messageBody, replyHandler: replyHandler, dataService: dataService)
case "createHighlight":
+ dataService.invalidateCachedPage(slug: slug)
createHighlight(messageBody: messageBody, replyHandler: replyHandler, dataService: dataService)
case "mergeHighlight":
+ dataService.invalidateCachedPage(slug: slug)
mergeHighlight(messageBody: messageBody, replyHandler: replyHandler, dataService: dataService)
case "updateHighlight":
+ dataService.invalidateCachedPage(slug: slug)
updateHighlight(messageBody: messageBody, replyHandler: replyHandler, dataService: dataService)
case "articleReadingProgress":
updateReadingProgress(messageBody: messageBody, replyHandler: replyHandler, dataService: dataService)
diff --git a/apple/OmnivoreKit/Sources/Models/ArticleContent.swift b/apple/OmnivoreKit/Sources/Models/ArticleContent.swift
index 7a3d5b0e7..032ccf434 100644
--- a/apple/OmnivoreKit/Sources/Models/ArticleContent.swift
+++ b/apple/OmnivoreKit/Sources/Models/ArticleContent.swift
@@ -1,9 +1,11 @@
import Foundation
public class CachedPageContent: NSObject {
+ public let slug: String
public let value: ArticleContent
- public init(_ content: ArticleContent) {
+ public init(_ slug: String, _ content: ArticleContent) {
+ self.slug = slug
self.value = content
}
}
diff --git a/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift b/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift
index aca49bdfa..12e72e406 100644
--- a/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift
+++ b/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift
@@ -4,7 +4,10 @@ import Models
public class CacheManager: NSObject, NSCacheDelegate {
public func cache(_: NSCache, willEvictObject obj: Any) {
- print("evicting object", obj)
+ // This is just used for debugging
+ if let content = obj as? CachedPageContent {
+ print("evicting page from cache", content.slug)
+ }
}
}
@@ -32,23 +35,6 @@ public final class DataService: ObservableObject {
pageCache.delegate = cacheManager
}
- public func prefetchPages(items: [FeedItem]) {
- print("prefetching items", items, "cost limit", pageCache.countLimit)
-
- guard let viewer = currentViewer else { return }
-
- for item in items {
- let slug = item.slug
- articleContentPublisher(username: viewer.username, slug: slug).sink(
- receiveCompletion: { _ in },
- receiveValue: { [weak self] articleContent in
- self?.pageCache.setObject(CachedPageContent(articleContent), forKey: NSString(string: slug))
- }
- )
- .store(in: &subscriptions)
- }
- }
-
public func clearHighlights() {
highlightsCache.removeAllObjects()
}
@@ -62,3 +48,37 @@ public final class DataService: ObservableObject {
}
}
}
+
+public extension DataService {
+ func prefetchPages(items: [FeedItem]) {
+ print("prefetching pages")
+ guard let viewer = currentViewer else { return }
+
+ for item in items {
+ let slug = item.slug
+ articleContentPublisher(username: viewer.username, slug: slug).sink(
+ receiveCompletion: { _ in },
+ receiveValue: { [weak self] articleContent in
+ self?.pageCache.setObject(CachedPageContent(slug, articleContent), forKey: NSString(string: slug))
+ }
+ )
+ .store(in: &subscriptions)
+ }
+ }
+
+ func pageFromCache(slug: String) -> ArticleContent? {
+ if let content = pageCache.object(forKey: NSString(string: slug)) {
+ print("cache hit", slug)
+ return content.value
+ } else {
+ print("cache miss", slug)
+ }
+ return nil
+ }
+
+ func invalidateCachedPage(slug: String?) {
+ if let slug = slug {
+ pageCache.removeObject(forKey: NSString(string: slug))
+ }
+ }
+}
From 250118de45d8931fba8415821a71e5b274c53399 Mon Sep 17 00:00:00 2001
From: Hongbo Wu
Date: Fri, 1 Apr 2022 13:07:44 +0800
Subject: [PATCH 033/298] fix missing index_settings.json file in api
dockerfile for creating elastic index (#363)
---
packages/api/Dockerfile | 1 +
packages/db/setup.sh | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile
index 603154477..2727fd217 100644
--- a/packages/api/Dockerfile
+++ b/packages/api/Dockerfile
@@ -38,6 +38,7 @@ COPY --from=builder /app/packages/api/package.json /app/packages/api/package.jso
COPY --from=builder /app/packages/api/node_modules /app/packages/api/node_modules
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/package.json /app/package.json
+COPY --from=builder /app/packages/api/index_settings.json /app/packages/api/index_settings.json
EXPOSE 8080
diff --git a/packages/db/setup.sh b/packages/db/setup.sh
index 09db79a7c..3898b4647 100755
--- a/packages/db/setup.sh
+++ b/packages/db/setup.sh
@@ -4,4 +4,4 @@ psql --host $PG_HOST -U $PG_USER -d $PG_DB -c "CREATE USER app_user WITH PASSWOR
echo "created app_user"
yarn workspace @omnivore/db migrate
psql --host $PG_HOST -U $PG_USER -d $PG_DB -c "GRANT omnivore_user TO app_user;"
-echo "granted omnivore_user to app_user"
\ No newline at end of file
+echo "granted omnivore_user to app_user"
From f950f658fdc3f5be9da18f5b4ebd6aa48971f5b9 Mon Sep 17 00:00:00 2001
From: gitstart-omnivore
Date: Fri, 1 Apr 2022 08:00:05 +0000
Subject: [PATCH 034/298] remove line already added to packages/api/Dockerfile
---
packages/api/Dockerfile | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile
index 9bfbc1b58..2727fd217 100644
--- a/packages/api/Dockerfile
+++ b/packages/api/Dockerfile
@@ -33,7 +33,6 @@ ENV NODE_OPTIONS=--max-old-space-size=4096
ENV PORT=8080
COPY --from=builder /app/packages/api/dist /app/packages/api/dist
-COPY --from=builder /app/packages/api/index_settings.json /app/packages/api/index_settings.json
COPY --from=builder /app/packages/readabilityjs/ /app/packages/readabilityjs/
COPY --from=builder /app/packages/api/package.json /app/packages/api/package.json
COPY --from=builder /app/packages/api/node_modules /app/packages/api/node_modules
From da28998130d2287509c0dbbb5e89690abd1bd876 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Thu, 31 Mar 2022 11:21:41 -0700
Subject: [PATCH 035/298] Pull ul list out of newsletter blurb
next/react doesnt want child elements of the paragraphs
Improve formatting
Improve wording
Use buttons in the subscribe directly blocks
Simplify docs on setting up forwarding rules
Add extra padding on bottom of help docs
Remove unused style
Add emails help page
Improve formatting
Prefetch page content on iOS
Reduce the reader overly length now that items are precached
Add invalidation when highlights are added to items
fix missing index_settings.json file in api dockerfile for creating elastic index (#363)
Handle full email address objects in the to param from sendgrid
These come in a format like:
"jacksonh-dfdf@inbox.omnivore.app"
New IDs for short highlights because they dont cascade delete now
Testing CI issues
Simplify test
CI test
Use promises for async tests
Temporarily remove test to debug CI
Re-enable
re-enable test, return error
Specify a userId when looking up saved email pages
create a unique url for newsletters without a URL
Use 500ms on page test timeouts
Increase timeout
Dont use deep equal to match newsletter label
Run just the labels API
Run against just the newsletter emails
Run without the page tests
Fix
Set the allow uncaught flag
Remove highlight tests
Remove newsletters tests
more resolver tests
Remove newsetter tests
Comment out resolver tests
Use nock for external requests in tests
Specify puppeteer url for tests
Comment out more tests
uncomment tests
re-enable
re-enable email test
Re-disable
Re-enable one pdf attachment test
Re-disable pdf attachment test
Use promises on setTimeout tests
rm label tests
mv label tests into a context
Comment out pdf tests
Comment out pdf tests
Async test
Async wrappers
Delay when creating test pages
More debugging
Unique short ids
Remove potentially problematic test
Fetch page before returning for test
handler in before block
more debugging
More debugging
Move errors checks into contexts
Use a context when saving newsletters to force index refresh
Prettier fix
Fix newsletter label check, remove setTimeout
Re-enable test
timeout on pdf router handler
Fix method call
comment out PDF test
Unique fake username
Comment out PDF test
Debugging signed urls
Re-enable
New email
pdf test
PDF tests
Comment out pdf test
Add nock stubs for email URLs
Use full address for PDF test
Remove debug
Use full email addresses
---
packages/api/.env.test | 2 +
packages/api/package.json | 4 +-
packages/api/src/routers/svc/emails.ts | 3 +-
packages/api/src/services/newsletters.ts | 15 ++-
packages/api/src/services/save_email.ts | 4 +-
.../api/src/services/save_newsletter_email.ts | 9 +-
packages/api/test/elastic/index.test.ts | 2 -
packages/api/test/resolvers/highlight.test.ts | 4 +-
packages/api/test/resolvers/labels.test.ts | 126 +++++++++++-------
.../api/test/resolvers/newsletters.test.ts | 4 +-
.../api/test/routers/article_router.test.ts | 3 +-
.../api/test/routers/pdf_attachments.test.ts | 2 +-
packages/api/test/services/labels.test.ts | 66 ++++-----
packages/api/test/services/save_email.test.ts | 17 +--
.../services/save_newsletter_email.test.ts | 42 +++---
packages/api/test/util.ts | 10 +-
packages/api/test/utils/parser.test.ts | 10 ++
packages/readabilityjs/Readability.js | 1 -
yarn.lock | 12 ++
19 files changed, 205 insertions(+), 131 deletions(-)
diff --git a/packages/api/.env.test b/packages/api/.env.test
index cb55a1b02..d3b940a69 100644
--- a/packages/api/.env.test
+++ b/packages/api/.env.test
@@ -27,3 +27,5 @@ PREVIEW_IMAGE_WRAPPER_ID='selected_highlight_wrapper'
SEGMENT_WRITE_KEY='test'
REMINDER_TASK_HANDLER_URL=http://localhost:4000/svc/reminders/trigger
PUBSUB_VERIFICATION_TOKEN='123456'
+PUPPETEER_TASK_HANDLER_URL=http://localhost:9090/
+
diff --git a/packages/api/package.json b/packages/api/package.json
index 3fdc6ded2..73fd953f9 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -8,7 +8,7 @@
"start": "node dist/server.js",
"lint": "eslint src --ext ts,js,tsx,jsx",
"lint:fix": "eslint src --fix --ext ts,js,tsx,jsx",
- "test": "nyc mocha -r ts-node/register --config mocha-config.json --exit --timeout 10000"
+ "test": "nyc mocha -r ts-node/register --config mocha-config.json --exit --timeout 10000 --allow-uncaught --check-leaks"
},
"dependencies": {
"@elastic/elasticsearch": "~7.12.0",
@@ -84,6 +84,7 @@
"knex-stringcase": "^1.4.2",
"luxon": "^1.25.0",
"nanoid": "^3.1.25",
+ "nodemailer": "^6.7.3",
"normalize-url": "^6.1.0",
"oauth": "^0.9.15",
"pg": "^8.3.3",
@@ -107,6 +108,7 @@
"@types/analytics-node": "^3.1.7",
"@types/highlightjs": "^9.12.2",
"@types/nanoid": "^3.0.0",
+ "@types/nodemailer": "^6.4.4",
"@types/private-ip": "^1.0.0",
"chai": "^4.3.4",
"chai-string": "^1.5.0",
diff --git a/packages/api/src/routers/svc/emails.ts b/packages/api/src/routers/svc/emails.ts
index 4bb9aa6df..4bc000d81 100644
--- a/packages/api/src/routers/svc/emails.ts
+++ b/packages/api/src/routers/svc/emails.ts
@@ -4,6 +4,7 @@ import { sendEmail } from '../../utils/sendEmail'
import { analytics } from '../../utils/analytics'
import { getNewsletterEmail } from '../../services/newsletters'
import { env } from '../../env'
+import { v4 as uuid } from 'uuid'
import { findNewsletterUrl, isProbablyNewsletter } from '../../utils/parser'
import { saveNewsletterEmail } from '../../services/save_newsletter_email'
@@ -59,7 +60,7 @@ export function emailsServiceRouter() {
author: data.from,
url:
(await findNewsletterUrl(data.html)) ||
- 'https://omnivore.app/no_url',
+ 'https://omnivore.app/no_url?q' + uuid(),
})
res.status(200).send('Newsletter')
return
diff --git a/packages/api/src/services/newsletters.ts b/packages/api/src/services/newsletters.ts
index 1ff5949d6..21fe94180 100644
--- a/packages/api/src/services/newsletters.ts
+++ b/packages/api/src/services/newsletters.ts
@@ -4,6 +4,15 @@ import { nanoid } from 'nanoid'
import { User } from '../entity/user'
import { CreateNewsletterEmailErrorCode } from '../generated/graphql'
import { env } from '../env'
+import addressparser from 'nodemailer/lib/addressparser'
+
+const parsedAddress = (emailAddress: string): string | undefined => {
+ const res = addressparser(emailAddress, { flatten: true })
+ if (!res || res.length < 1) {
+ return undefined
+ }
+ return res[0].address
+}
export const createNewsletterEmail = async (
userId: string
@@ -46,9 +55,10 @@ export const updateConfirmationCode = async (
emailAddress: string,
confirmationCode: string
): Promise => {
+ const address = parsedAddress(emailAddress)
const result = await getRepository(NewsletterEmail)
.createQueryBuilder()
- .where('address ILIKE :address', { address: emailAddress })
+ .where('address ILIKE :address', { address })
.update({
confirmationCode: confirmationCode,
})
@@ -60,10 +70,11 @@ export const updateConfirmationCode = async (
export const getNewsletterEmail = async (
emailAddress: string
): Promise => {
+ const address = parsedAddress(emailAddress)
return getRepository(NewsletterEmail)
.createQueryBuilder('newsletter_email')
.innerJoinAndSelect('newsletter_email.user', 'user')
- .where('address ILIKE :address', { address: emailAddress })
+ .where('address ILIKE :address', { address })
.getOne()
}
diff --git a/packages/api/src/services/save_email.ts b/packages/api/src/services/save_email.ts
index 590d983d9..a733f84be 100644
--- a/packages/api/src/services/save_email.ts
+++ b/packages/api/src/services/save_email.ts
@@ -12,6 +12,7 @@ import { createPage, getPageByParam, updatePage } from '../elastic'
export type SaveContext = {
pubsub: PubsubClient
uid: string
+ refresh?: boolean
}
export type SaveEmailInput = {
@@ -67,7 +68,7 @@ export const saveEmail = async (
readingProgressPercent: 0,
}
- const page = await getPageByParam({ url: articleToSave.url })
+ const page = await getPageByParam({ userId: ctx.uid, url: articleToSave.url })
if (page) {
const result = await updatePage(page.id, { archivedAt: null }, ctx)
console.log('updated page from email', result)
@@ -82,7 +83,6 @@ export const saveEmail = async (
return undefined
}
- console.log('created new page from email', pageId)
articleToSave.id = pageId
return articleToSave
diff --git a/packages/api/src/services/save_newsletter_email.ts b/packages/api/src/services/save_newsletter_email.ts
index 039082d34..df879df1c 100644
--- a/packages/api/src/services/save_newsletter_email.ts
+++ b/packages/api/src/services/save_newsletter_email.ts
@@ -22,7 +22,8 @@ interface NewsletterMessage {
// Returns true if the link was created successfully. Can still fail to
// send the push but that is ok and we wont retry in that case.
export const saveNewsletterEmail = async (
- data: NewsletterMessage
+ data: NewsletterMessage,
+ ctx?: SaveContext
): Promise => {
// get user from newsletter email
const newsletterEmail = await getNewsletterEmail(data.email)
@@ -43,7 +44,7 @@ export const saveNewsletterEmail = async (
},
})
- const ctx: SaveContext = {
+ const saveCtx = ctx || {
pubsub: createPubSubClient(),
uid: newsletterEmail.user.id,
}
@@ -55,14 +56,14 @@ export const saveNewsletterEmail = async (
author: data.author,
}
- const page = await saveEmail(ctx, input)
+ const page = await saveEmail(saveCtx, input)
if (!page) {
console.log('newsletter not created:', input)
return false
}
// add newsletters label to page
- const result = await addLabelToPage(ctx, page.id, {
+ const result = await addLabelToPage(saveCtx, page.id, {
name: 'Newsletter',
color: '#07D2D1',
})
diff --git a/packages/api/test/elastic/index.test.ts b/packages/api/test/elastic/index.test.ts
index 2d6983114..29e86d07d 100644
--- a/packages/api/test/elastic/index.test.ts
+++ b/packages/api/test/elastic/index.test.ts
@@ -113,7 +113,6 @@ describe('elastic api', () => {
describe('getPageById', () => {
it('gets a page by id', async () => {
const pageFound = await getPageById(page.id)
-
expect(pageFound).not.undefined
})
})
@@ -128,7 +127,6 @@ describe('elastic api', () => {
await updatePage(page.id, updatedPageData, ctx)
const updatedPage = await getPageById(page.id)
-
expect(updatedPage?.title).to.eql(newTitle)
})
})
diff --git a/packages/api/test/resolvers/highlight.test.ts b/packages/api/test/resolvers/highlight.test.ts
index e72f635fe..f76898897 100644
--- a/packages/api/test/resolvers/highlight.test.ts
+++ b/packages/api/test/resolvers/highlight.test.ts
@@ -137,7 +137,7 @@ describe('Highlights API', () => {
before(async () => {
// create test highlight
highlightId = generateFakeUuid()
- const shortHighlightId = '_short_id'
+ const shortHighlightId = '_short_id_1'
const query = createHighlightQuery(
authToken,
pageId,
@@ -149,7 +149,7 @@ describe('Highlights API', () => {
it('should not fail', async () => {
const newHighlightId = generateFakeUuid()
- const newShortHighlightId = '_short_id_1'
+ const newShortHighlightId = '_short_id_2'
const query = mergeHighlightQuery(
pageId,
newHighlightId,
diff --git a/packages/api/test/resolvers/labels.test.ts b/packages/api/test/resolvers/labels.test.ts
index 66e221e1a..26399359b 100644
--- a/packages/api/test/resolvers/labels.test.ts
+++ b/packages/api/test/resolvers/labels.test.ts
@@ -22,31 +22,40 @@ describe('Labels API', () => {
let labels: Label[]
before(async () => {
- // create test user and login
- user = await createTestUser(username)
- const res = await request
- .post('/local/debug/fake-user-login')
- .send({ fakeEmail: user.email })
+ try {
+ // create test user and login
+ user = await createTestUser(username)
+ const res = await request
+ .post('/local/debug/fake-user-login')
+ .send({ fakeEmail: user.email })
- authToken = res.body.authToken
+ authToken = res.body.authToken
- // create testing labels
- const label1 = await createTestLabel(user, 'label_1', '#ffffff')
- const label2 = await createTestLabel(user, 'label_2', '#eeeeee')
- labels = [label1, label2]
+ // create testing labels
+ const label1 = await createTestLabel(user, 'label_1', '#ffffff')
+ const label2 = await createTestLabel(user, 'label_2', '#eeeeee')
+ labels = [label1, label2]
- // create a page with label
- const existingLabelOfLink = await createTestLabel(
- user,
- 'different_label',
- '#dddddd'
- )
- page = await createTestElasticPage(user, [existingLabelOfLink])
+ // create a page with label
+ const existingLabelOfLink = await createTestLabel(
+ user,
+ 'different_label',
+ '#dddddd'
+ )
+ page = await createTestElasticPage(user, [existingLabelOfLink])
+ console.log('created elastic page', page)
+ } catch (err) {
+ console.log('error in setup', err)
+ }
})
after(async () => {
// clean up
- await deleteTestUser(username)
+ try {
+ await deleteTestUser(username)
+ } catch (err) {
+ console.log('error in cleanup', err)
+ }
})
describe('GET labels', () => {
@@ -220,18 +229,20 @@ describe('Labels API', () => {
})
})
- it('responds status code 400 when invalid query', async () => {
- const invalidQuery = `
- mutation {
- deleteLabel {}
- }
- `
- return graphqlRequest(invalidQuery, authToken).expect(400)
- })
+ context('error states', () => {
+ it('responds status code 400 when invalid query', async () => {
+ const invalidQuery = `
+ mutation {
+ deleteLabel {}
+ }
+ `
+ return graphqlRequest(invalidQuery, authToken).expect(400)
+ })
- it('responds status code 500 when invalid user', async () => {
- const invalidAuthToken = 'Fake token'
- return graphqlRequest(query, invalidAuthToken).expect(500)
+ it('responds status code 500 when invalid user', async () => {
+ const invalidAuthToken = 'Fake token'
+ return graphqlRequest(query, invalidAuthToken).expect(500)
+ })
})
})
@@ -266,21 +277,28 @@ describe('Labels API', () => {
`
})
- context('when labels exists', () => {
- before(() => {
- pageId = page.id
- labelIds = [labels[0].id, labels[1].id]
- })
+ // context('when labels exists', () => {
+ // before(() => {
+ // pageId = page.id
+ // labelIds = [labels[0].id, labels[1].id]
+ // })
- it('should set labels', async () => {
- await graphqlRequest(query, authToken).expect(200)
- const page = await getPageById(pageId)
- expect(page?.labels?.map((l) => l.id)).to.eql(labelIds)
- })
- })
+ // it('should set labels', async () => {
+ // await graphqlRequest(query, authToken).expect(200)
+ // return new Promise((resolve, reject) => {
+ // setTimeout(async () => {
+ // const page = await getPageById(pageId)
+ // console.log('got page', page, pageId)
+ // expect(page?.labels?.map((l) => l.id)).to.eql(labelIds)
+ // resolve()
+ // }, 1000)
+ // })
+ // })
+ // })
context('when labels not exist', () => {
before(() => {
+ console.log('page id', page)
pageId = page.id
labelIds = [generateFakeUuid(), generateFakeUuid()]
})
@@ -303,18 +321,24 @@ describe('Labels API', () => {
})
})
- it('responds status code 400 when invalid query', async () => {
- const invalidQuery = `
- mutation {
- setLabels {}
- }
- `
- return graphqlRequest(invalidQuery, authToken).expect(400)
- })
+ context('invalid request', () => {
+ before(() => {
+ pageId = generateFakeUuid()
+ labelIds = [labels[0].id, labels[1].id]
+ })
+ it('responds status code 400 when invalid query', async () => {
+ const invalidQuery = `
+ mutation {
+ setLabels {}
+ }
+ `
+ return graphqlRequest(invalidQuery, authToken).expect(400)
+ })
- it('responds status code 500 when invalid user', async () => {
- const invalidAuthToken = 'Fake token'
- return graphqlRequest(query, invalidAuthToken).expect(500)
+ it('responds status code 500 when invalid user', async () => {
+ const invalidAuthToken = 'Fake token'
+ return graphqlRequest(query, invalidAuthToken).expect(500)
+ })
})
})
})
diff --git a/packages/api/test/resolvers/newsletters.test.ts b/packages/api/test/resolvers/newsletters.test.ts
index 8c8a8d199..c762a9a3a 100644
--- a/packages/api/test/resolvers/newsletters.test.ts
+++ b/packages/api/test/resolvers/newsletters.test.ts
@@ -28,11 +28,11 @@ describe('Newsletters API', () => {
// create test newsletter emails
const newsletterEmail1 = await createTestNewsletterEmail(
user,
- 'Test_email_address_1'
+ 'Test_email_address_1@fake-email.com'
)
const newsletterEmail2 = await createTestNewsletterEmail(
user,
- 'Test_email_address_2'
+ 'Test_email_address_2@fake-email.com'
)
newsletterEmails = [newsletterEmail1, newsletterEmail2]
})
diff --git a/packages/api/test/routers/article_router.test.ts b/packages/api/test/routers/article_router.test.ts
index 1671fdef0..06fba8bb1 100644
--- a/packages/api/test/routers/article_router.test.ts
+++ b/packages/api/test/routers/article_router.test.ts
@@ -3,6 +3,7 @@ import { request } from '../util'
import { expect } from 'chai'
import nock from 'nock'
import 'mocha'
+import { env } from '../../src/env'
describe('/article/save API', () => {
const username = 'fakeUser'
@@ -12,7 +13,7 @@ describe('/article/save API', () => {
// We need to mock the pupeeteer-parse
// service here because in dev mode the task gets
// called immediately.
- nock('http://localhost:8080/').post('/').reply(200)
+ nock(env.queue.puppeteerTaskHanderUrl).post('/').reply(200)
before(async () => {
// create test user and login
diff --git a/packages/api/test/routers/pdf_attachments.test.ts b/packages/api/test/routers/pdf_attachments.test.ts
index 512b1c789..9e0648fe0 100644
--- a/packages/api/test/routers/pdf_attachments.test.ts
+++ b/packages/api/test/routers/pdf_attachments.test.ts
@@ -12,7 +12,7 @@ import { getPageById } from '../../src/elastic'
describe('PDF attachments Router', () => {
const username = 'fakeUser'
- const newsletterEmail = 'fakeEmail'
+ const newsletterEmail = 'fakeEmail@fake-email.com'
let user: User
let authToken: string
diff --git a/packages/api/test/services/labels.test.ts b/packages/api/test/services/labels.test.ts
index 354af4e44..427978f88 100644
--- a/packages/api/test/services/labels.test.ts
+++ b/packages/api/test/services/labels.test.ts
@@ -14,42 +14,42 @@ import { LinkLabel } from '../../src/entity/link_label'
import { Label } from '../../src/entity/label'
import { Link } from '../../src/entity/link'
-describe('batch get labels from linkIds', () => {
- let username = 'testUser'
- let labels: Label[] = []
- let link: Link
+// describe('batch get labels from linkIds', () => {
+// let username = 'testUser'
+// let labels: Label[] = []
+// let link: Link
- before(async () => {
- // create test user
- const user = await createTestUser(username)
+// before(async () => {
+// // create test user
+// const user = await createTestUser(username)
- // Create some test links
- const page = await createTestPage()
- link = await createTestLink(user, page)
+// // Create some test links
+// const page = await createTestPage()
+// link = await createTestLink(user, page)
- for (let i = 0; i < 3; i++) {
- // create testing labels
- const label = await createTestLabel(user, `label_${i}`, '#d55757')
- // set label to a link
- await getRepository(LinkLabel).save({
- link: link,
- label: label,
- })
- labels.push(label)
- }
- })
+// for (let i = 0; i < 3; i++) {
+// // create testing labels
+// const label = await createTestLabel(user, `label_${i}`, '#d55757')
+// // set label to a link
+// await getRepository(LinkLabel).save({
+// link: link,
+// label: label,
+// })
+// labels.push(label)
+// }
+// })
- after(async () => {
- // clean up
- await deleteTestUser(username)
- })
+// after(async () => {
+// // clean up
+// await deleteTestUser(username)
+// })
- it('should return a list of label from one link', async () => {
- const result = await labelsLoader.load(link.id)
+// it('should return a list of label from one link', async () => {
+// const result = await labelsLoader.load(link.id)
- expect(result).length(3)
- expect(result[0].id).to.eql(labels[0].id)
- expect(result[1].id).to.eql(labels[1].id)
- expect(result[2].id).to.eql(labels[2].id)
- })
-})
+// expect(result).length(3)
+// expect(result[0].id).to.eql(labels[0].id)
+// expect(result[1].id).to.eql(labels[1].id)
+// expect(result[2].id).to.eql(labels[2].id)
+// })
+// })
diff --git a/packages/api/test/services/save_email.test.ts b/packages/api/test/services/save_email.test.ts
index 1f08cf75b..cd4724636 100644
--- a/packages/api/test/services/save_email.test.ts
+++ b/packages/api/test/services/save_email.test.ts
@@ -17,6 +17,7 @@ describe('saveEmail', () => {
const ctx: SaveContext = {
pubsub: createPubSubClient(),
uid: user.id,
+ refresh: true,
}
await saveEmail(ctx, {
@@ -36,15 +37,11 @@ describe('saveEmail', () => {
})
expect(secondResult).to.not.be.undefined
- setTimeout(async () => {
- const page = await getPageByParam({ userId: user.id })
- if (!page) {
- expect.fail('page not found')
- }
- expect(page.url).to.equal('https://example.com')
- expect(page.title).to.equal('fake title')
- expect(page.author).to.equal('fake author')
- expect(page.content).to.contain('fake content')
- })
+ const page = await getPageByParam({ userId: user.id })
+ expect(page).to.exist
+ expect(page?.url).to.equal('https://example.com')
+ expect(page?.title).to.equal('fake title')
+ expect(page?.author).to.equal('fake author')
+ expect(page?.content).to.contain('fake content')
})
})
diff --git a/packages/api/test/services/save_newsletter_email.test.ts b/packages/api/test/services/save_newsletter_email.test.ts
index cbd070f26..398ad3ef6 100644
--- a/packages/api/test/services/save_newsletter_email.test.ts
+++ b/packages/api/test/services/save_newsletter_email.test.ts
@@ -7,16 +7,28 @@ import { saveNewsletterEmail } from '../../src/services/save_newsletter_email'
import { getPageByParam } from '../../src/elastic'
import { User } from '../../src/entity/user'
import { NewsletterEmail } from '../../src/entity/newsletter_email'
+import { SaveContext } from '../../src/services/save_email'
+import { createPubSubClient } from '../../src/datalayer/pubsub'
+import nock from 'nock'
describe('saveNewsletterEmail', () => {
const username = 'fakeUser'
let user: User
let email: NewsletterEmail
+ let ctx: SaveContext
before(async () => {
user = await createTestUser(username)
email = await createNewsletterEmail(user.id)
+ ctx = {
+ pubsub: createPubSubClient(),
+ uid: user.id,
+ refresh: true,
+ }
+ nock('https://example.com')
+ .get(/\/(.*)?$/)
+ .reply(200);
})
after(async () => {
@@ -30,18 +42,16 @@ describe('saveNewsletterEmail', () => {
url: 'https://example.com',
title: 'fake title',
author: 'fake author',
- })
+ }, ctx)
- setTimeout(async () => {
- const page = await getPageByParam({ userId: user.id })
- if (!page) {
- expect.fail('page not found')
- }
- expect(page.url).to.equal('https://example.com')
- expect(page.title).to.equal('fake title')
- expect(page.author).to.equal('fake author')
- expect(page.content).to.contain('fake content')
- })
+ const page = await getPageByParam({ userId: user.id })
+ if (!page) {
+ expect.fail('page not found')
+ }
+ expect(page.url).to.equal('https://example.com')
+ expect(page.title).to.equal('fake title')
+ expect(page.author).to.equal('fake author')
+ expect(page.content).to.contain('fake content')
})
it('should adds a Newsletter label to that page', async () => {
@@ -56,11 +66,11 @@ describe('saveNewsletterEmail', () => {
url: 'https://example.com/2',
title: 'fake title',
author: 'fake author',
- })
+ }, ctx)
- setTimeout(async () => {
- const page = await getPageByParam({ userId: user.id })
- expect(page?.labels).to.deep.include(newLabel)
- })
+ const page = await getPageByParam({ userId: user.id })
+ const newsletterLabel = page?.labels?.find(l => l.name === 'Newsletter')
+ expect(newsletterLabel).to.exist
+ expect(newsletterLabel?.color).to.equal(newLabel.color)
})
})
diff --git a/packages/api/test/util.ts b/packages/api/test/util.ts
index e3a84dac9..b53342fde 100644
--- a/packages/api/test/util.ts
+++ b/packages/api/test/util.ts
@@ -4,7 +4,7 @@ import { v4 } from 'uuid'
import { corsConfig } from '../src/utils/corsConfig'
import { Page } from '../src/elastic/types'
import { PageType } from '../src/generated/graphql'
-import { createPage } from '../src/elastic'
+import { createPage, getPageById } from '../src/elastic'
import { User } from '../src/entity/user'
import { Label } from '../src/entity/label'
import { createPubSubClient } from '../src/datalayer/pubsub'
@@ -62,5 +62,11 @@ export const createTestElasticPage = async (
if (pageId) {
page.id = pageId
}
- return page
+
+ const res = await getPageById(page.id)
+ console.log('got page', res)
+ if (!res) {
+ throw new Error('Failed to create page')
+ }
+ return res
}
diff --git a/packages/api/test/utils/parser.test.ts b/packages/api/test/utils/parser.test.ts
index 2c877236c..87c48e1b0 100644
--- a/packages/api/test/utils/parser.test.ts
+++ b/packages/api/test/utils/parser.test.ts
@@ -30,12 +30,22 @@ describe('isProbablyNewsletter', () => {
describe('findNewsletterUrl', async () => {
it('gets the URL from the header if it is a substack newsletter', async () => {
+ nock('https://newsletter.slowchinese.net')
+ .head('/p/companies-that-eat-people-217?token=eyJ1c2VyX2lkIjoxMTU0MzM0NSwicG9zdF9pZCI6NDg3MjA5NDAsImlhdCI6MTY0NTI1NzQ1MSwiaXNzIjoicHViLTI4MDUzMSIsInN1YiI6InBvc3QtcmVhY3Rpb24ifQ.l5F3Kx6K9tvy9cRAXx3MepobQBCJDJQgAxOpA0INIZA')
+ .reply(200, '');
const html = load('./test/utils/data/substack-forwarded-newsletter.html')
const url = await findNewsletterUrl(html)
// Not sure if the redirects from substack expire, this test could eventually fail
expect(url).to.startWith('https://newsletter.slowchinese.net/p/companies-that-eat-people-217')
})
it('gets the URL from the header if it is a beehiiv newsletter', async () => {
+ nock('https://u23463625.ct.sendgrid.net')
+ .head('/ss/c/AX1lEgEQaxtvFxLaVo0GBo_geajNrlI1TGeIcmMViR3pL3fEDZnbbkoeKcaY62QZk0KPFudUiUXc_uMLerV4nA/3k5/3TFZmreTR0qKSCgowABnVg/h30/zzLik7UXd1H_n4oyd5W8Xu639AYQQB2UXz-CsssSnno')
+ .reply(302, undefined,{
+ 'Location': 'https://www.milkroad.com/p/talked-guy-spent-30m-beeple'
+ })
+ .get('/p/talked-guy-spent-30m-beeple')
+ .reply(200, '');
const html = load('./test/utils/data/beehiiv-newsletter.html')
const url = await findNewsletterUrl(html)
expect(url).to.startWith('https://www.milkroad.com/p/talked-guy-spent-30m-beeple')
diff --git a/packages/readabilityjs/Readability.js b/packages/readabilityjs/Readability.js
index ef71eba99..f91dc4dc6 100644
--- a/packages/readabilityjs/Readability.js
+++ b/packages/readabilityjs/Readability.js
@@ -68,7 +68,6 @@ const extractPublishedDateFromAuthor = (author)=> {
* @param {Object} options The options object.
*/
function Readability(doc, options) {
- console.log("\nOmnivore Inc. v.0.1.9");
// In some older versions, people passed a URI as the first argument. Cope:
if (options && options.documentElement) {
doc = options;
diff --git a/yarn.lock b/yarn.lock
index f53b5f2ca..2e0ae8cf2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6417,6 +6417,13 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.32.tgz#2ca61c9ef8c77f6fa1733be9e623ceb0d372ad96"
integrity sha512-JcII3D5/OapPGx+eJ+Ik1SQGyt6WvuqdRfh9jUwL6/iHGjmyOriBDciBUu7lEIBTL2ijxwrR70WUnw5AEDmFvQ==
+"@types/nodemailer@^6.4.4":
+ version "6.4.4"
+ resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.4.tgz#c265f7e7a51df587597b3a49a023acaf0c741f4b"
+ integrity sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw==
+ dependencies:
+ "@types/node" "*"
+
"@types/normalize-package-data@^2.4.0":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
@@ -15023,6 +15030,11 @@ node-releases@^2.0.1, node-releases@^2.0.2:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01"
integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==
+nodemailer@^6.7.3:
+ version "6.7.3"
+ resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.3.tgz#b73f9a81b9c8fa8acb4ea14b608f5e725ea8e018"
+ integrity sha512-KUdDsspqx89sD4UUyUKzdlUOper3hRkDVkrKh/89G+d9WKsU5ox51NWS4tB1XR5dPUdR4SP0E3molyEfOvSa3g==
+
nodemon@^2.0.15:
version "2.0.15"
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.15.tgz#504516ce3b43d9dc9a955ccd9ec57550a31a8d4e"
From f6cfa2f9d2293b09f0337f5685df1afe61762c61 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Sat, 2 Apr 2022 17:00:45 -0700
Subject: [PATCH 036/298] Revert test files that dont need to be changed
---
packages/api/test/resolvers/labels.test.ts | 126 +++++++-----------
packages/api/test/services/labels.test.ts | 66 ++++-----
.../services/save_newsletter_email.test.ts | 42 +++---
3 files changed, 100 insertions(+), 134 deletions(-)
diff --git a/packages/api/test/resolvers/labels.test.ts b/packages/api/test/resolvers/labels.test.ts
index 26399359b..66e221e1a 100644
--- a/packages/api/test/resolvers/labels.test.ts
+++ b/packages/api/test/resolvers/labels.test.ts
@@ -22,40 +22,31 @@ describe('Labels API', () => {
let labels: Label[]
before(async () => {
- try {
- // create test user and login
- user = await createTestUser(username)
- const res = await request
- .post('/local/debug/fake-user-login')
- .send({ fakeEmail: user.email })
+ // create test user and login
+ user = await createTestUser(username)
+ const res = await request
+ .post('/local/debug/fake-user-login')
+ .send({ fakeEmail: user.email })
- authToken = res.body.authToken
+ authToken = res.body.authToken
- // create testing labels
- const label1 = await createTestLabel(user, 'label_1', '#ffffff')
- const label2 = await createTestLabel(user, 'label_2', '#eeeeee')
- labels = [label1, label2]
+ // create testing labels
+ const label1 = await createTestLabel(user, 'label_1', '#ffffff')
+ const label2 = await createTestLabel(user, 'label_2', '#eeeeee')
+ labels = [label1, label2]
- // create a page with label
- const existingLabelOfLink = await createTestLabel(
- user,
- 'different_label',
- '#dddddd'
- )
- page = await createTestElasticPage(user, [existingLabelOfLink])
- console.log('created elastic page', page)
- } catch (err) {
- console.log('error in setup', err)
- }
+ // create a page with label
+ const existingLabelOfLink = await createTestLabel(
+ user,
+ 'different_label',
+ '#dddddd'
+ )
+ page = await createTestElasticPage(user, [existingLabelOfLink])
})
after(async () => {
// clean up
- try {
- await deleteTestUser(username)
- } catch (err) {
- console.log('error in cleanup', err)
- }
+ await deleteTestUser(username)
})
describe('GET labels', () => {
@@ -229,20 +220,18 @@ describe('Labels API', () => {
})
})
- context('error states', () => {
- it('responds status code 400 when invalid query', async () => {
- const invalidQuery = `
- mutation {
- deleteLabel {}
- }
- `
- return graphqlRequest(invalidQuery, authToken).expect(400)
- })
+ it('responds status code 400 when invalid query', async () => {
+ const invalidQuery = `
+ mutation {
+ deleteLabel {}
+ }
+ `
+ return graphqlRequest(invalidQuery, authToken).expect(400)
+ })
- it('responds status code 500 when invalid user', async () => {
- const invalidAuthToken = 'Fake token'
- return graphqlRequest(query, invalidAuthToken).expect(500)
- })
+ it('responds status code 500 when invalid user', async () => {
+ const invalidAuthToken = 'Fake token'
+ return graphqlRequest(query, invalidAuthToken).expect(500)
})
})
@@ -277,28 +266,21 @@ describe('Labels API', () => {
`
})
- // context('when labels exists', () => {
- // before(() => {
- // pageId = page.id
- // labelIds = [labels[0].id, labels[1].id]
- // })
+ context('when labels exists', () => {
+ before(() => {
+ pageId = page.id
+ labelIds = [labels[0].id, labels[1].id]
+ })
- // it('should set labels', async () => {
- // await graphqlRequest(query, authToken).expect(200)
- // return new Promise((resolve, reject) => {
- // setTimeout(async () => {
- // const page = await getPageById(pageId)
- // console.log('got page', page, pageId)
- // expect(page?.labels?.map((l) => l.id)).to.eql(labelIds)
- // resolve()
- // }, 1000)
- // })
- // })
- // })
+ it('should set labels', async () => {
+ await graphqlRequest(query, authToken).expect(200)
+ const page = await getPageById(pageId)
+ expect(page?.labels?.map((l) => l.id)).to.eql(labelIds)
+ })
+ })
context('when labels not exist', () => {
before(() => {
- console.log('page id', page)
pageId = page.id
labelIds = [generateFakeUuid(), generateFakeUuid()]
})
@@ -321,24 +303,18 @@ describe('Labels API', () => {
})
})
- context('invalid request', () => {
- before(() => {
- pageId = generateFakeUuid()
- labelIds = [labels[0].id, labels[1].id]
- })
- it('responds status code 400 when invalid query', async () => {
- const invalidQuery = `
- mutation {
- setLabels {}
- }
- `
- return graphqlRequest(invalidQuery, authToken).expect(400)
- })
+ it('responds status code 400 when invalid query', async () => {
+ const invalidQuery = `
+ mutation {
+ setLabels {}
+ }
+ `
+ return graphqlRequest(invalidQuery, authToken).expect(400)
+ })
- it('responds status code 500 when invalid user', async () => {
- const invalidAuthToken = 'Fake token'
- return graphqlRequest(query, invalidAuthToken).expect(500)
- })
+ it('responds status code 500 when invalid user', async () => {
+ const invalidAuthToken = 'Fake token'
+ return graphqlRequest(query, invalidAuthToken).expect(500)
})
})
})
diff --git a/packages/api/test/services/labels.test.ts b/packages/api/test/services/labels.test.ts
index 427978f88..354af4e44 100644
--- a/packages/api/test/services/labels.test.ts
+++ b/packages/api/test/services/labels.test.ts
@@ -14,42 +14,42 @@ import { LinkLabel } from '../../src/entity/link_label'
import { Label } from '../../src/entity/label'
import { Link } from '../../src/entity/link'
-// describe('batch get labels from linkIds', () => {
-// let username = 'testUser'
-// let labels: Label[] = []
-// let link: Link
+describe('batch get labels from linkIds', () => {
+ let username = 'testUser'
+ let labels: Label[] = []
+ let link: Link
-// before(async () => {
-// // create test user
-// const user = await createTestUser(username)
+ before(async () => {
+ // create test user
+ const user = await createTestUser(username)
-// // Create some test links
-// const page = await createTestPage()
-// link = await createTestLink(user, page)
+ // Create some test links
+ const page = await createTestPage()
+ link = await createTestLink(user, page)
-// for (let i = 0; i < 3; i++) {
-// // create testing labels
-// const label = await createTestLabel(user, `label_${i}`, '#d55757')
-// // set label to a link
-// await getRepository(LinkLabel).save({
-// link: link,
-// label: label,
-// })
-// labels.push(label)
-// }
-// })
+ for (let i = 0; i < 3; i++) {
+ // create testing labels
+ const label = await createTestLabel(user, `label_${i}`, '#d55757')
+ // set label to a link
+ await getRepository(LinkLabel).save({
+ link: link,
+ label: label,
+ })
+ labels.push(label)
+ }
+ })
-// after(async () => {
-// // clean up
-// await deleteTestUser(username)
-// })
+ after(async () => {
+ // clean up
+ await deleteTestUser(username)
+ })
-// it('should return a list of label from one link', async () => {
-// const result = await labelsLoader.load(link.id)
+ it('should return a list of label from one link', async () => {
+ const result = await labelsLoader.load(link.id)
-// expect(result).length(3)
-// expect(result[0].id).to.eql(labels[0].id)
-// expect(result[1].id).to.eql(labels[1].id)
-// expect(result[2].id).to.eql(labels[2].id)
-// })
-// })
+ expect(result).length(3)
+ expect(result[0].id).to.eql(labels[0].id)
+ expect(result[1].id).to.eql(labels[1].id)
+ expect(result[2].id).to.eql(labels[2].id)
+ })
+})
diff --git a/packages/api/test/services/save_newsletter_email.test.ts b/packages/api/test/services/save_newsletter_email.test.ts
index 398ad3ef6..cbd070f26 100644
--- a/packages/api/test/services/save_newsletter_email.test.ts
+++ b/packages/api/test/services/save_newsletter_email.test.ts
@@ -7,28 +7,16 @@ import { saveNewsletterEmail } from '../../src/services/save_newsletter_email'
import { getPageByParam } from '../../src/elastic'
import { User } from '../../src/entity/user'
import { NewsletterEmail } from '../../src/entity/newsletter_email'
-import { SaveContext } from '../../src/services/save_email'
-import { createPubSubClient } from '../../src/datalayer/pubsub'
-import nock from 'nock'
describe('saveNewsletterEmail', () => {
const username = 'fakeUser'
let user: User
let email: NewsletterEmail
- let ctx: SaveContext
before(async () => {
user = await createTestUser(username)
email = await createNewsletterEmail(user.id)
- ctx = {
- pubsub: createPubSubClient(),
- uid: user.id,
- refresh: true,
- }
- nock('https://example.com')
- .get(/\/(.*)?$/)
- .reply(200);
})
after(async () => {
@@ -42,16 +30,18 @@ describe('saveNewsletterEmail', () => {
url: 'https://example.com',
title: 'fake title',
author: 'fake author',
- }, ctx)
+ })
- const page = await getPageByParam({ userId: user.id })
- if (!page) {
- expect.fail('page not found')
- }
- expect(page.url).to.equal('https://example.com')
- expect(page.title).to.equal('fake title')
- expect(page.author).to.equal('fake author')
- expect(page.content).to.contain('fake content')
+ setTimeout(async () => {
+ const page = await getPageByParam({ userId: user.id })
+ if (!page) {
+ expect.fail('page not found')
+ }
+ expect(page.url).to.equal('https://example.com')
+ expect(page.title).to.equal('fake title')
+ expect(page.author).to.equal('fake author')
+ expect(page.content).to.contain('fake content')
+ })
})
it('should adds a Newsletter label to that page', async () => {
@@ -66,11 +56,11 @@ describe('saveNewsletterEmail', () => {
url: 'https://example.com/2',
title: 'fake title',
author: 'fake author',
- }, ctx)
+ })
- const page = await getPageByParam({ userId: user.id })
- const newsletterLabel = page?.labels?.find(l => l.name === 'Newsletter')
- expect(newsletterLabel).to.exist
- expect(newsletterLabel?.color).to.equal(newLabel.color)
+ setTimeout(async () => {
+ const page = await getPageByParam({ userId: user.id })
+ expect(page?.labels).to.deep.include(newLabel)
+ })
})
})
From fc17daa5461c734453e14f50b6e0ae29d7bbd45e Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Sat, 2 Apr 2022 17:02:11 -0700
Subject: [PATCH 037/298] Remove unneeded mocha params
---
packages/api/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/api/package.json b/packages/api/package.json
index 73fd953f9..8fa9a30fd 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -8,7 +8,7 @@
"start": "node dist/server.js",
"lint": "eslint src --ext ts,js,tsx,jsx",
"lint:fix": "eslint src --fix --ext ts,js,tsx,jsx",
- "test": "nyc mocha -r ts-node/register --config mocha-config.json --exit --timeout 10000 --allow-uncaught --check-leaks"
+ "test": "nyc mocha -r ts-node/register --config mocha-config.json --exit --timeout 10000"
},
"dependencies": {
"@elastic/elasticsearch": "~7.12.0",
From 92925b6808ed4acb350f94e77958be609a8368c6 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Sun, 3 Apr 2022 10:21:16 -0700
Subject: [PATCH 038/298] Prettier fixes
---
packages/api/src/resolvers/labels/index.ts | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/packages/api/src/resolvers/labels/index.ts b/packages/api/src/resolvers/labels/index.ts
index 249105f78..e74454313 100644
--- a/packages/api/src/resolvers/labels/index.ts
+++ b/packages/api/src/resolvers/labels/index.ts
@@ -43,14 +43,11 @@ export const labelsResolver = authorized(
try {
const user = await getRepository(User)
- .createQueryBuilder("user")
- .innerJoinAndSelect(
- "user.labels",
- "labels",
- )
- .where("user.id = :uid", { uid })
- .orderBy("labels.createdAt", "DESC")
- .getOne()
+ .createQueryBuilder('user')
+ .innerJoinAndSelect('user.labels', 'labels')
+ .where('user.id = :uid', { uid })
+ .orderBy('labels.createdAt', 'DESC')
+ .getOne()
if (!user) {
return {
@@ -59,7 +56,10 @@ export const labelsResolver = authorized(
}
return {
- labels: user.labels?.sort((a,b) => a.createdAt.getTime() - b.createdAt.getTime()) || [],
+ labels:
+ user.labels?.sort(
+ (a, b) => a.createdAt.getTime() - b.createdAt.getTime()
+ ) || [],
}
} catch (error) {
log.error(error)
From 85b247321e6ef0fb0a22b231ac15b8179e6a97a5 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Sun, 3 Apr 2022 10:22:19 -0700
Subject: [PATCH 039/298] Upgrade yarn.lock
---
yarn.lock | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/yarn.lock b/yarn.lock
index f53b5f2ca..e39ad366d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -16594,6 +16594,11 @@ react-apple-login@^1.1.3:
resolved "https://registry.yarnpkg.com/react-apple-login/-/react-apple-login-1.1.3.tgz#5cb047a52a251fc52d920c7b4d9151d411994997"
integrity sha512-I6/2WQEfum9QGowHs9Maea5JhzsOjl8dMCqFP5got+jnnNZRimLE6wGambAvDXdiOuLr+gwMQx5W4JeBGKJHTA==
+react-colorful@^5.5.1:
+ version "5.5.1"
+ resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.5.1.tgz#29d9c4e496f2ca784dd2bb5053a3a4340cfaf784"
+ integrity sha512-M1TJH2X3RXEt12sWkpa6hLc/bbYS0H6F4rIqjQZ+RxNBstpY67d9TrFXtqdZwhpmBXcCwEi7stKqFue3ZRkiOg==
+
react-dom@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
From b668114c334a7d0d28577a01ce92db15e6a2a3fe Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 07:50:16 -0700
Subject: [PATCH 040/298] Fix multistage docker build
---
packages/api/Dockerfile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile
index 2727fd217..9403f8cfd 100644
--- a/packages/api/Dockerfile
+++ b/packages/api/Dockerfile
@@ -2,7 +2,7 @@ FROM node:14.18-alpine as builder
WORKDIR /app
-ENV NODE_ENV production
+ENV NODE_ENV development
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
COPY package.json .
@@ -14,7 +14,7 @@ COPY .eslintrc .
COPY /packages/readabilityjs/package.json ./packages/readabilityjs/package.json
COPY /packages/api/package.json ./packages/api/package.json
-RUN yarn install --pure-lockfile --production
+RUN yarn install --pure-lockfile
ADD /packages/readabilityjs ./packages/readabilityjs
ADD /packages/api ./packages/api
From 87077be85e5c9875c608eaab4a7041597292713b Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 08:11:06 -0700
Subject: [PATCH 041/298] First stage of build is development
---
packages/api/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile
index 9403f8cfd..075958b7a 100644
--- a/packages/api/Dockerfile
+++ b/packages/api/Dockerfile
@@ -14,7 +14,7 @@ COPY .eslintrc .
COPY /packages/readabilityjs/package.json ./packages/readabilityjs/package.json
COPY /packages/api/package.json ./packages/api/package.json
-RUN yarn install --pure-lockfile
+RUN yarn install --pure-lockfile --development
ADD /packages/readabilityjs ./packages/readabilityjs
ADD /packages/api ./packages/api
From c8ec7d636efaeb819eb37425bb8af21731e94e95 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 08:11:26 -0700
Subject: [PATCH 042/298] Use require to import address parser function
---
packages/api/src/services/newsletters.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/api/src/services/newsletters.ts b/packages/api/src/services/newsletters.ts
index 21fe94180..16b8c8810 100644
--- a/packages/api/src/services/newsletters.ts
+++ b/packages/api/src/services/newsletters.ts
@@ -4,7 +4,7 @@ import { nanoid } from 'nanoid'
import { User } from '../entity/user'
import { CreateNewsletterEmailErrorCode } from '../generated/graphql'
import { env } from '../env'
-import addressparser from 'nodemailer/lib/addressparser'
+import addressparser = require('nodemailer/lib/addressparser');
const parsedAddress = (emailAddress: string): string | undefined => {
const res = addressparser(emailAddress, { flatten: true })
From b8b471d3695e9f5785eda31e2a8a3aa44adb789a Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 08:17:00 -0700
Subject: [PATCH 043/298] Move @types into dev
---
packages/api/package.json | 40 +++++++++++++++++++--------------------
1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/packages/api/package.json b/packages/api/package.json
index 8fa9a30fd..913cf7f88 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -36,26 +36,6 @@
"@sentry/integrations": "^6.19.1",
"@sentry/node": "^5.26.0",
"@sentry/tracing": "^5.26.0",
- "@types/analytics-node": "^3.1.7",
- "@types/bcryptjs": "^2.4.2",
- "@types/chai": "^4.2.18",
- "@types/chai-string": "^1.4.2",
- "@types/cookie": "^0.4.0",
- "@types/cookie-parser": "^1.4.2",
- "@types/dompurify": "^2.0.4",
- "@types/express": "^4.17.7",
- "@types/highlightjs": "^9.12.2",
- "@types/intercom-client": "^2.11.8",
- "@types/jsdom": "^16.2.3",
- "@types/jsonwebtoken": "^8.5.0",
- "@types/luxon": "^1.25.0",
- "@types/mocha": "^8.2.2",
- "@types/oauth": "^0.9.1",
- "@types/sanitize-html": "^1.27.1",
- "@types/supertest": "^2.0.11",
- "@types/urlsafe-base64": "^1.0.28",
- "@types/uuid": "^8.3.0",
- "@types/voca": "^1.4.0",
"analytics-node": "^6.0.0",
"apollo-datasource": "^3.3.1",
"apollo-server-express": "^3.6.3",
@@ -105,11 +85,29 @@
"devDependencies": {
"@babel/register": "^7.14.5",
"@istanbuljs/nyc-config-typescript": "^1.0.2",
- "@types/analytics-node": "^3.1.7",
"@types/highlightjs": "^9.12.2",
"@types/nanoid": "^3.0.0",
"@types/nodemailer": "^6.4.4",
"@types/private-ip": "^1.0.0",
+ "@types/analytics-node": "^3.1.7",
+ "@types/bcryptjs": "^2.4.2",
+ "@types/chai": "^4.2.18",
+ "@types/chai-string": "^1.4.2",
+ "@types/cookie": "^0.4.0",
+ "@types/cookie-parser": "^1.4.2",
+ "@types/dompurify": "^2.0.4",
+ "@types/express": "^4.17.7",
+ "@types/intercom-client": "^2.11.8",
+ "@types/jsdom": "^16.2.3",
+ "@types/jsonwebtoken": "^8.5.0",
+ "@types/luxon": "^1.25.0",
+ "@types/mocha": "^8.2.2",
+ "@types/oauth": "^0.9.1",
+ "@types/sanitize-html": "^1.27.1",
+ "@types/supertest": "^2.0.11",
+ "@types/urlsafe-base64": "^1.0.28",
+ "@types/uuid": "^8.3.0",
+ "@types/voca": "^1.4.0",
"chai": "^4.3.4",
"chai-string": "^1.5.0",
"circular-dependency-plugin": "^5.2.0",
From 9845a49040a40596a8bcd2774282c43383d931d6 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 08:17:46 -0700
Subject: [PATCH 044/298] Remove semicolon
---
packages/api/src/services/newsletters.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/api/src/services/newsletters.ts b/packages/api/src/services/newsletters.ts
index 16b8c8810..99937bc4a 100644
--- a/packages/api/src/services/newsletters.ts
+++ b/packages/api/src/services/newsletters.ts
@@ -4,7 +4,7 @@ import { nanoid } from 'nanoid'
import { User } from '../entity/user'
import { CreateNewsletterEmailErrorCode } from '../generated/graphql'
import { env } from '../env'
-import addressparser = require('nodemailer/lib/addressparser');
+import addressparser = require('nodemailer/lib/addressparser')
const parsedAddress = (emailAddress: string): string | undefined => {
const res = addressparser(emailAddress, { flatten: true })
From bc7767bec176ebe784a3a2b332bff3bc26726d04 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 08:42:32 -0700
Subject: [PATCH 045/298] Build docker images in GitHub
---
.github/workflows/run-tests.yaml | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml
index baba3253f..432c04b8c 100644
--- a/.github/workflows/run-tests.yaml
+++ b/.github/workflows/run-tests.yaml
@@ -69,7 +69,6 @@ jobs:
yarn build
yarn lint
yarn test
-
env:
PG_HOST: localhost
PG_PORT: ${{ job.services.postgres.ports[5432] }}
@@ -78,3 +77,12 @@ jobs:
PG_DB: omnivore_test
PG_POOL_MAX: 10
ELASTIC_URL: http://localhost:${{ job.services.elastic.ports[9200] }}/
+ build-docker-images:
+ name: Build docker images
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+ - name: Build the API docker image
+ run: 'docker build -F packages/api .'
\ No newline at end of file
From b9300d3f3047a21f2806c821907f1c2a19405f57 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 08:44:00 -0700
Subject: [PATCH 046/298] Avoid shorthand flag syntax in build scripts
---
.github/workflows/run-tests.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml
index 432c04b8c..f85a8153a 100644
--- a/.github/workflows/run-tests.yaml
+++ b/.github/workflows/run-tests.yaml
@@ -85,4 +85,4 @@ jobs:
with:
fetch-depth: 0
- name: Build the API docker image
- run: 'docker build -F packages/api .'
\ No newline at end of file
+ run: 'docker build --file packages/api .'
\ No newline at end of file
From 1489ca52310a2496a323cc88019afa40286c6c3e Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 08:45:16 -0700
Subject: [PATCH 047/298] Specify file
---
.github/workflows/run-tests.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/run-tests.yaml b/.github/workflows/run-tests.yaml
index f85a8153a..16aab9ebb 100644
--- a/.github/workflows/run-tests.yaml
+++ b/.github/workflows/run-tests.yaml
@@ -85,4 +85,4 @@ jobs:
with:
fetch-depth: 0
- name: Build the API docker image
- run: 'docker build --file packages/api .'
\ No newline at end of file
+ run: 'docker build --file packages/api/Dockerfile .'
\ No newline at end of file
From b15a7b0bd5b63075bd8d50513b355d4dbb0ed161 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 09:15:56 -0700
Subject: [PATCH 048/298] Only install dev deps on the prod image
---
packages/api/Dockerfile | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile
index 075958b7a..be7808b9b 100644
--- a/packages/api/Dockerfile
+++ b/packages/api/Dockerfile
@@ -2,7 +2,6 @@ FROM node:14.18-alpine as builder
WORKDIR /app
-ENV NODE_ENV development
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
COPY package.json .
@@ -14,16 +13,16 @@ COPY .eslintrc .
COPY /packages/readabilityjs/package.json ./packages/readabilityjs/package.json
COPY /packages/api/package.json ./packages/api/package.json
-RUN yarn install --pure-lockfile --development
+RUN yarn install --pure-lockfile
ADD /packages/readabilityjs ./packages/readabilityjs
ADD /packages/api ./packages/api
RUN yarn
+RUN yarn clean
RUN yarn workspace @omnivore/api build
-
FROM node:14.18-alpine as runner
WORKDIR /app
@@ -35,10 +34,9 @@ ENV PORT=8080
COPY --from=builder /app/packages/api/dist /app/packages/api/dist
COPY --from=builder /app/packages/readabilityjs/ /app/packages/readabilityjs/
COPY --from=builder /app/packages/api/package.json /app/packages/api/package.json
-COPY --from=builder /app/packages/api/node_modules /app/packages/api/node_modules
-COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/package.json /app/package.json
COPY --from=builder /app/packages/api/index_settings.json /app/packages/api/index_settings.json
+RUN yarn install --production
EXPOSE 8080
From bd6bed746e6575bdf07c5e32ef55e144b8418e46 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 09:19:25 -0700
Subject: [PATCH 049/298] Remove clean command
---
packages/api/Dockerfile | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile
index be7808b9b..5bc4b9e2b 100644
--- a/packages/api/Dockerfile
+++ b/packages/api/Dockerfile
@@ -19,7 +19,6 @@ ADD /packages/readabilityjs ./packages/readabilityjs
ADD /packages/api ./packages/api
RUN yarn
-RUN yarn clean
RUN yarn workspace @omnivore/api build
From a99ab365b81c8634fbef3ae4be1978f07246a77e Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 09:22:18 -0700
Subject: [PATCH 050/298] Remove unused import
---
packages/web/lib/networking/queries/useGetLabelsQuery.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/web/lib/networking/queries/useGetLabelsQuery.tsx b/packages/web/lib/networking/queries/useGetLabelsQuery.tsx
index 6cab8ef62..c625b592e 100644
--- a/packages/web/lib/networking/queries/useGetLabelsQuery.tsx
+++ b/packages/web/lib/networking/queries/useGetLabelsQuery.tsx
@@ -1,7 +1,7 @@
import { gql } from 'graphql-request'
import useSWR from 'swr'
import { LabelColor } from '../../../utils/settings-page/labels/types';
-import { Label, labelFragment } from '../fragments/labelFragment'
+import { labelFragment } from '../fragments/labelFragment'
import { publicGqlFetcher } from '../networkHelpers'
type LabelsQueryResponse = {
From 946734d76c7372b146c48169496cab17b5d391ea Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 09:54:04 -0700
Subject: [PATCH 051/298] Revert docker changes
These were creating fatter images than we want because of the
lerna dependencies.
---
packages/api/Dockerfile | 7 +++++--
packages/api/package.json | 42 ++++++++++++++++++++-------------------
2 files changed, 27 insertions(+), 22 deletions(-)
diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile
index 5bc4b9e2b..2727fd217 100644
--- a/packages/api/Dockerfile
+++ b/packages/api/Dockerfile
@@ -2,6 +2,7 @@ FROM node:14.18-alpine as builder
WORKDIR /app
+ENV NODE_ENV production
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
COPY package.json .
@@ -13,7 +14,7 @@ COPY .eslintrc .
COPY /packages/readabilityjs/package.json ./packages/readabilityjs/package.json
COPY /packages/api/package.json ./packages/api/package.json
-RUN yarn install --pure-lockfile
+RUN yarn install --pure-lockfile --production
ADD /packages/readabilityjs ./packages/readabilityjs
ADD /packages/api ./packages/api
@@ -22,6 +23,7 @@ RUN yarn
RUN yarn workspace @omnivore/api build
+
FROM node:14.18-alpine as runner
WORKDIR /app
@@ -33,9 +35,10 @@ ENV PORT=8080
COPY --from=builder /app/packages/api/dist /app/packages/api/dist
COPY --from=builder /app/packages/readabilityjs/ /app/packages/readabilityjs/
COPY --from=builder /app/packages/api/package.json /app/packages/api/package.json
+COPY --from=builder /app/packages/api/node_modules /app/packages/api/node_modules
+COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/package.json /app/package.json
COPY --from=builder /app/packages/api/index_settings.json /app/packages/api/index_settings.json
-RUN yarn install --production
EXPOSE 8080
diff --git a/packages/api/package.json b/packages/api/package.json
index 913cf7f88..1871f9c8c 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -36,6 +36,27 @@
"@sentry/integrations": "^6.19.1",
"@sentry/node": "^5.26.0",
"@sentry/tracing": "^5.26.0",
+ "@types/analytics-node": "^3.1.7",
+ "@types/bcryptjs": "^2.4.2",
+ "@types/chai": "^4.2.18",
+ "@types/chai-string": "^1.4.2",
+ "@types/cookie": "^0.4.0",
+ "@types/cookie-parser": "^1.4.2",
+ "@types/dompurify": "^2.0.4",
+ "@types/express": "^4.17.7",
+ "@types/highlightjs": "^9.12.2",
+ "@types/intercom-client": "^2.11.8",
+ "@types/jsdom": "^16.2.3",
+ "@types/jsonwebtoken": "^8.5.0",
+ "@types/luxon": "^1.25.0",
+ "@types/mocha": "^8.2.2",
+ "@types/nodemailer": "^6.4.4",
+ "@types/oauth": "^0.9.1",
+ "@types/sanitize-html": "^1.27.1",
+ "@types/supertest": "^2.0.11",
+ "@types/urlsafe-base64": "^1.0.28",
+ "@types/uuid": "^8.3.0",
+ "@types/voca": "^1.4.0",
"analytics-node": "^6.0.0",
"apollo-datasource": "^3.3.1",
"apollo-server-express": "^3.6.3",
@@ -85,29 +106,10 @@
"devDependencies": {
"@babel/register": "^7.14.5",
"@istanbuljs/nyc-config-typescript": "^1.0.2",
+ "@types/analytics-node": "^3.1.7",
"@types/highlightjs": "^9.12.2",
"@types/nanoid": "^3.0.0",
- "@types/nodemailer": "^6.4.4",
"@types/private-ip": "^1.0.0",
- "@types/analytics-node": "^3.1.7",
- "@types/bcryptjs": "^2.4.2",
- "@types/chai": "^4.2.18",
- "@types/chai-string": "^1.4.2",
- "@types/cookie": "^0.4.0",
- "@types/cookie-parser": "^1.4.2",
- "@types/dompurify": "^2.0.4",
- "@types/express": "^4.17.7",
- "@types/intercom-client": "^2.11.8",
- "@types/jsdom": "^16.2.3",
- "@types/jsonwebtoken": "^8.5.0",
- "@types/luxon": "^1.25.0",
- "@types/mocha": "^8.2.2",
- "@types/oauth": "^0.9.1",
- "@types/sanitize-html": "^1.27.1",
- "@types/supertest": "^2.0.11",
- "@types/urlsafe-base64": "^1.0.28",
- "@types/uuid": "^8.3.0",
- "@types/voca": "^1.4.0",
"chai": "^4.3.4",
"chai-string": "^1.5.0",
"circular-dependency-plugin": "^5.2.0",
From 88e68ff4a3e7fe4de3473368bc2087c9a45335a0 Mon Sep 17 00:00:00 2001
From: Satindar Dhillon
Date: Mon, 4 Apr 2022 10:07:16 -0700
Subject: [PATCH 052/298] use selectedLinkItem to track active state of grid
items
---
.../App/Views/Home/Components/FeedCardNavigationLink.swift | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift
index 63919c49c..14916f3db 100644
--- a/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift
+++ b/apple/OmnivoreKit/Sources/App/Views/Home/Components/FeedCardNavigationLink.swift
@@ -36,7 +36,6 @@ struct GridCardNavigationLink: View {
@EnvironmentObject var dataService: DataService
@State private var scale = 1.0
- @State private var isActive = false
let item: FeedItem
let searchQuery: String
@@ -51,7 +50,8 @@ struct GridCardNavigationLink: View {
ZStack {
NavigationLink(
destination: LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item, homeFeedViewModel: viewModel)),
- isActive: $isActive
+ tag: item,
+ selection: $selectedLinkItem
) {
EmptyView()
}
@@ -60,7 +60,7 @@ struct GridCardNavigationLink: View {
scale = 0.95
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(150)) {
scale = 1.0
- isActive = true
+ selectedLinkItem = item
}
}
})
From 46c5b8c82a4a2d3fdf5fccd4731d176a97b1d4bd Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 10:42:04 -0700
Subject: [PATCH 053/298] Another attempt at slimming docker file
---
packages/api/Dockerfile | 9 +++++----
packages/api/package.json | 42 +++++++++++++++++++--------------------
2 files changed, 25 insertions(+), 26 deletions(-)
diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile
index 2727fd217..377397b16 100644
--- a/packages/api/Dockerfile
+++ b/packages/api/Dockerfile
@@ -2,7 +2,6 @@ FROM node:14.18-alpine as builder
WORKDIR /app
-ENV NODE_ENV production
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
COPY package.json .
@@ -14,7 +13,7 @@ COPY .eslintrc .
COPY /packages/readabilityjs/package.json ./packages/readabilityjs/package.json
COPY /packages/api/package.json ./packages/api/package.json
-RUN yarn install --pure-lockfile --production
+RUN yarn install --pure-lockfile
ADD /packages/readabilityjs ./packages/readabilityjs
ADD /packages/api ./packages/api
@@ -22,7 +21,10 @@ ADD /packages/api ./packages/api
RUN yarn
RUN yarn workspace @omnivore/api build
-
+# After building, fetch the production dependencies
+RUN rm -rf /app/packages/api/node_modules
+RUN rm -rf /app/node_modules
+RUN yarn install --pure-lockfile --production
FROM node:14.18-alpine as runner
@@ -39,7 +41,6 @@ COPY --from=builder /app/packages/api/node_modules /app/packages/api/node_module
COPY --from=builder /app/node_modules /app/node_modules
COPY --from=builder /app/package.json /app/package.json
COPY --from=builder /app/packages/api/index_settings.json /app/packages/api/index_settings.json
-
EXPOSE 8080
CMD ["yarn", "workspace", "@omnivore/api", "start"]
diff --git a/packages/api/package.json b/packages/api/package.json
index 1871f9c8c..8e4a08657 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -36,27 +36,6 @@
"@sentry/integrations": "^6.19.1",
"@sentry/node": "^5.26.0",
"@sentry/tracing": "^5.26.0",
- "@types/analytics-node": "^3.1.7",
- "@types/bcryptjs": "^2.4.2",
- "@types/chai": "^4.2.18",
- "@types/chai-string": "^1.4.2",
- "@types/cookie": "^0.4.0",
- "@types/cookie-parser": "^1.4.2",
- "@types/dompurify": "^2.0.4",
- "@types/express": "^4.17.7",
- "@types/highlightjs": "^9.12.2",
- "@types/intercom-client": "^2.11.8",
- "@types/jsdom": "^16.2.3",
- "@types/jsonwebtoken": "^8.5.0",
- "@types/luxon": "^1.25.0",
- "@types/mocha": "^8.2.2",
- "@types/nodemailer": "^6.4.4",
- "@types/oauth": "^0.9.1",
- "@types/sanitize-html": "^1.27.1",
- "@types/supertest": "^2.0.11",
- "@types/urlsafe-base64": "^1.0.28",
- "@types/uuid": "^8.3.0",
- "@types/voca": "^1.4.0",
"analytics-node": "^6.0.0",
"apollo-datasource": "^3.3.1",
"apollo-server-express": "^3.6.3",
@@ -106,10 +85,29 @@
"devDependencies": {
"@babel/register": "^7.14.5",
"@istanbuljs/nyc-config-typescript": "^1.0.2",
- "@types/analytics-node": "^3.1.7",
"@types/highlightjs": "^9.12.2",
"@types/nanoid": "^3.0.0",
"@types/private-ip": "^1.0.0",
+ "@types/analytics-node": "^3.1.7",
+ "@types/bcryptjs": "^2.4.2",
+ "@types/chai": "^4.2.18",
+ "@types/chai-string": "^1.4.2",
+ "@types/cookie": "^0.4.0",
+ "@types/cookie-parser": "^1.4.2",
+ "@types/dompurify": "^2.0.4",
+ "@types/express": "^4.17.7",
+ "@types/intercom-client": "^2.11.8",
+ "@types/jsdom": "^16.2.3",
+ "@types/jsonwebtoken": "^8.5.0",
+ "@types/luxon": "^1.25.0",
+ "@types/mocha": "^8.2.2",
+ "@types/nodemailer": "^6.4.4",
+ "@types/oauth": "^0.9.1",
+ "@types/sanitize-html": "^1.27.1",
+ "@types/supertest": "^2.0.11",
+ "@types/urlsafe-base64": "^1.0.28",
+ "@types/uuid": "^8.3.0",
+ "@types/voca": "^1.4.0",
"chai": "^4.3.4",
"chai-string": "^1.5.0",
"circular-dependency-plugin": "^5.2.0",
From 3b4254a71199ba2952ff4448e10e2a00314f2bde Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 4 Apr 2022 17:55:59 +0000
Subject: [PATCH 054/298] Bump luxon from 1.28.0 to 2.3.1
Bumps [luxon](https://github.com/moment/luxon) from 1.28.0 to 2.3.1.
- [Release notes](https://github.com/moment/luxon/releases)
- [Changelog](https://github.com/moment/luxon/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moment/luxon/compare/1.28.0...2.3.1)
---
updated-dependencies:
- dependency-name: luxon
dependency-type: direct:production
update-type: version-update:semver-major
...
Signed-off-by: dependabot[bot]
---
packages/api/package.json | 2 +-
packages/puppeteer-parse/package.json | 2 +-
yarn.lock | 8 ++++----
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/packages/api/package.json b/packages/api/package.json
index 8e4a08657..c6509f1f2 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -62,7 +62,7 @@
"jwks-rsa": "^2.0.3",
"knex": "0.21.12",
"knex-stringcase": "^1.4.2",
- "luxon": "^1.25.0",
+ "luxon": "^2.3.1",
"nanoid": "^3.1.25",
"nodemailer": "^6.7.3",
"normalize-url": "^6.1.0",
diff --git a/packages/puppeteer-parse/package.json b/packages/puppeteer-parse/package.json
index 83f3e09e0..9e1aebe7e 100644
--- a/packages/puppeteer-parse/package.json
+++ b/packages/puppeteer-parse/package.json
@@ -12,7 +12,7 @@
"dotenv": "^8.2.0",
"jsdom": "^19.0.0",
"jsonwebtoken": "^8.5.1",
- "luxon": "^1.26.0",
+ "luxon": "^2.3.1",
"puppeteer-core": "^7.1.0",
"winston": "^3.3.3"
},
diff --git a/yarn.lock b/yarn.lock
index 2e0ae8cf2..00b0022b9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14188,10 +14188,10 @@ lru_map@^0.3.3:
resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=
-luxon@^1.25.0, luxon@^1.26.0:
- version "1.28.0"
- resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.28.0.tgz#e7f96daad3938c06a62de0fb027115d251251fbf"
- integrity sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==
+luxon@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/luxon/-/luxon-2.3.1.tgz#f276b1b53fd9a740a60e666a541a7f6dbed4155a"
+ integrity sha512-I8vnjOmhXsMSlNMZlMkSOvgrxKJl0uOsEzdGgGNZuZPaS9KlefpE9KV95QFftlJSC+1UyCC9/I69R02cz/zcCA==
lz-string@^1.4.4:
version "1.4.4"
From b79c71ff6541882ff9badde781003c994d6209e4 Mon Sep 17 00:00:00 2001
From: Satindar Dhillon
Date: Mon, 4 Apr 2022 12:05:06 -0700
Subject: [PATCH 055/298] update reading progress only when user has navigated
back to the grid view
---
.../Sources/App/Views/Home/HomeFeedViewIOS.swift | 5 ++++-
.../App/Views/Home/HomeFeedViewModel.swift | 15 ++++++++++++++-
.../Sources/App/Views/LinkItemDetailView.swift | 2 +-
.../App/Views/WebReader/WebReaderContainer.swift | 4 ++--
apple/OmnivoreKit/Sources/Models/FeedItem.swift | 1 -
5 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift
index 4c29dd93b..a6c17d60f 100644
--- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift
+++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewIOS.swift
@@ -100,6 +100,9 @@ import Views
viewModel.loadItems(dataService: dataService, searchQuery: searchQuery, isRefresh: true)
}
}
+ .onChange(of: selectedLinkItem) { _ in
+ viewModel.commitProgressUpdates()
+ }
}
}
@@ -326,7 +329,7 @@ import Views
var body: some View {
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 325), spacing: 24)], spacing: 24) {
- ForEach(viewModel.items, id: \.renderID) { item in
+ ForEach(viewModel.items) { item in
let link = GridCardNavigationLink(
item: item,
searchQuery: searchQuery,
diff --git a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift
index 6a917f435..84408f83e 100644
--- a/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift
+++ b/apple/OmnivoreKit/Sources/App/Views/Home/HomeFeedViewModel.swift
@@ -8,6 +8,9 @@ import Views
final class HomeFeedViewModel: ObservableObject {
var currentDetailViewModel: LinkItemDetailViewModel?
+ /// Track progress updates to be committed when user navigates back to grid view
+ var uncommittedReadingProgressUpdates = [String: Double]()
+
@Published var items = [FeedItem]()
@Published var isLoading = false
@Published var showPushNotificationPrimer = false
@@ -163,7 +166,17 @@ final class HomeFeedViewModel: ObservableObject {
.store(in: &subscriptions)
}
- func updateProgress(itemID: String, progress: Double) {
+ /// Update `FeedItem`s with the cached reading progress values so it can animate when the
+ /// user navigates back to the grid view (and also avoid mutations of the grid items
+ /// that can cause the `NavigationView` to pop.
+ func commitProgressUpdates() {
+ for (key, value) in uncommittedReadingProgressUpdates {
+ updateProgress(itemID: key, progress: value)
+ }
+ uncommittedReadingProgressUpdates = [:]
+ }
+
+ private func updateProgress(itemID: String, progress: Double) {
guard sendProgressUpdates, let item = items.first(where: { $0.id == itemID }) else { return }
if let index = items.firstIndex(of: item) {
items[index].readingProgress = progress
diff --git a/apple/OmnivoreKit/Sources/App/Views/LinkItemDetailView.swift b/apple/OmnivoreKit/Sources/App/Views/LinkItemDetailView.swift
index 06f94ea3c..2d83208f3 100644
--- a/apple/OmnivoreKit/Sources/App/Views/LinkItemDetailView.swift
+++ b/apple/OmnivoreKit/Sources/App/Views/LinkItemDetailView.swift
@@ -92,7 +92,7 @@ final class LinkItemDetailViewModel: ObservableObject {
case let .shareHighlight(highlightID):
print("show share modal for highlight with id: \(highlightID)")
case let .updateReadingProgess(progress: progress):
- self?.homeFeedViewModel.updateProgress(itemID: self?.item.id ?? "", progress: Double(progress))
+ self?.homeFeedViewModel.uncommittedReadingProgressUpdates[self?.item.id ?? ""] = Double(progress)
}
}
.store(in: &newWebAppWrapperViewModel.subscriptions)
diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift
index 7cc5bf938..51bc8fca4 100644
--- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift
+++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContainer.swift
@@ -36,7 +36,7 @@ struct WebReaderContainerView: View {
let messageBody = message.body as? [String: Double]
if let messageBody = messageBody, let progress = messageBody["progress"] {
- homeFeedViewModel.updateProgress(itemID: item.id, progress: Double(progress))
+ homeFeedViewModel.uncommittedReadingProgressUpdates[item.id] = Double(progress)
}
}
@@ -56,7 +56,7 @@ struct WebReaderContainerView: View {
if message.name == WebViewAction.readingProgressUpdate.rawValue {
guard let messageBody = message.body as? [String: Double] else { return }
guard let progress = messageBody["progress"] else { return }
- homeFeedViewModel.updateProgress(itemID: item.id, progress: Double(progress))
+ homeFeedViewModel.uncommittedReadingProgressUpdates[item.id] = Double(progress)
}
}
diff --git a/apple/OmnivoreKit/Sources/Models/FeedItem.swift b/apple/OmnivoreKit/Sources/Models/FeedItem.swift
index c8f5a418e..30960fbb7 100644
--- a/apple/OmnivoreKit/Sources/Models/FeedItem.swift
+++ b/apple/OmnivoreKit/Sources/Models/FeedItem.swift
@@ -12,7 +12,6 @@ public struct HomeFeedData {
public struct FeedItem: Identifiable, Hashable, Decodable {
public let id: String
- public let renderID = UUID()
public let title: String
public let createdAt: Date
public let savedAt: Date
From 0a075d21a4e01f87b758be56178fc8e2ccb9ff41 Mon Sep 17 00:00:00 2001
From: Jackson Harper
Date: Mon, 4 Apr 2022 12:10:56 -0700
Subject: [PATCH 056/298] Update the newsletter signup help GIF
---
.../static/help/newsletter-email-signup.gif | Bin 1049689 -> 527790 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/packages/web/public/static/help/newsletter-email-signup.gif b/packages/web/public/static/help/newsletter-email-signup.gif
index 24da2371b5e6eae6abc8952c28029fd8ee22d723..b839322d26e0f5b6cc0de68b9927308602dcfc4b 100644
GIT binary patch
literal 527790
zcmWhzcTf{f6HO;TfKa5D(7S{xO$bFgh=58H10qFQKvcR3y^Hj2Kza>LP(VWw=^)aJ
z6j6#)0e^sCKEFS1cIIYh?q+UxZ{OReZ>XoN;)nusfN&H5KZVxphLxp`miZ02t7tF~
z008ixL7+7Mtkk~+_`h4sKTDxdPESu!0z&diswXEW|8{^NAP@lj@4x?!j*gCxk6{oP
z55K^VA3vx;;Ip$cCw}M
zl2_%f0HMZEj-B1z!^1;;C_4v?Rs+g*3(Dc||CAa=yT8Bx=g%JjK~a7noCONM4dqsa
zvfa=#{CoMgtE($7FOQBI+0oJY>(?)!Du9WOO_qvE{rdII%}q2~?k|P%-}udyl@$fZ
z6||h