feat: add set favorite article api which adds the favorites internal label to it

This commit is contained in:
Hongbo Wu 2023-06-09 13:09:47 +08:00
parent 6116746e80
commit 55904ccf04
5 changed files with 136 additions and 1 deletions

View file

@ -1271,6 +1271,7 @@ export type Mutation = {
saveUrl: SaveResult;
setBookmarkArticle: SetBookmarkArticleResult;
setDeviceToken: SetDeviceTokenResult;
setFavoriteArticle: SetFavoriteArticleResult;
setFollow: SetFollowResult;
setIntegration: SetIntegrationResult;
setLabels: SetLabelsResult;
@ -1516,6 +1517,11 @@ export type MutationSetDeviceTokenArgs = {
};
export type MutationSetFavoriteArticleArgs = {
id: Scalars['ID'];
};
export type MutationSetFollowArgs = {
input: SetFollowInput;
};
@ -2393,6 +2399,24 @@ export type SetDeviceTokenSuccess = {
deviceToken: DeviceToken;
};
export type SetFavoriteArticleError = {
__typename?: 'SetFavoriteArticleError';
errorCodes: Array<SetFavoriteArticleErrorCode>;
};
export enum SetFavoriteArticleErrorCode {
BadRequest = 'BAD_REQUEST',
NotFound = 'NOT_FOUND',
Unauthorized = 'UNAUTHORIZED'
}
export type SetFavoriteArticleResult = SetFavoriteArticleError | SetFavoriteArticleSuccess;
export type SetFavoriteArticleSuccess = {
__typename?: 'SetFavoriteArticleSuccess';
favoriteArticle: Article;
};
export type SetFollowError = {
__typename?: 'SetFollowError';
errorCodes: Array<SetFollowErrorCode>;
@ -3600,6 +3624,10 @@ export type ResolversTypes = {
SetDeviceTokenInput: SetDeviceTokenInput;
SetDeviceTokenResult: ResolversTypes['SetDeviceTokenError'] | ResolversTypes['SetDeviceTokenSuccess'];
SetDeviceTokenSuccess: ResolverTypeWrapper<SetDeviceTokenSuccess>;
SetFavoriteArticleError: ResolverTypeWrapper<SetFavoriteArticleError>;
SetFavoriteArticleErrorCode: SetFavoriteArticleErrorCode;
SetFavoriteArticleResult: ResolversTypes['SetFavoriteArticleError'] | ResolversTypes['SetFavoriteArticleSuccess'];
SetFavoriteArticleSuccess: ResolverTypeWrapper<SetFavoriteArticleSuccess>;
SetFollowError: ResolverTypeWrapper<SetFollowError>;
SetFollowErrorCode: SetFollowErrorCode;
SetFollowInput: SetFollowInput;
@ -4016,6 +4044,9 @@ export type ResolversParentTypes = {
SetDeviceTokenInput: SetDeviceTokenInput;
SetDeviceTokenResult: ResolversParentTypes['SetDeviceTokenError'] | ResolversParentTypes['SetDeviceTokenSuccess'];
SetDeviceTokenSuccess: SetDeviceTokenSuccess;
SetFavoriteArticleError: SetFavoriteArticleError;
SetFavoriteArticleResult: ResolversParentTypes['SetFavoriteArticleError'] | ResolversParentTypes['SetFavoriteArticleSuccess'];
SetFavoriteArticleSuccess: SetFavoriteArticleSuccess;
SetFollowError: SetFollowError;
SetFollowInput: SetFollowInput;
SetFollowResult: ResolversParentTypes['SetFollowError'] | ResolversParentTypes['SetFollowSuccess'];
@ -5065,6 +5096,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
saveUrl?: Resolver<ResolversTypes['SaveResult'], ParentType, ContextType, RequireFields<MutationSaveUrlArgs, 'input'>>;
setBookmarkArticle?: Resolver<ResolversTypes['SetBookmarkArticleResult'], ParentType, ContextType, RequireFields<MutationSetBookmarkArticleArgs, 'input'>>;
setDeviceToken?: Resolver<ResolversTypes['SetDeviceTokenResult'], ParentType, ContextType, RequireFields<MutationSetDeviceTokenArgs, 'input'>>;
setFavoriteArticle?: Resolver<ResolversTypes['SetFavoriteArticleResult'], ParentType, ContextType, RequireFields<MutationSetFavoriteArticleArgs, 'id'>>;
setFollow?: Resolver<ResolversTypes['SetFollowResult'], ParentType, ContextType, RequireFields<MutationSetFollowArgs, 'input'>>;
setIntegration?: Resolver<ResolversTypes['SetIntegrationResult'], ParentType, ContextType, RequireFields<MutationSetIntegrationArgs, 'input'>>;
setLabels?: Resolver<ResolversTypes['SetLabelsResult'], ParentType, ContextType, RequireFields<MutationSetLabelsArgs, 'input'>>;
@ -5542,6 +5574,20 @@ export type SetDeviceTokenSuccessResolvers<ContextType = ResolverContext, Parent
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type SetFavoriteArticleErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SetFavoriteArticleError'] = ResolversParentTypes['SetFavoriteArticleError']> = {
errorCodes?: Resolver<Array<ResolversTypes['SetFavoriteArticleErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type SetFavoriteArticleResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SetFavoriteArticleResult'] = ResolversParentTypes['SetFavoriteArticleResult']> = {
__resolveType: TypeResolveFn<'SetFavoriteArticleError' | 'SetFavoriteArticleSuccess', ParentType, ContextType>;
};
export type SetFavoriteArticleSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SetFavoriteArticleSuccess'] = ResolversParentTypes['SetFavoriteArticleSuccess']> = {
favoriteArticle?: Resolver<ResolversTypes['Article'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type SetFollowErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SetFollowError'] = ResolversParentTypes['SetFollowError']> = {
errorCodes?: Resolver<Array<ResolversTypes['SetFollowErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@ -6263,6 +6309,9 @@ export type Resolvers<ContextType = ResolverContext> = {
SetDeviceTokenError?: SetDeviceTokenErrorResolvers<ContextType>;
SetDeviceTokenResult?: SetDeviceTokenResultResolvers<ContextType>;
SetDeviceTokenSuccess?: SetDeviceTokenSuccessResolvers<ContextType>;
SetFavoriteArticleError?: SetFavoriteArticleErrorResolvers<ContextType>;
SetFavoriteArticleResult?: SetFavoriteArticleResultResolvers<ContextType>;
SetFavoriteArticleSuccess?: SetFavoriteArticleSuccessResolvers<ContextType>;
SetFollowError?: SetFollowErrorResolvers<ContextType>;
SetFollowResult?: SetFollowResultResolvers<ContextType>;
SetFollowSuccess?: SetFollowSuccessResolvers<ContextType>;

View file

@ -1139,6 +1139,7 @@ type Mutation {
saveUrl(input: SaveUrlInput!): SaveResult!
setBookmarkArticle(input: SetBookmarkArticleInput!): SetBookmarkArticleResult!
setDeviceToken(input: SetDeviceTokenInput!): SetDeviceTokenResult!
setFavoriteArticle(id: ID!): SetFavoriteArticleResult!
setFollow(input: SetFollowInput!): SetFollowResult!
setIntegration(input: SetIntegrationInput!): SetIntegrationResult!
setLabels(input: SetLabelsInput!): SetLabelsResult!
@ -1774,6 +1775,22 @@ type SetDeviceTokenSuccess {
deviceToken: DeviceToken!
}
type SetFavoriteArticleError {
errorCodes: [SetFavoriteArticleErrorCode!]!
}
enum SetFavoriteArticleErrorCode {
BAD_REQUEST
NOT_FOUND
UNAUTHORIZED
}
union SetFavoriteArticleResult = SetFavoriteArticleError | SetFavoriteArticleSuccess
type SetFavoriteArticleSuccess {
favoriteArticle: Article!
}
type SetFollowError {
errorCodes: [SetFollowErrorCode!]!
}

View file

@ -42,6 +42,7 @@ import {
MutationCreateArticleArgs,
MutationSaveArticleReadingProgressArgs,
MutationSetBookmarkArticleArgs,
MutationSetFavoriteArticleArgs,
MutationSetShareArticleArgs,
PageInfo,
QueryArticleArgs,
@ -60,6 +61,9 @@ import {
SetBookmarkArticleError,
SetBookmarkArticleErrorCode,
SetBookmarkArticleSuccess,
SetFavoriteArticleError,
SetFavoriteArticleErrorCode,
SetFavoriteArticleSuccess,
SetShareArticleError,
SetShareArticleErrorCode,
SetShareArticleSuccess,
@ -74,7 +78,11 @@ import {
UpdatesSinceSuccess,
} from '../../generated/graphql'
import { createPageSaveRequest } from '../../services/create_page_save_request'
import { createLabels, getLabelsByIds } from '../../services/labels'
import {
addLabelToPage,
createLabels,
getLabelsByIds,
} from '../../services/labels'
import { parsedContentToPage } from '../../services/save_page'
import { traceAs } from '../../tracing'
import { Merge } from '../../util'
@ -1152,6 +1160,45 @@ export const bulkActionResolver = authorized<
}
)
export const setFavoriteArticleResolver = authorized<
SetFavoriteArticleSuccess,
SetFavoriteArticleError,
MutationSetFavoriteArticleArgs
>(async (_, { id }, { claims: { uid }, log, pubsub }) => {
try {
const page = await getPageByParam({ userId: uid, _id: id })
if (!page) {
return { errorCodes: [SetFavoriteArticleErrorCode.NotFound] }
}
// adds Favorites label to page
const result = await addLabelToPage(
{
uid,
pubsub,
},
page.id,
{
name: 'Favorites',
color: '#07D2D0', // TODO: pick a color
}
)
if (!result) {
return { errorCodes: [SetFavoriteArticleErrorCode.Unauthorized] }
}
log.debug('Favorites label added:', result)
return {
favoriteArticle: page,
}
} catch (error) {
log.debug('Error adding Favorites label:', error)
return { errorCodes: [SetFavoriteArticleErrorCode.BadRequest] }
}
})
const getUpdateReason = (page: Page, since: Date) => {
if (page.state === ArticleSavingRequestStatus.Deleted) {
return UpdateReason.Deleted

View file

@ -23,6 +23,7 @@ import {
generateDownloadSignedUrl,
generateUploadFilePathName,
} from '../utils/uploads'
import { setFavoriteArticleResolver } from './article'
import { optInFeatureResolver } from './features'
import { uploadImportFileResolver } from './importers/uploadImportFileResolver'
import {
@ -204,6 +205,7 @@ export const functionResolvers = {
markEmailAsItem: markEmailAsItemResolver,
bulkAction: bulkActionResolver,
importFromIntegration: importFromIntegrationResolver,
setFavoriteArticle: setFavoriteArticleResolver,
},
Query: {
me: getMeUserResolver,
@ -659,4 +661,5 @@ export const functionResolvers = {
...resultResolveTypeResolver('MarkEmailAsItem'),
...resultResolveTypeResolver('BulkAction'),
...resultResolveTypeResolver('ImportFromIntegration'),
...resultResolveTypeResolver('SetFavoriteArticle'),
}

View file

@ -2454,6 +2454,24 @@ const schema = gql`
BAD_REQUEST
}
union SetFavoriteArticleResult =
SetFavoriteArticleSuccess
| SetFavoriteArticleError
type SetFavoriteArticleSuccess {
favoriteArticle: Article!
}
type SetFavoriteArticleError {
errorCodes: [SetFavoriteArticleErrorCode!]!
}
enum SetFavoriteArticleErrorCode {
UNAUTHORIZED
BAD_REQUEST
NOT_FOUND
}
# Mutations
type Mutation {
googleLogin(input: GoogleLoginInput!): LoginResult!
@ -2551,6 +2569,7 @@ const schema = gql`
async: Boolean # if true, return immediately and process in the background
): BulkActionResult!
importFromIntegration(integrationId: ID!): ImportFromIntegrationResult!
setFavoriteArticle(id: ID!): SetFavoriteArticleResult!
}
# FIXME: remove sort from feedArticles after all cached tabs are closed