Refactor savePage a bit to use it as a service from the jobs

This commit is contained in:
Jackson Harper
2024-01-20 21:07:02 +08:00
parent 2f405ebed0
commit a4e707075f
10 changed files with 53 additions and 88 deletions

View File

@ -3,10 +3,10 @@ import jwt from 'jsonwebtoken'
import { promisify } from 'util'
import { env } from '../env'
import { redisDataSource } from '../redis_data_source'
import { savePage } from '../services/save_page'
import { savePage, stringToRequestStatus } from '../services/save_page'
import { userRepository } from '../repository/user'
import { ArticleSavingRequestStatus, ParseResult } from '../generated/graphql'
import { logger } from '../utils/logger'
import { Readability } from '@omnivore/readability'
const signToken = promisify(jwt.sign)
@ -69,7 +69,7 @@ interface FetchResult {
title: string
content?: string
contentType?: string
readabilityResult?: unknown
readabilityResult?: Readability.ParseResult
}
const isFetchResult = (obj: unknown): obj is FetchResult => {
@ -238,60 +238,6 @@ const sendCreateArticleMutation = async (userId: string, input: unknown) => {
}
}
const sendSavePageMutation = async (userId: string, input: unknown) => {
const data = JSON.stringify({
query: `mutation SavePage ($input: SavePageInput!){
savePage(input:$input){
... on SaveSuccess{
url
clientRequestId
}
... on SaveError{
errorCodes
}
}
}`,
variables: {
input,
},
})
const auth = await signToken({ uid: userId }, JWT_SECRET)
try {
const response = await axios.post<SavePageResponse>(
`${REST_BACKEND_ENDPOINT}/graphql`,
data,
{
headers: {
Cookie: `auth=${auth as string};`,
'Content-Type': 'application/json',
},
timeout: REQUEST_TIMEOUT,
}
)
if (
response.data.data.savePage.errorCodes &&
response.data.data.savePage.errorCodes.length > 0
) {
console.error(
'error while saving page',
response.data.data.savePage.errorCodes[0]
)
if (response.data.data.savePage.errorCodes[0] === 'UNAUTHORIZED') {
return { error: 'UNAUTHORIZED' }
}
return null
}
return response.data.data.savePage
} catch (error) {
console.error('error saving page', error)
return null
}
}
const sendImportStatusUpdate = async (
userId: string,
taskId: string,
@ -409,26 +355,26 @@ export const savePageJob = async (data: Data, attemptsMade: number) => {
clientRequestId: articleSavingRequestId,
title,
originalContent: content,
parseResult: readabilityResult as ParseResult,
state: state as ArticleSavingRequestStatus,
parseResult: readabilityResult,
state: stringToRequestStatus(state),
labels: labels?.map((name) => {
return {
name,
}
}),
rssFeedUrl,
savedAt,
publishedAt,
savedAt: savedAt ? new Date(savedAt) : new Date(),
publishedAt: publishedAt ? new Date(publishedAt) : null,
source,
folder,
},
user
)
if (result.__typename == 'SaveError') {
logger.error('Error saving page', { userId, url, result })
throw new Error('Error saving page')
}
// if (result.__typename == 'SaveError') {
// logger.error('Error saving page', { userId, url, result })
// throw new Error('Error saving page')
// }
// if the readability result is not parsed, the import is failed
isImported = !!readabilityResult

View File

@ -93,7 +93,6 @@ import { traceAs } from '../../tracing'
import { analytics } from '../../utils/analytics'
import { isSiteBlockedForParse } from '../../utils/blocked'
import {
authorized,
cleanUrl,
errorHandler,
generateSlug,
@ -103,6 +102,7 @@ import {
titleForFilePath,
userDataToUser,
} from '../../utils/helpers'
import { authorized } from '../../utils/gql-utils'
import {
contentConverter,
getDistillerResult,

View File

@ -19,11 +19,12 @@ import {
} from '../../services/library_item'
import { analytics } from '../../utils/analytics'
import {
authorized,
cleanUrl,
isParsingTimeout,
libraryItemToArticleSavingRequest,
} from '../../utils/helpers'
import { authorized } from '../../utils/gql-utils'
import { isErrorWithCode } from '../user'
export const createArticleSavingRequestResolver = authorized<

View File

@ -34,7 +34,8 @@ import {
updateHighlight,
} from '../../services/highlights'
import { analytics } from '../../utils/analytics'
import { authorized, highlightDataToHighlight } from '../../utils/helpers'
import { highlightDataToHighlight } from '../../utils/helpers'
import { authorized } from '../../utils/gql-utils'
export const createHighlightResolver = authorized<
CreateHighlightSuccess,

View File

@ -40,7 +40,8 @@ import {
import { findLibraryItemById } from '../../services/library_item'
import { analytics } from '../../utils/analytics'
import { enqueueRecommendation } from '../../utils/createTask'
import { authorized, userDataToUser } from '../../utils/helpers'
import { userDataToUser } from '../../utils/helpers'
import { authorized } from '../../utils/gql-utils'
export const createGroupResolver = authorized<
CreateGroupSuccess,

View File

@ -44,11 +44,8 @@ import { unsubscribe } from '../../services/subscriptions'
import { Merge } from '../../util'
import { analytics } from '../../utils/analytics'
import { enqueueRssFeedFetch } from '../../utils/createTask'
import {
authorized,
getAbsoluteUrl,
keysToCamelCase,
} from '../../utils/helpers'
import { getAbsoluteUrl, keysToCamelCase } from '../../utils/helpers'
import { authorized } from '../../utils/gql-utils'
import { parseFeed, parseOpml, RSS_PARSER_CONFIG } from '../../utils/parser'
import { updateSubscription } from '../../services/update_subscription'

View File

@ -5,7 +5,8 @@ import {
UpdatePageSuccess,
} from '../../generated/graphql'
import { updateLibraryItem } from '../../services/library_item'
import { authorized, libraryItemToArticle } from '../../utils/helpers'
import { libraryItemToArticle } from '../../utils/helpers'
import { authorized } from '../../utils/gql-utils'
export const updatePageResolver = authorized<
UpdatePageSuccess,

View File

@ -19,7 +19,9 @@ import {
updateLibraryItem,
} from '../../services/library_item'
import { analytics } from '../../utils/analytics'
import { authorized, generateSlug } from '../../utils/helpers'
import { generateSlug } from '../../utils/helpers'
import { authorized } from '../../utils/gql-utils'
import {
contentReaderForLibraryItem,
generateUploadFilePathName,

View File

@ -43,9 +43,10 @@ import { userRepository } from '../../repository/user'
import { createUser } from '../../services/create_user'
import { sendVerificationEmail } from '../../services/send_emails'
import { softDeleteUser } from '../../services/user'
import { authorized, userDataToUser } from '../../utils/helpers'
import { userDataToUser } from '../../utils/helpers'
import { validateUsername } from '../../utils/usernamePolicy'
import { WithDataSourcesContext } from '../types'
import { authorized } from '../../utils/gql-utils'
export const updateUserResolver = authorized<
UpdateUserSuccess,

View File

@ -5,14 +5,12 @@ import { Highlight } from '../entity/highlight'
import { LibraryItem, LibraryItemState } from '../entity/library_item'
import { User } from '../entity/user'
import { homePageURL } from '../env'
import {
ArticleSavingRequestStatus,
Maybe,
PreparedDocumentInput,
SaveErrorCode,
SavePageInput,
SaveResult,
} from '../generated/graphql'
// import {
// ArticleSavingRequestStatus,
// PreparedDocumentInput,
// SaveErrorCode,
// SaveResult,
// } from '../generated/graphql'
import { authTrx } from '../repository'
import { enqueueThumbnailTask } from '../utils/createTask'
import {
@ -30,6 +28,14 @@ import { createPageSaveRequest } from './create_page_save_request'
import { createHighlight } from './highlights'
import { createAndSaveLabelsInLibraryItem } from './labels'
import { createLibraryItem, updateLibraryItem } from './library_item'
import { CreateLabelInput } from '../repository/label'
import {
ArticleSavingRequestStatus,
PreparedDocumentInput,
SaveErrorCode,
SavePageInput,
SaveResult,
} from '../generated/graphql'
// where we can use APIs to fetch their underlying content.
const FORCE_PUPPETEER_URLS = [
@ -43,7 +49,7 @@ const ALREADY_PARSED_SOURCES = [
'pocket',
]
const createSlug = (url: string, title?: Maybe<string> | undefined) => {
const createSlug = (url: string, title?: string | null | undefined) => {
const { pathname } = new URL(url)
const croppedPathname = decodeURIComponent(
pathname
@ -63,6 +69,15 @@ const shouldParseInBackend = (input: SavePageInput): boolean => {
)
}
export const stringToRequestStatus = (
str: string | undefined | null
): ArticleSavingRequestStatus | null => {
if (str && str in ArticleSavingRequestStatus) {
return str as ArticleSavingRequestStatus
}
return null
}
export const savePage = async (
input: SavePageInput,
user: User
@ -95,7 +110,7 @@ export const savePage = async (
canonicalUrl: parseResult.canonicalUrl,
savedAt: input.savedAt ? new Date(input.savedAt) : new Date(),
publishedAt: input.publishedAt ? new Date(input.publishedAt) : undefined,
state: input.state || undefined,
state: stringToRequestStatus(input.state) || undefined,
rssFeedUrl: input.rssFeedUrl,
folder: input.folder,
})
@ -109,7 +124,7 @@ export const savePage = async (
userId: user.id,
url: itemToSave.originalUrl,
articleSavingRequestId: clientRequestId || undefined,
state: input.state || undefined,
state: stringToRequestStatus(input.state) || undefined,
labels: input.labels || undefined,
folder: input.folder || undefined,
})