From 92aa11b98ed87a81ff1c3e5d7d2c70266ac0a603 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Tue, 19 Dec 2023 18:05:02 +0800 Subject: [PATCH] add fetchContent api --- packages/api/src/generated/graphql.ts | 48 ++++++++++++++++++ packages/api/src/generated/schema.graphql | 16 ++++++ packages/api/src/resolvers/article/index.ts | 49 +++++++++++++++++++ packages/api/src/schema.ts | 16 ++++++ .../src/services/create_page_save_request.ts | 2 +- 5 files changed, 130 insertions(+), 1 deletion(-) diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index ad76bc495..080b4614e 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -820,6 +820,23 @@ export type FeedsSuccess = { pageInfo: PageInfo; }; +export type FetchContentError = { + __typename?: 'FetchContentError'; + errorCodes: Array; +}; + +export enum FetchContentErrorCode { + BadRequest = 'BAD_REQUEST', + Unauthorized = 'UNAUTHORIZED' +} + +export type FetchContentResult = FetchContentError | FetchContentSuccess; + +export type FetchContentSuccess = { + __typename?: 'FetchContentSuccess'; + success: Scalars['Boolean']; +}; + export type Filter = { __typename?: 'Filter'; category?: Maybe; @@ -1335,6 +1352,7 @@ export type Mutation = { deleteNewsletterEmail: DeleteNewsletterEmailResult; deleteRule: DeleteRuleResult; deleteWebhook: DeleteWebhookResult; + fetchContent: FetchContentResult; generateApiKey: GenerateApiKeyResult; googleLogin: LoginResult; googleSignup: GoogleSignupResult; @@ -1467,6 +1485,11 @@ export type MutationDeleteWebhookArgs = { }; +export type MutationFetchContentArgs = { + id: Scalars['ID']; +}; + + export type MutationGenerateApiKeyArgs = { input: GenerateApiKeyInput; }; @@ -3624,6 +3647,10 @@ export type ResolversTypes = { FeedsInput: FeedsInput; FeedsResult: ResolversTypes['FeedsError'] | ResolversTypes['FeedsSuccess']; FeedsSuccess: ResolverTypeWrapper; + FetchContentError: ResolverTypeWrapper; + FetchContentErrorCode: FetchContentErrorCode; + FetchContentResult: ResolversTypes['FetchContentError'] | ResolversTypes['FetchContentSuccess']; + FetchContentSuccess: ResolverTypeWrapper; Filter: ResolverTypeWrapper; FiltersError: ResolverTypeWrapper; FiltersErrorCode: FiltersErrorCode; @@ -4119,6 +4146,9 @@ export type ResolversParentTypes = { FeedsInput: FeedsInput; FeedsResult: ResolversParentTypes['FeedsError'] | ResolversParentTypes['FeedsSuccess']; FeedsSuccess: FeedsSuccess; + FetchContentError: FetchContentError; + FetchContentResult: ResolversParentTypes['FetchContentError'] | ResolversParentTypes['FetchContentSuccess']; + FetchContentSuccess: FetchContentSuccess; Filter: Filter; FiltersError: FiltersError; FiltersResult: ResolversParentTypes['FiltersError'] | ResolversParentTypes['FiltersSuccess']; @@ -4987,6 +5017,20 @@ export type FeedsSuccessResolvers; }; +export type FetchContentErrorResolvers = { + errorCodes?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}; + +export type FetchContentResultResolvers = { + __resolveType: TypeResolveFn<'FetchContentError' | 'FetchContentSuccess', ParentType, ContextType>; +}; + +export type FetchContentSuccessResolvers = { + success?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type FilterResolvers = { category?: Resolver, ParentType, ContextType>; createdAt?: Resolver; @@ -5377,6 +5421,7 @@ export type MutationResolvers>; deleteRule?: Resolver>; deleteWebhook?: Resolver>; + fetchContent?: Resolver>; generateApiKey?: Resolver>; googleLogin?: Resolver>; googleSignup?: Resolver>; @@ -6559,6 +6604,9 @@ export type Resolvers = { FeedsError?: FeedsErrorResolvers; FeedsResult?: FeedsResultResolvers; FeedsSuccess?: FeedsSuccessResolvers; + FetchContentError?: FetchContentErrorResolvers; + FetchContentResult?: FetchContentResultResolvers; + FetchContentSuccess?: FetchContentSuccessResolvers; Filter?: FilterResolvers; FiltersError?: FiltersErrorResolvers; FiltersResult?: FiltersResultResolvers; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index f54cac8f3..97fbbe750 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -728,6 +728,21 @@ type FeedsSuccess { pageInfo: PageInfo! } +type FetchContentError { + errorCodes: [FetchContentErrorCode!]! +} + +enum FetchContentErrorCode { + BAD_REQUEST + UNAUTHORIZED +} + +union FetchContentResult = FetchContentError | FetchContentSuccess + +type FetchContentSuccess { + success: Boolean! +} + type Filter { category: String createdAt: Date! @@ -1198,6 +1213,7 @@ type Mutation { deleteNewsletterEmail(newsletterEmailId: ID!): DeleteNewsletterEmailResult! deleteRule(id: ID!): DeleteRuleResult! deleteWebhook(id: ID!): DeleteWebhookResult! + fetchContent(id: ID!): FetchContentResult! generateApiKey(input: GenerateApiKeyInput!): GenerateApiKeyResult! googleLogin(input: GoogleLoginInput!): LoginResult! googleSignup(input: GoogleSignupInput!): GoogleSignupResult! diff --git a/packages/api/src/resolvers/article/index.ts b/packages/api/src/resolvers/article/index.ts index 9969dfa95..ec7bd1e8e 100644 --- a/packages/api/src/resolvers/article/index.ts +++ b/packages/api/src/resolvers/article/index.ts @@ -21,11 +21,15 @@ import { CreateArticleError, CreateArticleErrorCode, CreateArticleSuccess, + FetchContentError, + FetchContentErrorCode, + FetchContentSuccess, MoveToFolderError, MoveToFolderErrorCode, MoveToFolderSuccess, MutationBulkActionArgs, MutationCreateArticleArgs, + MutationFetchContentArgs, MutationMoveToFolderArgs, MutationSaveArticleReadingProgressArgs, MutationSetBookmarkArticleArgs, @@ -67,6 +71,7 @@ import { } from '../../services/labels' import { createLibraryItem, + findLibraryItemById, findLibraryItemByUrl, findLibraryItemsByPrefix, searchLibraryItems, @@ -981,6 +986,50 @@ export const moveToFolderResolver = authorized< } }) +export const fetchContentResolver = authorized< + FetchContentSuccess, + FetchContentError, + MutationFetchContentArgs +>(async (_, { id }, { uid, log, pubsub }) => { + analytics.track({ + userId: uid, + event: 'fetch_content', + properties: { + id, + }, + }) + + const item = await findLibraryItemById(id, uid) + if (!item) { + return { + errorCodes: [FetchContentErrorCode.Unauthorized], + } + } + + // if the content is not fetched yet, create a page save request + if (item.state === LibraryItemState.ContentNotFetched) { + try { + await createPageSaveRequest({ + userId: uid, + url: item.originalUrl, + articleSavingRequestId: id, + priority: 'high', + pubsub, + }) + } catch (error) { + log.error('fetchContentResolver error', error) + + return { + errorCodes: [FetchContentErrorCode.BadRequest], + } + } + } + + return { + success: true, + } +}) + const getUpdateReason = (libraryItem: LibraryItem, since: Date) => { if (libraryItem.deletedAt) { return UpdateReason.Deleted diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index afc66d1bc..49c64e669 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -2722,6 +2722,21 @@ const schema = gql` BAD_REQUEST } + union FetchContentResult = FetchContentSuccess | FetchContentError + + type FetchContentSuccess { + success: Boolean! + } + + type FetchContentError { + errorCodes: [FetchContentErrorCode!]! + } + + enum FetchContentErrorCode { + UNAUTHORIZED + BAD_REQUEST + } + # Mutations type Mutation { googleLogin(input: GoogleLoginInput!): LoginResult! @@ -2829,6 +2844,7 @@ const schema = gql` input: UpdateSubscriptionInput! ): UpdateSubscriptionResult! moveToFolder(id: ID!, folder: String!): MoveToFolderResult! + fetchContent(id: ID!): FetchContentResult! } # FIXME: remove sort from feedArticles after all cached tabs are closed diff --git a/packages/api/src/services/create_page_save_request.ts b/packages/api/src/services/create_page_save_request.ts index 4e1fd6b07..bd336f28c 100644 --- a/packages/api/src/services/create_page_save_request.ts +++ b/packages/api/src/services/create_page_save_request.ts @@ -137,7 +137,7 @@ export const createPageSaveRequest = async ({ pubsub ) } - // reset state to processing if not in following + // reset state to processing if (libraryItem.state !== LibraryItemState.Processing) { libraryItem = await updateLibraryItem( libraryItem.id,