allow returning library item information in highlight

This commit is contained in:
Hongbo Wu
2024-06-06 15:23:56 +08:00
parent 9259a9cfe3
commit 51efff8b8e
6 changed files with 52 additions and 80 deletions

View File

@ -1261,6 +1261,7 @@ export type Highlight = {
html?: Maybe<Scalars['String']>;
id: Scalars['ID'];
labels?: Maybe<Array<Label>>;
libraryItem: Article;
patch?: Maybe<Scalars['String']>;
prefix?: Maybe<Scalars['String']>;
quote?: Maybe<Scalars['String']>;
@ -6128,6 +6129,7 @@ export type HighlightResolvers<ContextType = ResolverContext, ParentType extends
html?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
labels?: Resolver<Maybe<Array<ResolversTypes['Label']>>, ParentType, ContextType>;
libraryItem?: Resolver<ResolversTypes['Article'], ParentType, ContextType>;
patch?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
prefix?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
quote?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;

View File

@ -1133,6 +1133,7 @@ type Highlight {
html: String
id: ID!
labels: [Label!]
libraryItem: Article!
patch: String
prefix: String
quote: String

View File

@ -6,7 +6,6 @@
import { createHmac } from 'crypto'
import { isError } from 'lodash'
import { Highlight } from '../entity/highlight'
import { Label } from '../entity/label'
import { LibraryItem } from '../entity/library_item'
import {
EXISTING_NEWSLETTER_FOLDER,
@ -71,14 +70,12 @@ import {
createHighlightResolver,
createLabelResolver,
createNewsletterEmailResolver,
// createReminderResolver,
deleteAccountResolver,
deleteFilterResolver,
deleteHighlightResolver,
deleteIntegrationResolver,
deleteLabelResolver,
deleteNewsletterEmailResolver,
// deleteReminderResolver,
deleteRuleResolver,
deleteWebhookResolver,
deviceTokensResolver,
@ -88,11 +85,7 @@ import {
generateApiKeyResolver,
getAllUsersResolver,
getArticleResolver,
// getFollowersResolver,
// getFollowingResolver,
getMeUserResolver,
// getSharedArticleResolver,
// getUserFeedArticlesResolver,
getUserPersonalizationResolver,
getUserResolver,
googleLoginResolver,
@ -112,7 +105,6 @@ import {
newsletterEmailsResolver,
recommendHighlightsResolver,
recommendResolver,
// reminderResolver,
reportItemResolver,
revokeApiKeyResolver,
rulesResolver,
@ -127,14 +119,11 @@ import {
setBookmarkArticleResolver,
setDeviceTokenResolver,
setFavoriteArticleResolver,
// setFollowResolver,
setIntegrationResolver,
setLabelsForHighlightResolver,
setLabelsResolver,
setLinkArchivedResolver,
setRuleResolver,
// setShareArticleResolver,
// setShareHighlightResolver,
setUserPersonalizationResolver,
setWebhookResolver,
subscribeResolver,
@ -145,10 +134,7 @@ import {
updateHighlightResolver,
updateLabelResolver,
updateNewsletterEmailResolver,
// updateLinkShareInfoResolver,
updatePageResolver,
// updateReminderResolver,
// updateSharedCommentResolver,
updatesSinceResolver,
updateSubscriptionResolver,
updateUserProfileResolver,
@ -259,30 +245,20 @@ export const functionResolvers = {
updateUserProfile: updateUserProfileResolver,
createArticle: createArticleResolver,
createHighlight: createHighlightResolver,
// createReaction: createReactionResolver,
// deleteReaction: deleteReactionResolver,
mergeHighlight: mergeHighlightResolver,
updateHighlight: updateHighlightResolver,
deleteHighlight: deleteHighlightResolver,
uploadFileRequest: uploadFileRequestResolver,
// setShareArticle: setShareArticleResolver,
// updateSharedComment: updateSharedCommentResolver,
// setFollow: setFollowResolver,
setBookmarkArticle: setBookmarkArticleResolver,
setUserPersonalization: setUserPersonalizationResolver,
createArticleSavingRequest: createArticleSavingRequestResolver,
// setShareHighlight: setShareHighlightResolver,
reportItem: reportItemResolver,
// updateLinkShareInfo: updateLinkShareInfoResolver,
setLinkArchived: setLinkArchivedResolver,
createNewsletterEmail: createNewsletterEmailResolver,
deleteNewsletterEmail: deleteNewsletterEmailResolver,
saveUrl: saveUrlResolver,
savePage: savePageResolver,
saveFile: saveFileResolver,
// createReminder: createReminderResolver,
// updateReminder: updateReminderResolver,
// deleteReminder: deleteReminderResolver,
setDeviceToken: setDeviceTokenResolver,
createLabel: createLabelResolver,
updateLabel: updateLabelResolver,
@ -340,14 +316,9 @@ export const functionResolvers = {
users: getAllUsersResolver,
validateUsername: validateUsernameResolver,
article: getArticleResolver,
// sharedArticle: getSharedArticleResolver,
// feedArticles: getUserFeedArticlesResolver,
// getFollowers: getFollowersResolver,
// getFollowing: getFollowingResolver,
getUserPersonalization: getUserPersonalizationResolver,
articleSavingRequest: articleSavingRequestResolver,
newsletterEmails: newsletterEmailsResolver,
// reminder: reminderResolver,
labels: labelsResolver,
search: searchResolver,
subscriptions: subscriptionsResolver,
@ -373,11 +344,7 @@ export const functionResolvers = {
highlights: highlightsResolver,
},
User: {
async intercomHash(
user: User,
__: Record<string, unknown>,
ctx: WithDataSourcesContext
) {
async intercomHash(user: User) {
if (env.intercom.secretKey) {
const userIdentifier = user.id.toString()
@ -445,8 +412,8 @@ export const functionResolvers = {
hasContent(article: LibraryItem) {
return !!article.originalContent && !!article.readableContent
},
publishedAt(article: { publishedAt: Date }) {
return validatedDate(article.publishedAt)
publishedAt(article: LibraryItem) {
return validatedDate(article.publishedAt || undefined)
},
image(article: LibraryItem): string | undefined {
if (article.thumbnail) {
@ -471,6 +438,15 @@ export const functionResolvers = {
return ctx.dataLoaders.labels.load(article.id)
},
async highlights(
article: LibraryItem,
_: unknown,
ctx: WithDataSourcesContext
) {
if (article.highlights) return article.highlights
return ctx.dataLoaders.highlights.load(article.id)
},
content: (item: LibraryItem) => item.readableContent,
hash: (item: LibraryItem) => item.textContentHash || '',
isArchived: (item: LibraryItem) => !!item.archivedAt,
@ -486,11 +462,18 @@ export const functionResolvers = {
return ctx.dataLoaders.users.load(highlight.userId)
},
createdByMe(
highlight: { user: { id: string } },
highlight: Highlight,
__: unknown,
ctx: WithDataSourcesContext
) {
return highlight.user.id === ctx.uid
return highlight.userId === ctx.uid
},
libraryItem(highlight: Highlight, _: unknown, ctx: WithDataSourcesContext) {
if (highlight.libraryItem) {
return highlight.libraryItem
}
return ctx.dataLoaders.libraryItems.load(highlight.libraryItemId)
},
},
SearchItem: {
@ -526,30 +509,19 @@ export const functionResolvers = {
return item.siteIcon
},
async labels(
item: { id: string; labels?: Label[] },
_: unknown,
ctx: WithDataSourcesContext
) {
async labels(item: LibraryItem, _: unknown, ctx: WithDataSourcesContext) {
if (item.labels) return item.labels
const labels = await ctx.dataLoaders.labels.load(item.id)
return labels
return ctx.dataLoaders.labels.load(item.id)
},
async recommendations(
item: {
id: string
recommendations?: Recommendation[]
},
item: LibraryItem,
_: unknown,
ctx: WithDataSourcesContext
) {
if (item.recommendations) return item.recommendations
const recommendations = await ctx.dataLoaders.recommendations.load(
item.id
)
return recommendations
return ctx.dataLoaders.recommendations.load(item.id)
},
async aiSummary(
item: LibraryItem,
@ -565,19 +537,14 @@ export const functionResolvers = {
)?.summary
},
async highlights(
item: {
id: string
highlights?: Highlight[]
},
item: LibraryItem,
_: unknown,
ctx: WithDataSourcesContext
) {
if (item.highlights) return item.highlights
const highlights = await ctx.dataLoaders.highlights.load(item.id)
return highlights
return ctx.dataLoaders.highlights.load(item.id)
},
...readingProgressHandlers,
async content(
item: PartialLibraryItem,
_: unknown,
@ -615,6 +582,7 @@ export const functionResolvers = {
},
isArchived: (item: LibraryItem) => !!item.archivedAt,
pageType: (item: LibraryItem) => item.itemType,
...readingProgressHandlers,
},
Subscription: {
newsletterEmail(subscription: Subscription) {
@ -811,31 +779,21 @@ export const functionResolvers = {
...resultResolveTypeResolver('UpdateUser'),
...resultResolveTypeResolver('UpdateUserProfile'),
...resultResolveTypeResolver('Article'),
// ...resultResolveTypeResolver('SharedArticle'),
...resultResolveTypeResolver('Articles'),
...resultResolveTypeResolver('User'),
...resultResolveTypeResolver('Users'),
...resultResolveTypeResolver('SaveArticleReadingProgress'),
// ...resultResolveTypeResolver('FeedArticles'),
...resultResolveTypeResolver('CreateArticle'),
...resultResolveTypeResolver('CreateHighlight'),
// ...resultResolveTypeResolver('CreateReaction'),
// ...resultResolveTypeResolver('DeleteReaction'),
...resultResolveTypeResolver('MergeHighlight'),
...resultResolveTypeResolver('UpdateHighlight'),
...resultResolveTypeResolver('DeleteHighlight'),
...resultResolveTypeResolver('UploadFileRequest'),
// ...resultResolveTypeResolver('SetShareArticle'),
// ...resultResolveTypeResolver('UpdateSharedComment'),
...resultResolveTypeResolver('SetBookmarkArticle'),
// ...resultResolveTypeResolver('SetFollow'),
// ...resultResolveTypeResolver('GetFollowers'),
// ...resultResolveTypeResolver('GetFollowing'),
...resultResolveTypeResolver('GetUserPersonalization'),
...resultResolveTypeResolver('SetUserPersonalization'),
...resultResolveTypeResolver('ArticleSavingRequest'),
...resultResolveTypeResolver('CreateArticleSavingRequest'),
// ...resultResolveTypeResolver('SetShareHighlight'),
...resultResolveTypeResolver('ArchiveLink'),
...resultResolveTypeResolver('CreateNewsletterEmail'),
...resultResolveTypeResolver('NewsletterEmails'),

View File

@ -237,25 +237,34 @@ export const highlightsResolver = authorized<
PartialHighlightsSuccess,
HighlightsError,
QueryHighlightsArgs
>(async (_, { after, first }, { uid, log }) => {
>(async (_, { after, first, query }, { uid, log }) => {
const limit = first || 10
const offset = parseInt(after || '0')
if (isNaN(offset) || offset < 0 || limit > 50) {
log.error('Invalid after', { after })
if (
isNaN(offset) ||
offset < 0 ||
limit > 50 ||
(query?.length && query.length > 1000)
) {
log.error('Invalid args', { after, first, query })
return {
errorCodes: [HighlightsErrorCode.BadRequest],
}
}
const highlights = await searchHighlights(uid, limit + 1, offset)
const highlights = await searchHighlights(
uid,
query || undefined,
limit + 1,
offset
)
const start = offset
const hasNextPage = highlights.length > limit
if (hasNextPage) {
highlights.pop()
}
const endCursor = String(start + highlights.length)
const endCursor = String(offset + highlights.length)
const edges = highlights.map((highlight) => ({
cursor: endCursor,
@ -265,9 +274,9 @@ export const highlightsResolver = authorized<
return {
edges,
pageInfo: {
startCursor: String(start),
startCursor: String(offset),
endCursor,
hasPreviousPage: start > 0,
hasPreviousPage: offset > 0,
hasNextPage,
},
}

View File

@ -751,6 +751,7 @@ const schema = gql`
html: String
color: String
representation: RepresentationType!
libraryItem: Article!
}
input CreateHighlightInput {

View File

@ -281,9 +281,10 @@ export const findHighlightsByLibraryItemId = async (
export const searchHighlights = async (
userId: string,
limit: number,
query?: string,
limit?: number,
offset?: number
) => {
): Promise<Array<Highlight>> => {
return authTrx(
async (tx) =>
tx.withRepository(highlightRepository).find({