From 9ef608b4b6e8ca32613a6078987381134dd01dba Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 3 Nov 2023 10:11:14 +0800 Subject: [PATCH 1/2] fix: highlights not added to the content if searching for highlighted content --- packages/api/src/resolvers/article/index.ts | 54 +++-- packages/api/src/resolvers/following/index.ts | 189 ++++++++++++++++++ .../api/src/resolvers/function_resolvers.ts | 23 +-- 3 files changed, 223 insertions(+), 43 deletions(-) create mode 100644 packages/api/src/resolvers/following/index.ts diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index 83ea4830b..8a4c8c8c3 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -46,7 +46,6 @@ import { TypeaheadSearchSuccess, UpdateReason, UpdatesSinceError, - UpdatesSinceErrorCode, UpdatesSinceSuccess, } from '../../generated/graphql' import { getColumns } from '../../repository' @@ -54,6 +53,7 @@ import { getInternalLabelWithColor } from '../../repository/label' import { libraryItemRepository } from '../../repository/library_item' import { userRepository } from '../../repository/user' import { createPageSaveRequest } from '../../services/create_page_save_request' +import { findHighlightsByLibraryItemId } from '../../services/highlights' import { addLabelsToLibraryItem, findLabelsByIds, @@ -661,28 +661,40 @@ export const searchResolver = authorized< libraryItems.pop() } - const edges = libraryItems.map((libraryItem) => { - if (params.includeContent && libraryItem.readableContent) { - // convert html to the requested format - const format = params.format || ArticleFormat.Html - try { - const converter = contentConverter(format) - if (converter) { - libraryItem.readableContent = converter( - libraryItem.readableContent, - libraryItem.highlights - ) - } - } catch (error) { - log.error('Error converting content', error) + const edges = await Promise.all( + libraryItems.map(async (libraryItem) => { + if ( + libraryItem.highlightAnnotations && + libraryItem.highlightAnnotations.length > 0 + ) { + libraryItem.highlights = await findHighlightsByLibraryItemId( + libraryItem.id, + uid + ) } - } - return { - node: libraryItemToSearchItem(libraryItem), - cursor: endCursor, - } - }) + if (params.includeContent && libraryItem.readableContent) { + // convert html to the requested format + const format = params.format || ArticleFormat.Html + try { + const converter = contentConverter(format) + if (converter) { + libraryItem.readableContent = converter( + libraryItem.readableContent, + libraryItem.highlights + ) + } + } catch (error) { + log.error('Error converting content', error) + } + } + + return { + node: libraryItemToSearchItem(libraryItem), + cursor: endCursor, + } + }) + ) return { edges, diff --git a/packages/api/src/resolvers/following/index.ts b/packages/api/src/resolvers/following/index.ts new file mode 100644 index 000000000..83fcf5b25 --- /dev/null +++ b/packages/api/src/resolvers/following/index.ts @@ -0,0 +1,189 @@ +import { UserFeedItem } from '../../entity/user_feed_item' +import { env } from '../../env' +import { + FeedEdge, + FeedsError, + FeedsErrorCode, + FeedsSuccess, + FollowingEdge, + FollowingError, + FollowingErrorCode, + FollowingSuccess, + MutationSaveFollowingArgs, + QueryFeedsArgs, + QueryFollowingArgs, + SaveFollowingError, + SaveFollowingErrorCode, + SaveFollowingSuccess, +} from '../../generated/graphql' +import { feedRepository } from '../../repository/feed' +import { userRepository } from '../../repository/user' +import { userFeedItemRepository } from '../../repository/user_feed_item' +import { saveUrl } from '../../services/save_url' +import { analytics } from '../../utils/analytics' +import { authorized } from '../../utils/helpers' + +export const feedsResolve = authorized< + FeedsSuccess, + FeedsError, + QueryFeedsArgs +>(async (_, { input }, { log }) => { + try { + const startCursor = input.after || '' + const start = + startCursor && !isNaN(Number(startCursor)) ? Number(startCursor) : 0 + const first = Math.min(input.first || 10, 100) // cap at 100 + + const { feeds, count } = await feedRepository.searchFeeds( + input.query || '', + first + 1, // fetch one extra to check if there is a next page + start, + input.sort?.by, + input.sort?.order || undefined + ) + + const hasNextPage = feeds.length > first + const endCursor = String(start + feeds.length - (hasNextPage ? 1 : 0)) + + if (hasNextPage) { + // remove an extra if exists + feeds.pop() + } + + const edges: FeedEdge[] = feeds.map((feed) => ({ + node: feed, + cursor: endCursor, + })) + + return { + __typename: 'FeedsSuccess', + edges, + pageInfo: { + hasPreviousPage: start > 0, + hasNextPage, + startCursor, + endCursor, + totalCount: count, + }, + } + } catch (error) { + log.error('Error fetching feeds', error) + + return { + errorCodes: [FeedsErrorCode.BadRequest], + } + } +}) + +export const followingResolver = authorized< + FollowingSuccess, + FollowingError, + QueryFollowingArgs +>(async (_, args, { authTrx, log }) => { + try { + const startCursor = args.after || '' + const start = + startCursor && !isNaN(Number(startCursor)) ? Number(startCursor) : 0 + const first = Math.min(args.first || 10, 100) // cap at 100 + const since = args.since ? new Date(args.since) : undefined + const until = args.until ? new Date(args.until) : undefined + + const { userFeedItems, count } = await authTrx((tx) => + tx.withRepository(userFeedItemRepository).searchUserFeedItems( + first + 1, // fetch one extra to check if there is a next page + start, + since, + until + ) + ) + + const hasNextPage = userFeedItems.length > first + const endCursor = String( + start + userFeedItems.length - (hasNextPage ? 1 : 0) + ) + + if (hasNextPage) { + // remove an extra if exists + userFeedItems.pop() + } + + const edges: FollowingEdge[] = userFeedItems.map((item) => ({ + node: { + ...item.feedItem, + ...item, + isHidden: !!item.hiddenAt, + isSaved: !!item.savedAt, + }, + cursor: endCursor, + })) + + return { + __typename: 'FollowingSuccess', + edges, + pageInfo: { + hasPreviousPage: start > 0, + hasNextPage, + startCursor, + endCursor, + totalCount: count, + }, + } + } catch (error) { + log.error('Error fetching following', error) + + return { + errorCodes: [FollowingErrorCode.Unauthorized], + } + } +}) + +export const saveFollowing = authorized< + SaveFollowingSuccess, + SaveFollowingError, + MutationSaveFollowingArgs +>(async (_, args, { authTrx, log, uid }) => { + try { + analytics.track({ + userId: uid, + event: 'save_following', + properties: { + id: args.id, + env: env.server.apiEnv, + }, + }) + + const user = await userRepository.findById(uid) + if (!user) { + return { errorCodes: [SaveFollowingErrorCode.Unauthorized] } + } + + const result = await authTrx((tx) => + tx.withRepository(userFeedItemRepository).updateAndReturn(args.id, { + savedAt: new Date(), + }) + ) + + if (!result.affected || result.affected < 1) { + return { + errorCodes: [SaveFollowingErrorCode.NotFound], + } + } + + const userFeedItem = result.generatedMaps[0] as UserFeedItem + + const saveResult = await saveUrl( + { + url: userFeedItem.feedItem.links[0], + clientRequestId: '', + source: 'following', + }, + user + ) + } catch (error) { + log.error('Error saving following', error) + + return { + errorCodes: [FeedsErrorCode.BadRequest], + } + } +}) diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index 397867f17..365a32162 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -3,23 +3,21 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +import { createHmac } from 'crypto' import { Subscription } from '../entity/subscription' import { env } from '../env' import { Article, - Highlight, Label, PageType, Recommendation, SearchItem, User, } from '../generated/graphql' -import { findHighlightsByLibraryItemId } from '../services/highlights' import { findLabelsByLibraryItemId } from '../services/labels' import { findRecommendationsByLibraryItemId } from '../services/recommendation' import { findUploadFileById } from '../services/upload_file' import { - highlightDataToHighlight, isBase64Image, recommandationDataToRecommendation, validatedDate, @@ -128,7 +126,6 @@ import { markEmailAsItemResolver, recentEmailsResolver } from './recent_emails' import { recentSearchesResolver } from './recent_searches' import { WithDataSourcesContext } from './types' import { updateEmailResolver } from './user' -import { createHmac } from 'crypto' /* eslint-disable @typescript-eslint/naming-convention */ type ResultResolveType = { @@ -378,24 +375,6 @@ export const functionResolvers = { return item.siteIcon }, - async highlights( - item: { - id: string - highlights?: Highlight[] - highlightAnnotations?: string[] | null - }, - _: unknown, - ctx: WithDataSourcesContext - ) { - if (item.highlights) return item.highlights - - if (item.highlightAnnotations && item.highlightAnnotations.length > 0) { - const highlights = await findHighlightsByLibraryItemId(item.id, ctx.uid) - return highlights.map(highlightDataToHighlight) - } - - return [] - }, async labels( item: { id: string; labels?: Label[]; labelNames?: string[] | null }, _: unknown, From 3761b396f444c81f19fae6071df352ab05ea5089 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Fri, 3 Nov 2023 10:17:36 +0800 Subject: [PATCH 2/2] remove unused code --- packages/api/src/resolvers/following/index.ts | 189 ------------------ 1 file changed, 189 deletions(-) delete mode 100644 packages/api/src/resolvers/following/index.ts diff --git a/packages/api/src/resolvers/following/index.ts b/packages/api/src/resolvers/following/index.ts deleted file mode 100644 index 83fcf5b25..000000000 --- a/packages/api/src/resolvers/following/index.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { UserFeedItem } from '../../entity/user_feed_item' -import { env } from '../../env' -import { - FeedEdge, - FeedsError, - FeedsErrorCode, - FeedsSuccess, - FollowingEdge, - FollowingError, - FollowingErrorCode, - FollowingSuccess, - MutationSaveFollowingArgs, - QueryFeedsArgs, - QueryFollowingArgs, - SaveFollowingError, - SaveFollowingErrorCode, - SaveFollowingSuccess, -} from '../../generated/graphql' -import { feedRepository } from '../../repository/feed' -import { userRepository } from '../../repository/user' -import { userFeedItemRepository } from '../../repository/user_feed_item' -import { saveUrl } from '../../services/save_url' -import { analytics } from '../../utils/analytics' -import { authorized } from '../../utils/helpers' - -export const feedsResolve = authorized< - FeedsSuccess, - FeedsError, - QueryFeedsArgs ->(async (_, { input }, { log }) => { - try { - const startCursor = input.after || '' - const start = - startCursor && !isNaN(Number(startCursor)) ? Number(startCursor) : 0 - const first = Math.min(input.first || 10, 100) // cap at 100 - - const { feeds, count } = await feedRepository.searchFeeds( - input.query || '', - first + 1, // fetch one extra to check if there is a next page - start, - input.sort?.by, - input.sort?.order || undefined - ) - - const hasNextPage = feeds.length > first - const endCursor = String(start + feeds.length - (hasNextPage ? 1 : 0)) - - if (hasNextPage) { - // remove an extra if exists - feeds.pop() - } - - const edges: FeedEdge[] = feeds.map((feed) => ({ - node: feed, - cursor: endCursor, - })) - - return { - __typename: 'FeedsSuccess', - edges, - pageInfo: { - hasPreviousPage: start > 0, - hasNextPage, - startCursor, - endCursor, - totalCount: count, - }, - } - } catch (error) { - log.error('Error fetching feeds', error) - - return { - errorCodes: [FeedsErrorCode.BadRequest], - } - } -}) - -export const followingResolver = authorized< - FollowingSuccess, - FollowingError, - QueryFollowingArgs ->(async (_, args, { authTrx, log }) => { - try { - const startCursor = args.after || '' - const start = - startCursor && !isNaN(Number(startCursor)) ? Number(startCursor) : 0 - const first = Math.min(args.first || 10, 100) // cap at 100 - const since = args.since ? new Date(args.since) : undefined - const until = args.until ? new Date(args.until) : undefined - - const { userFeedItems, count } = await authTrx((tx) => - tx.withRepository(userFeedItemRepository).searchUserFeedItems( - first + 1, // fetch one extra to check if there is a next page - start, - since, - until - ) - ) - - const hasNextPage = userFeedItems.length > first - const endCursor = String( - start + userFeedItems.length - (hasNextPage ? 1 : 0) - ) - - if (hasNextPage) { - // remove an extra if exists - userFeedItems.pop() - } - - const edges: FollowingEdge[] = userFeedItems.map((item) => ({ - node: { - ...item.feedItem, - ...item, - isHidden: !!item.hiddenAt, - isSaved: !!item.savedAt, - }, - cursor: endCursor, - })) - - return { - __typename: 'FollowingSuccess', - edges, - pageInfo: { - hasPreviousPage: start > 0, - hasNextPage, - startCursor, - endCursor, - totalCount: count, - }, - } - } catch (error) { - log.error('Error fetching following', error) - - return { - errorCodes: [FollowingErrorCode.Unauthorized], - } - } -}) - -export const saveFollowing = authorized< - SaveFollowingSuccess, - SaveFollowingError, - MutationSaveFollowingArgs ->(async (_, args, { authTrx, log, uid }) => { - try { - analytics.track({ - userId: uid, - event: 'save_following', - properties: { - id: args.id, - env: env.server.apiEnv, - }, - }) - - const user = await userRepository.findById(uid) - if (!user) { - return { errorCodes: [SaveFollowingErrorCode.Unauthorized] } - } - - const result = await authTrx((tx) => - tx.withRepository(userFeedItemRepository).updateAndReturn(args.id, { - savedAt: new Date(), - }) - ) - - if (!result.affected || result.affected < 1) { - return { - errorCodes: [SaveFollowingErrorCode.NotFound], - } - } - - const userFeedItem = result.generatedMaps[0] as UserFeedItem - - const saveResult = await saveUrl( - { - url: userFeedItem.feedItem.links[0], - clientRequestId: '', - source: 'following', - }, - user - ) - } catch (error) { - log.error('Error saving following', error) - - return { - errorCodes: [FeedsErrorCode.BadRequest], - } - } -})