mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
allow returning library item information in highlight
This commit is contained in:
parent
9259a9cfe3
commit
51efff8b8e
6 changed files with 52 additions and 80 deletions
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -1133,6 +1133,7 @@ type Highlight {
|
|||
html: String
|
||||
id: ID!
|
||||
labels: [Label!]
|
||||
libraryItem: Article!
|
||||
patch: String
|
||||
prefix: String
|
||||
quote: String
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -751,6 +751,7 @@ const schema = gql`
|
|||
html: String
|
||||
color: String
|
||||
representation: RepresentationType!
|
||||
libraryItem: Article!
|
||||
}
|
||||
|
||||
input CreateHighlightInput {
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
Loading…
Reference in a new issue