Merge pull request #4000 from omnivore-app/fix/home
fix: home items order is not accurate
This commit is contained in:
@ -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<ExpressContext, ResolverContext> = async ({
|
||||
throw new Error('No user id found in claims')
|
||||
}
|
||||
|
||||
return findSubscriptionsByNames(claims?.uid || '', names as string[])
|
||||
return batchGetSubscriptionsByNames(claims.uid, names as string[])
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
@ -1303,6 +1303,7 @@ export type HomeItem = {
|
||||
previewContent?: Maybe<Scalars['String']>;
|
||||
saveCount?: Maybe<Scalars['Int']>;
|
||||
seen_at?: Maybe<Scalars['Date']>;
|
||||
slug?: Maybe<Scalars['String']>;
|
||||
source?: Maybe<HomeItemSource>;
|
||||
thumbnail?: Maybe<Scalars['String']>;
|
||||
title: Scalars['String'];
|
||||
@ -6043,6 +6044,7 @@ export type HomeItemResolvers<ContextType = ResolverContext, ParentType extends
|
||||
previewContent?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
saveCount?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
|
||||
seen_at?: Resolver<Maybe<ResolversTypes['Date']>, ParentType, ContextType>;
|
||||
slug?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
source?: Resolver<Maybe<ResolversTypes['HomeItemSource']>, ParentType, ContextType>;
|
||||
thumbnail?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
|
||||
title?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
|
||||
@ -1172,6 +1172,7 @@ type HomeItem {
|
||||
previewContent: String
|
||||
saveCount: Int
|
||||
seen_at: Date
|
||||
slug: String
|
||||
source: HomeItemSource
|
||||
thumbnail: String
|
||||
title: String!
|
||||
|
||||
@ -311,7 +311,8 @@ const mixHomeItems = (rankedHomeItems: Array<Candidate>): Array<Section> => {
|
||||
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 (
|
||||
|
||||
@ -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<LibraryItem>
|
||||
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<PublicItem>
|
||||
|
||||
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,
|
||||
|
||||
@ -55,9 +55,9 @@ export interface RequestContext {
|
||||
highlights: DataLoader<string, Highlight[]>
|
||||
recommendations: DataLoader<string, Recommendation[]>
|
||||
uploadFiles: DataLoader<string, UploadFile | undefined>
|
||||
libraryItems: DataLoader<string, LibraryItem>
|
||||
publicItems: DataLoader<string, PublicItem>
|
||||
subscriptions: DataLoader<string, Subscription>
|
||||
libraryItems: DataLoader<string, LibraryItem | undefined>
|
||||
publicItems: DataLoader<string, PublicItem | undefined>
|
||||
subscriptions: DataLoader<string, Subscription | undefined>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3126,6 +3126,7 @@ const schema = gql`
|
||||
likeCount: Int
|
||||
broadcastCount: Int
|
||||
date: Date!
|
||||
slug: String
|
||||
author: String
|
||||
dir: String
|
||||
seen_at: Date
|
||||
|
||||
@ -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<Array<PublicItem>> => {
|
||||
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<Array<HomeItem>> => {
|
||||
const libraryItems = await findLibraryItemsByIds(ids as string[])
|
||||
|
||||
): Promise<Array<PublicItem | undefined>> => {
|
||||
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<HomeItem>
|
||||
return ids.map((id) => publicItems.find((pi) => pi.id === id))
|
||||
}
|
||||
|
||||
export const findUnseenPublicItems = async (
|
||||
|
||||
@ -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}`
|
||||
|
||||
@ -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'
|
||||
|
||||
Reference in New Issue
Block a user