diff --git a/packages/api/src/apollo.ts b/packages/api/src/apollo.ts index 67eb0b65a..9c0ce1271 100644 --- a/packages/api/src/apollo.ts +++ b/packages/api/src/apollo.ts @@ -40,7 +40,7 @@ import { countDailyServiceUsage, createServiceUsage, } from './services/service_usage' -import { findSubscriptionsByNames } from './services/subscriptions' +import { batchGetSubscriptionsByNames } from './services/subscriptions' import { batchGetUploadFilesByIds } from './services/upload_file' import { tracer } from './tracing' import { getClaimsByToken, setAuthInCookie } from './utils/auth' @@ -122,7 +122,7 @@ const contextFunc: ContextFunction = async ({ throw new Error('No user id found in claims') } - return findSubscriptionsByNames(claims?.uid || '', names as string[]) + return batchGetSubscriptionsByNames(claims.uid, names as string[]) }), }, } diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index ee60e84b9..63d4e2b14 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -1303,6 +1303,7 @@ export type HomeItem = { previewContent?: Maybe; saveCount?: Maybe; seen_at?: Maybe; + slug?: Maybe; source?: Maybe; thumbnail?: Maybe; title: Scalars['String']; @@ -6043,6 +6044,7 @@ export type HomeItemResolvers, ParentType, ContextType>; saveCount?: Resolver, ParentType, ContextType>; seen_at?: Resolver, ParentType, ContextType>; + slug?: Resolver, ParentType, ContextType>; source?: Resolver, ParentType, ContextType>; thumbnail?: Resolver, ParentType, ContextType>; title?: Resolver; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index 220808a8a..c60a0689c 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -1172,6 +1172,7 @@ type HomeItem { previewContent: String saveCount: Int seen_at: Date + slug: String source: HomeItemSource thumbnail: String title: String! diff --git a/packages/api/src/jobs/update_home.ts b/packages/api/src/jobs/update_home.ts index d60d4a3e4..f2d6d5e59 100644 --- a/packages/api/src/jobs/update_home.ts +++ b/packages/api/src/jobs/update_home.ts @@ -311,7 +311,8 @@ const mixHomeItems = (rankedHomeItems: Array): Array
=> { const authorCount = batch.filter((i) => i.author === item.author).length const siteCount = batch.filter((i) => i.siteName === item.siteName).length const subscriptionCount = batch.filter( - (i) => i.subscription?.name === item.subscription?.name + (i) => + item.subscription && i.subscription?.name === item.subscription.name ).length return ( diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index 6f4e84ee9..d29f6229e 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -639,12 +639,17 @@ export const functionResolvers = { _: unknown, ctx: WithDataSourcesContext ) { - const libraryItemIds = section.items + const items = section.items + console.log('items', items) + + const libraryItemIds = items .filter((item) => item.type === 'library_item') .map((item) => item.id) + console.log('libraryItemIds', libraryItemIds) const libraryItems = ( await ctx.dataLoaders.libraryItems.loadMany(libraryItemIds) ).filter((libraryItem) => !isError(libraryItem)) as Array + console.log('libraryItems', libraryItems) const publicItemIds = section.items .filter((item) => item.type === 'public_item') @@ -653,10 +658,15 @@ export const functionResolvers = { await ctx.dataLoaders.publicItems.loadMany(publicItemIds) ).filter((publicItem) => !isError(publicItem)) as Array - return libraryItems - .map( - (libraryItem) => - ({ + return items + .map((item) => { + console.log('item', item) + const libraryItem = libraryItems.find( + (libraryItem) => item.id === libraryItem.id + ) + console.log('libraryItem', libraryItem) + if (libraryItem) { + return { id: libraryItem.id, title: libraryItem.title, author: libraryItem.author, @@ -667,36 +677,44 @@ export const functionResolvers = { canArchive: !libraryItem.archivedAt, canDelete: !libraryItem.deletedAt, canSave: false, + canComment: false, + canShare: true, dir: libraryItem.directionality, previewContent: libraryItem.description, subscription: libraryItem.subscription, siteName: libraryItem.siteName, siteIcon: libraryItem.siteIcon, - } as HomeItem) - ) - .concat( - publicItems.map( - (publicItem) => - ({ - id: publicItem.id, - title: publicItem.title, - author: publicItem.author, - dir: publicItem.dir, - previewContent: publicItem.previewContent, - thumbnail: publicItem.thumbnail, - wordCount: publicItem.wordCount, - date: publicItem.createdAt, - url: publicItem.url, - canArchive: false, - canDelete: false, - canSave: true, - broadcastCount: publicItem.stats.broadcastCount, - likeCount: publicItem.stats.likeCount, - saveCount: publicItem.stats.saveCount, - source: publicItem.source, - } as HomeItem) + slug: libraryItem.slug, + } + } + + const publicItem = publicItems.find( + (publicItem) => item.id === publicItem.id ) - ) + if (publicItem) { + return { + id: publicItem.id, + title: publicItem.title, + author: publicItem.author, + dir: publicItem.dir, + previewContent: publicItem.previewContent, + thumbnail: publicItem.thumbnail, + wordCount: publicItem.wordCount, + date: publicItem.createdAt, + url: publicItem.url, + canArchive: false, + canDelete: false, + canSave: true, + canComment: true, + canShare: true, + broadcastCount: publicItem.stats.broadcastCount, + likeCount: publicItem.stats.likeCount, + saveCount: publicItem.stats.saveCount, + source: publicItem.source, + } + } + }) + .filter((item) => !!item) }, }, HomeItem: { @@ -723,6 +741,13 @@ export const functionResolvers = { const subscription = await ctx.dataLoaders.subscriptions.load( item.subscription ) + if (!subscription) { + return { + name: item.siteName, + icon: item.siteIcon, + type: HomeItemSourceType.Library, + } + } return { id: subscription.id, diff --git a/packages/api/src/resolvers/types.ts b/packages/api/src/resolvers/types.ts index 21b049bae..7aaf46322 100644 --- a/packages/api/src/resolvers/types.ts +++ b/packages/api/src/resolvers/types.ts @@ -55,9 +55,9 @@ export interface RequestContext { highlights: DataLoader recommendations: DataLoader uploadFiles: DataLoader - libraryItems: DataLoader - publicItems: DataLoader - subscriptions: DataLoader + libraryItems: DataLoader + publicItems: DataLoader + subscriptions: DataLoader } } diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 963adf81f..c478014e8 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -3126,6 +3126,7 @@ const schema = gql` likeCount: Int broadcastCount: Int date: Date! + slug: String author: String dir: String seen_at: Date diff --git a/packages/api/src/services/home.ts b/packages/api/src/services/home.ts index c70a98003..b78772377 100644 --- a/packages/api/src/services/home.ts +++ b/packages/api/src/services/home.ts @@ -1,77 +1,18 @@ import { PublicItem } from '../entity/public_item' -import { HomeItem } from '../generated/graphql' import { authTrx } from '../repository' -import { findLibraryItemsByIds } from './library_item' export const batchGetPublicItems = async ( ids: readonly string[] -): Promise> => { - return authTrx(async (tx) => - tx - .getRepository(PublicItem) - .createQueryBuilder('public_item') - .where('public_item.id IN (:...ids)', { ids }) - .getMany() - ) -} - -export const batchGetHomeItems = async ( - ids: readonly string[] -): Promise> => { - const libraryItems = await findLibraryItemsByIds(ids as string[]) - +): Promise> => { const publicItems = await authTrx(async (tx) => tx .getRepository(PublicItem) .createQueryBuilder('public_item') - .innerJoin( - 'public_item_stats', - 'stats', - 'stats.public_item_id = public_item.id' - ) - .innerJoin( - 'public_item_source', - 'source', - 'source.id = public_item.source_id' - ) .where('public_item.id IN (:...ids)', { ids }) .getMany() ) - return ids - .map((id) => { - const libraryItem = libraryItems.find((li) => li.id === id) - if (libraryItem) { - return { - ...libraryItem, - date: libraryItem.savedAt, - url: libraryItem.originalUrl, - canArchive: !libraryItem.archivedAt, - canDelete: !libraryItem.deletedAt, - canSave: false, - dir: libraryItem.directionality, - subscription: null, - previewContent: libraryItem.description, - } as HomeItem - } else { - const publicItem = publicItems.find((pi) => pi.id === id) - return publicItem - ? ({ - ...publicItem, - date: publicItem.createdAt, - url: publicItem.url, - canArchive: false, - canDelete: false, - canSave: true, - broadcastCount: publicItem.stats.broadcastCount, - likeCount: publicItem.stats.likeCount, - saveCount: publicItem.stats.saveCount, - subscription: publicItem.source, - } as HomeItem) - : undefined - } - }) - .filter((item) => item !== undefined) as Array + return ids.map((id) => publicItems.find((pi) => pi.id === id)) } export const findUnseenPublicItems = async ( diff --git a/packages/api/src/services/library_item.ts b/packages/api/src/services/library_item.ts index b90aa0e80..80848fc75 100644 --- a/packages/api/src/services/library_item.ts +++ b/packages/api/src/services/library_item.ts @@ -141,7 +141,27 @@ interface Select { const readingProgressDataSource = new ReadingProgressDataSource() export const batchGetLibraryItems = async (ids: readonly string[]) => { - return findLibraryItemsByIds(ids as string[]) + const items = await findLibraryItemsByIds(ids as string[], undefined, { + select: [ + 'id', + 'title', + 'author', + 'thumbnail', + 'wordCount', + 'savedAt', + 'originalUrl', + 'directionality', + 'description', + 'subscription', + 'siteName', + 'siteIcon', + 'archivedAt', + 'deletedAt', + 'slug', + ], + }) + + return ids.map((id) => items.find((item) => item.id === id) || undefined) } export const getItemUrl = (id: string) => `${env.client.url}/me/${id}` diff --git a/packages/api/src/services/subscriptions.ts b/packages/api/src/services/subscriptions.ts index 72b0fc9d2..52f4bef50 100644 --- a/packages/api/src/services/subscriptions.ts +++ b/packages/api/src/services/subscriptions.ts @@ -21,6 +21,17 @@ interface SaveSubscriptionInput { export const UNSUBSCRIBE_EMAIL_TEXT = 'This message was automatically generated by Omnivore.' +export const batchGetSubscriptionsByNames = async ( + userId: string, + names: string[] +) => { + const subscriptions = await findSubscriptionsByNames(userId, names) + + return names.map((name) => + subscriptions.find((s) => s?.name === name || s?.url === name) + ) +} + export const parseUnsubscribeMailTo = (unsubscribeMailTo: string) => { const parsed = new URL(`mailto://${unsubscribeMailTo}`) const subject = parsed.searchParams.get('subject') || 'Unsubscribe'