Add updatesSince API resolver

This commit is contained in:
Hongbo Wu
2022-07-29 18:11:18 +08:00
parent 7ce183d6f8
commit 336d06375a
5 changed files with 113 additions and 13 deletions

View File

@ -2183,7 +2183,7 @@ export type UpdateUserSuccess = {
export type UpdatesSinceError = {
__typename?: 'UpdatesSinceError';
errorCodes?: Maybe<Array<UpdatesSinceErrorCode>>;
errorCodes: Array<UpdatesSinceErrorCode>;
};
export enum UpdatesSinceErrorCode {
@ -4339,7 +4339,7 @@ export type UpdateUserSuccessResolvers<ContextType = ResolverContext, ParentType
};
export type UpdatesSinceErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdatesSinceError'] = ResolversParentTypes['UpdatesSinceError']> = {
errorCodes?: Resolver<Maybe<Array<ResolversTypes['UpdatesSinceErrorCode']>>, ParentType, ContextType>;
errorCodes?: Resolver<Array<ResolversTypes['UpdatesSinceErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

View File

@ -1678,7 +1678,7 @@ type UpdateUserSuccess {
}
type UpdatesSinceError {
errorCodes: [UpdatesSinceErrorCode!]
errorCodes: [UpdatesSinceErrorCode!]!
}
enum UpdatesSinceErrorCode {

View File

@ -23,6 +23,7 @@ import {
QueryArticlesArgs,
QuerySearchArgs,
QueryTypeaheadSearchArgs,
QueryUpdatesSinceArgs,
ResolverFn,
SaveArticleReadingProgressError,
SaveArticleReadingProgressErrorCode,
@ -39,6 +40,10 @@ import {
TypeaheadSearchError,
TypeaheadSearchErrorCode,
TypeaheadSearchSuccess,
UpdateReason,
UpdatesSinceError,
UpdatesSinceErrorCode,
UpdatesSinceSuccess,
} from '../../generated/graphql'
import { Merge } from '../../util'
import {
@ -68,7 +73,7 @@ import { createImageProxyUrl } from '../../utils/imageproxy'
import normalizeUrl from 'normalize-url'
import { WithDataSourcesContext } from '../types'
import { parseSearchQuery } from '../../utils/search'
import { parseSearchQuery, SortBy, SortOrder } from '../../utils/search'
import { createPageSaveRequest } from '../../services/create_page_save_request'
import { analytics } from '../../utils/analytics'
import { env } from '../../env'
@ -618,7 +623,7 @@ export const setBookmarkArticleResolver = authorized<
async (
_,
{ input: { articleID, bookmark } },
{ models, authTrx, claims: { uid }, log, pubsub }
{ claims: { uid }, log, pubsub }
) => {
const page = await getPageById(articleID)
if (!page) {
@ -636,15 +641,14 @@ export const setBookmarkArticleResolver = authorized<
}
// delete the page
await updatePage(
const deleted = await updatePage(
pageRemoved.id,
{ state: ArticleSavingRequestStatus.Deleted },
{ pubsub, uid }
)
const highlightsUnshared = await authTrx(async (tx) => {
return models.highlight.unshareAllHighlights(articleID, uid, tx)
})
if (!deleted) {
return { errorCodes: [SetBookmarkArticleErrorCode.NotFound] }
}
analytics.track({
userId: uid,
@ -660,7 +664,6 @@ export const setBookmarkArticleResolver = authorized<
content: undefined,
originalHtml: undefined,
}),
highlightsUnshared: highlightsUnshared.length,
labels: {
source: 'resolver',
resolver: 'setBookmarkArticleResolver',
@ -683,7 +686,13 @@ export const setBookmarkArticleResolver = authorized<
userId: uid,
slug: generateSlug(page.title),
}
await updatePage(articleID, pageUpdated, { pubsub, uid })
const updated = await updatePage(articleID, pageUpdated, {
pubsub,
uid,
})
if (!updated) {
return { errorCodes: [SetBookmarkArticleErrorCode.NotFound] }
}
log.info('Article bookmarked', {
page: Object.assign({}, page, {
@ -927,3 +936,91 @@ export const typeaheadSearchResolver = authorized<
return { items: await searchAsYouType(claims.uid, query, first || undefined) }
})
export const updatesSinceResolver = authorized<
UpdatesSinceSuccess,
UpdatesSinceError,
QueryUpdatesSinceArgs
>(async (_obj, { since, first, after }, { claims: { uid } }) => {
if (!uid) {
return { errorCodes: [UpdatesSinceErrorCode.Unauthorized] }
}
analytics.track({
userId: uid,
event: 'updatesSince',
properties: {
env: env.server.apiEnv,
since,
first,
after,
},
})
const startCursor = after || ''
const size = first || 10
const startDate = new Date(since)
const [pages, totalCount] = (await searchPages(
{
from: Number(startCursor),
size: size + 1, // fetch one more item to get next cursor
includeDeleted: true,
dateFilters: [{ field: 'updatedAt', startDate }],
sort: { by: SortBy.UPDATED, order: SortOrder.ASCENDING },
},
uid
)) || [[], 0]
const start =
startCursor && !isNaN(Number(startCursor)) ? Number(startCursor) : 0
const hasNextPage = pages.length > size
const endCursor = String(start + pages.length - (hasNextPage ? 1 : 0))
//TODO: refactor so that the lastCursor included
if (hasNextPage) {
// remove an extra if exists
pages.pop()
}
const edges = pages.map((p) => {
const updateReason = getUpdateReason(p, startDate)
return {
node:
updateReason === UpdateReason.Deleted
? null
: ({
...p,
image: p.image && createImageProxyUrl(p.image, 88, 88),
isArchived: !!p.archivedAt,
contentReader:
p.pageType === PageType.File
? ContentReader.Pdf
: ContentReader.Web,
} as SearchItem),
cursor: endCursor,
itemID: p.id,
updateReason,
}
})
return {
edges,
pageInfo: {
hasPreviousPage: false,
startCursor,
hasNextPage,
endCursor,
totalCount,
},
}
})
const getUpdateReason = (page: Page, since: Date) => {
if (page.state === ArticleSavingRequestStatus.Deleted) {
return UpdateReason.Deleted
}
if (page.createdAt >= since) {
return UpdateReason.Created
}
return UpdateReason.Updated
}

View File

@ -82,6 +82,7 @@ import {
updatePageResolver,
updateReminderResolver,
updateSharedCommentResolver,
updatesSinceResolver,
updateUserProfileResolver,
updateUserResolver,
uploadFileRequestResolver,
@ -186,6 +187,7 @@ export const functionResolvers = {
webhook: webhookResolver,
apiKeys: apiKeysResolver,
typeaheadSearch: typeaheadSearchResolver,
updatesSince: updatesSinceResolver,
},
User: {
async sharedArticles(
@ -586,4 +588,5 @@ export const functionResolvers = {
...resultResolveTypeResolver('RevokeApiKey'),
...resultResolveTypeResolver('DeleteAccount'),
...resultResolveTypeResolver('TypeaheadSearch'),
...resultResolveTypeResolver('UpdatesSince'),
}

View File

@ -1783,7 +1783,7 @@ const schema = gql`
}
type UpdatesSinceError {
errorCodes: [UpdatesSinceErrorCode!]
errorCodes: [UpdatesSinceErrorCode!]!
}
enum UpdatesSinceErrorCode {