list posts api

This commit is contained in:
Hongbo Wu 2024-06-15 22:07:32 +08:00
parent c02f2d5036
commit 3fb146e864
9 changed files with 685 additions and 36 deletions

View file

@ -19,11 +19,11 @@ export class Post {
@JoinColumn({ name: 'user_id' })
user!: User
@Column('uuid', { array: true })
libraryItemIds!: string[]
@Column('uuid', { array: true, nullable: true })
libraryItemIds?: string[]
@Column('uuid', { array: true })
highlightIds!: string[]
@Column('uuid', { array: true, nullable: true })
highlightIds?: string[]
@Column('text')
title!: string

View file

@ -509,6 +509,32 @@ export type CreateNewsletterEmailSuccess = {
newsletterEmail: NewsletterEmail;
};
export type CreatePostError = {
__typename?: 'CreatePostError';
errorCodes: Array<CreatePostErrorCode>;
};
export enum CreatePostErrorCode {
BadRequest = 'BAD_REQUEST',
Unauthorized = 'UNAUTHORIZED'
}
export type CreatePostInput = {
content: Scalars['String'];
highlightIds?: InputMaybe<Array<Scalars['ID']>>;
libraryItemIds?: InputMaybe<Array<Scalars['ID']>>;
thought?: InputMaybe<Scalars['String']>;
thumbnail?: InputMaybe<Scalars['String']>;
title: Scalars['String'];
};
export type CreatePostResult = CreatePostError | CreatePostSuccess;
export type CreatePostSuccess = {
__typename?: 'CreatePostSuccess';
post: Post;
};
export type CreateReactionError = {
__typename?: 'CreateReactionError';
errorCodes: Array<CreateReactionErrorCode>;
@ -749,6 +775,23 @@ export type DeleteNewsletterEmailSuccess = {
newsletterEmail: NewsletterEmail;
};
export type DeletePostError = {
__typename?: 'DeletePostError';
errorCodes: Array<DeletePostErrorCode>;
};
export enum DeletePostErrorCode {
BadRequest = 'BAD_REQUEST',
Unauthorized = 'UNAUTHORIZED'
}
export type DeletePostResult = DeletePostError | DeletePostSuccess;
export type DeletePostSuccess = {
__typename?: 'DeletePostSuccess';
success: Scalars['Boolean'];
};
export type DeleteReactionError = {
__typename?: 'DeleteReactionError';
errorCodes: Array<DeleteReactionErrorCode>;
@ -1800,6 +1843,7 @@ export type Mutation = {
createHighlight: CreateHighlightResult;
createLabel: CreateLabelResult;
createNewsletterEmail: CreateNewsletterEmailResult;
createPost: CreatePostResult;
deleteAccount: DeleteAccountResult;
deleteDiscoverArticle: DeleteDiscoverArticleResult;
deleteDiscoverFeed: DeleteDiscoverFeedResult;
@ -1809,6 +1853,7 @@ export type Mutation = {
deleteIntegration: DeleteIntegrationResult;
deleteLabel: DeleteLabelResult;
deleteNewsletterEmail: DeleteNewsletterEmailResult;
deletePost: DeletePostResult;
deleteRule: DeleteRuleResult;
deleteWebhook: DeleteWebhookResult;
editDiscoverFeed: EditDiscoverFeedResult;
@ -1859,6 +1904,7 @@ export type Mutation = {
updateLabel: UpdateLabelResult;
updateNewsletterEmail: UpdateNewsletterEmailResult;
updatePage: UpdatePageResult;
updatePost: UpdatePostResult;
updateSubscription: UpdateSubscriptionResult;
updateUser: UpdateUserResult;
updateUserProfile: UpdateUserProfileResult;
@ -1922,6 +1968,11 @@ export type MutationCreateNewsletterEmailArgs = {
};
export type MutationCreatePostArgs = {
input: CreatePostInput;
};
export type MutationDeleteAccountArgs = {
userID: Scalars['ID'];
};
@ -1967,6 +2018,11 @@ export type MutationDeleteNewsletterEmailArgs = {
};
export type MutationDeletePostArgs = {
id: Scalars['ID'];
};
export type MutationDeleteRuleArgs = {
id: Scalars['ID'];
};
@ -2205,6 +2261,11 @@ export type MutationUpdatePageArgs = {
};
export type MutationUpdatePostArgs = {
input: UpdatePostInput;
};
export type MutationUpdateSubscriptionArgs = {
input: UpdateSubscriptionInput;
};
@ -2346,6 +2407,62 @@ export type ParseResult = {
title: Scalars['String'];
};
export type Post = {
__typename?: 'Post';
author: User;
content: Scalars['String'];
createdAt: Scalars['Date'];
highlights?: Maybe<Array<Highlight>>;
id: Scalars['ID'];
libraryItems?: Maybe<Array<Article>>;
ownedByViewer: Scalars['Boolean'];
thought?: Maybe<Scalars['String']>;
thumbnail?: Maybe<Scalars['String']>;
title: Scalars['String'];
updatedAt: Scalars['Date'];
};
export type PostEdge = {
__typename?: 'PostEdge';
cursor: Scalars['String'];
node: Post;
};
export type PostError = {
__typename?: 'PostError';
errorCodes: Array<PostErrorCode>;
};
export enum PostErrorCode {
BadRequest = 'BAD_REQUEST',
Unauthorized = 'UNAUTHORIZED'
}
export type PostResult = PostError | PostSuccess;
export type PostSuccess = {
__typename?: 'PostSuccess';
post: Post;
};
export type PostsError = {
__typename?: 'PostsError';
errorCodes: Array<PostsErrorCode>;
};
export enum PostsErrorCode {
BadRequest = 'BAD_REQUEST',
Unauthorized = 'UNAUTHORIZED'
}
export type PostsResult = PostsError | PostsSuccess;
export type PostsSuccess = {
__typename?: 'PostsSuccess';
edges: Array<PostEdge>;
pageInfo: PageInfo;
};
export type PreparedDocumentInput = {
document: Scalars['String'];
pageInfo: PageInfoInput;
@ -2383,6 +2500,8 @@ export type Query = {
labels: LabelsResult;
me?: Maybe<User>;
newsletterEmails: NewsletterEmailsResult;
post: PostResult;
posts: PostsResult;
recentEmails: RecentEmailsResult;
recentSearches: RecentSearchesResult;
rules: RulesResult;
@ -2445,6 +2564,18 @@ export type QueryIntegrationArgs = {
};
export type QueryPostArgs = {
id: Scalars['ID'];
};
export type QueryPostsArgs = {
after?: InputMaybe<Scalars['String']>;
first?: InputMaybe<Scalars['Int']>;
userId: Scalars['ID'];
};
export type QueryRulesArgs = {
enabled?: InputMaybe<Scalars['Boolean']>;
};
@ -3824,6 +3955,33 @@ export type UpdatePageSuccess = {
updatedPage: Article;
};
export type UpdatePostError = {
__typename?: 'UpdatePostError';
errorCodes: Array<UpdatePostErrorCode>;
};
export enum UpdatePostErrorCode {
BadRequest = 'BAD_REQUEST',
Unauthorized = 'UNAUTHORIZED'
}
export type UpdatePostInput = {
content?: InputMaybe<Scalars['String']>;
highlightIds?: InputMaybe<Array<Scalars['ID']>>;
id: Scalars['ID'];
libraryItemIds?: InputMaybe<Array<Scalars['ID']>>;
thought?: InputMaybe<Scalars['String']>;
thumbnail?: InputMaybe<Scalars['String']>;
title?: InputMaybe<Scalars['String']>;
};
export type UpdatePostResult = UpdatePostError | UpdatePostSuccess;
export type UpdatePostSuccess = {
__typename?: 'UpdatePostSuccess';
post: Post;
};
export enum UpdateReason {
Created = 'CREATED',
Deleted = 'DELETED',
@ -4324,6 +4482,11 @@ export type ResolversTypes = {
CreateNewsletterEmailInput: CreateNewsletterEmailInput;
CreateNewsletterEmailResult: ResolversTypes['CreateNewsletterEmailError'] | ResolversTypes['CreateNewsletterEmailSuccess'];
CreateNewsletterEmailSuccess: ResolverTypeWrapper<CreateNewsletterEmailSuccess>;
CreatePostError: ResolverTypeWrapper<CreatePostError>;
CreatePostErrorCode: CreatePostErrorCode;
CreatePostInput: CreatePostInput;
CreatePostResult: ResolversTypes['CreatePostError'] | ResolversTypes['CreatePostSuccess'];
CreatePostSuccess: ResolverTypeWrapper<CreatePostSuccess>;
CreateReactionError: ResolverTypeWrapper<CreateReactionError>;
CreateReactionErrorCode: CreateReactionErrorCode;
CreateReactionInput: CreateReactionInput;
@ -4377,6 +4540,10 @@ export type ResolversTypes = {
DeleteNewsletterEmailErrorCode: DeleteNewsletterEmailErrorCode;
DeleteNewsletterEmailResult: ResolversTypes['DeleteNewsletterEmailError'] | ResolversTypes['DeleteNewsletterEmailSuccess'];
DeleteNewsletterEmailSuccess: ResolverTypeWrapper<DeleteNewsletterEmailSuccess>;
DeletePostError: ResolverTypeWrapper<DeletePostError>;
DeletePostErrorCode: DeletePostErrorCode;
DeletePostResult: ResolversTypes['DeletePostError'] | ResolversTypes['DeletePostSuccess'];
DeletePostSuccess: ResolverTypeWrapper<DeletePostSuccess>;
DeleteReactionError: ResolverTypeWrapper<DeleteReactionError>;
DeleteReactionErrorCode: DeleteReactionErrorCode;
DeleteReactionResult: ResolversTypes['DeleteReactionError'] | ResolversTypes['DeleteReactionSuccess'];
@ -4589,6 +4756,16 @@ export type ResolversTypes = {
PageInfoInput: PageInfoInput;
PageType: PageType;
ParseResult: ParseResult;
Post: ResolverTypeWrapper<Post>;
PostEdge: ResolverTypeWrapper<PostEdge>;
PostError: ResolverTypeWrapper<PostError>;
PostErrorCode: PostErrorCode;
PostResult: ResolversTypes['PostError'] | ResolversTypes['PostSuccess'];
PostSuccess: ResolverTypeWrapper<PostSuccess>;
PostsError: ResolverTypeWrapper<PostsError>;
PostsErrorCode: PostsErrorCode;
PostsResult: ResolversTypes['PostsError'] | ResolversTypes['PostsSuccess'];
PostsSuccess: ResolverTypeWrapper<PostsSuccess>;
PreparedDocumentInput: PreparedDocumentInput;
Profile: ResolverTypeWrapper<Profile>;
Query: ResolverTypeWrapper<{}>;
@ -4823,6 +5000,11 @@ export type ResolversTypes = {
UpdatePageInput: UpdatePageInput;
UpdatePageResult: ResolversTypes['UpdatePageError'] | ResolversTypes['UpdatePageSuccess'];
UpdatePageSuccess: ResolverTypeWrapper<UpdatePageSuccess>;
UpdatePostError: ResolverTypeWrapper<UpdatePostError>;
UpdatePostErrorCode: UpdatePostErrorCode;
UpdatePostInput: UpdatePostInput;
UpdatePostResult: ResolversTypes['UpdatePostError'] | ResolversTypes['UpdatePostSuccess'];
UpdatePostSuccess: ResolverTypeWrapper<UpdatePostSuccess>;
UpdateReason: UpdateReason;
UpdateReminderError: ResolverTypeWrapper<UpdateReminderError>;
UpdateReminderErrorCode: UpdateReminderErrorCode;
@ -4952,6 +5134,10 @@ export type ResolversParentTypes = {
CreateNewsletterEmailInput: CreateNewsletterEmailInput;
CreateNewsletterEmailResult: ResolversParentTypes['CreateNewsletterEmailError'] | ResolversParentTypes['CreateNewsletterEmailSuccess'];
CreateNewsletterEmailSuccess: CreateNewsletterEmailSuccess;
CreatePostError: CreatePostError;
CreatePostInput: CreatePostInput;
CreatePostResult: ResolversParentTypes['CreatePostError'] | ResolversParentTypes['CreatePostSuccess'];
CreatePostSuccess: CreatePostSuccess;
CreateReactionError: CreateReactionError;
CreateReactionInput: CreateReactionInput;
CreateReactionResult: ResolversParentTypes['CreateReactionError'] | ResolversParentTypes['CreateReactionSuccess'];
@ -4993,6 +5179,9 @@ export type ResolversParentTypes = {
DeleteNewsletterEmailError: DeleteNewsletterEmailError;
DeleteNewsletterEmailResult: ResolversParentTypes['DeleteNewsletterEmailError'] | ResolversParentTypes['DeleteNewsletterEmailSuccess'];
DeleteNewsletterEmailSuccess: DeleteNewsletterEmailSuccess;
DeletePostError: DeletePostError;
DeletePostResult: ResolversParentTypes['DeletePostError'] | ResolversParentTypes['DeletePostSuccess'];
DeletePostSuccess: DeletePostSuccess;
DeleteReactionError: DeleteReactionError;
DeleteReactionResult: ResolversParentTypes['DeleteReactionError'] | ResolversParentTypes['DeleteReactionSuccess'];
DeleteReactionSuccess: DeleteReactionSuccess;
@ -5157,6 +5346,14 @@ export type ResolversParentTypes = {
PageInfo: PageInfo;
PageInfoInput: PageInfoInput;
ParseResult: ParseResult;
Post: Post;
PostEdge: PostEdge;
PostError: PostError;
PostResult: ResolversParentTypes['PostError'] | ResolversParentTypes['PostSuccess'];
PostSuccess: PostSuccess;
PostsError: PostsError;
PostsResult: ResolversParentTypes['PostsError'] | ResolversParentTypes['PostsSuccess'];
PostsSuccess: PostsSuccess;
PreparedDocumentInput: PreparedDocumentInput;
Profile: Profile;
Query: {};
@ -5339,6 +5536,10 @@ export type ResolversParentTypes = {
UpdatePageInput: UpdatePageInput;
UpdatePageResult: ResolversParentTypes['UpdatePageError'] | ResolversParentTypes['UpdatePageSuccess'];
UpdatePageSuccess: UpdatePageSuccess;
UpdatePostError: UpdatePostError;
UpdatePostInput: UpdatePostInput;
UpdatePostResult: ResolversParentTypes['UpdatePostError'] | ResolversParentTypes['UpdatePostSuccess'];
UpdatePostSuccess: UpdatePostSuccess;
UpdateReminderError: UpdateReminderError;
UpdateReminderInput: UpdateReminderInput;
UpdateReminderResult: ResolversParentTypes['UpdateReminderError'] | ResolversParentTypes['UpdateReminderSuccess'];
@ -5702,6 +5903,20 @@ export type CreateNewsletterEmailSuccessResolvers<ContextType = ResolverContext,
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type CreatePostErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['CreatePostError'] = ResolversParentTypes['CreatePostError']> = {
errorCodes?: Resolver<Array<ResolversTypes['CreatePostErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type CreatePostResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['CreatePostResult'] = ResolversParentTypes['CreatePostResult']> = {
__resolveType: TypeResolveFn<'CreatePostError' | 'CreatePostSuccess', ParentType, ContextType>;
};
export type CreatePostSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['CreatePostSuccess'] = ResolversParentTypes['CreatePostSuccess']> = {
post?: Resolver<ResolversTypes['Post'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type CreateReactionErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['CreateReactionError'] = ResolversParentTypes['CreateReactionError']> = {
errorCodes?: Resolver<Array<ResolversTypes['CreateReactionErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@ -5874,6 +6089,20 @@ export type DeleteNewsletterEmailSuccessResolvers<ContextType = ResolverContext,
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type DeletePostErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeletePostError'] = ResolversParentTypes['DeletePostError']> = {
errorCodes?: Resolver<Array<ResolversTypes['DeletePostErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type DeletePostResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeletePostResult'] = ResolversParentTypes['DeletePostResult']> = {
__resolveType: TypeResolveFn<'DeletePostError' | 'DeletePostSuccess', ParentType, ContextType>;
};
export type DeletePostSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeletePostSuccess'] = ResolversParentTypes['DeletePostSuccess']> = {
success?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type DeleteReactionErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeleteReactionError'] = ResolversParentTypes['DeleteReactionError']> = {
errorCodes?: Resolver<Array<ResolversTypes['DeleteReactionErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@ -6693,6 +6922,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
createHighlight?: Resolver<ResolversTypes['CreateHighlightResult'], ParentType, ContextType, RequireFields<MutationCreateHighlightArgs, 'input'>>;
createLabel?: Resolver<ResolversTypes['CreateLabelResult'], ParentType, ContextType, RequireFields<MutationCreateLabelArgs, 'input'>>;
createNewsletterEmail?: Resolver<ResolversTypes['CreateNewsletterEmailResult'], ParentType, ContextType, Partial<MutationCreateNewsletterEmailArgs>>;
createPost?: Resolver<ResolversTypes['CreatePostResult'], ParentType, ContextType, RequireFields<MutationCreatePostArgs, 'input'>>;
deleteAccount?: Resolver<ResolversTypes['DeleteAccountResult'], ParentType, ContextType, RequireFields<MutationDeleteAccountArgs, 'userID'>>;
deleteDiscoverArticle?: Resolver<ResolversTypes['DeleteDiscoverArticleResult'], ParentType, ContextType, RequireFields<MutationDeleteDiscoverArticleArgs, 'input'>>;
deleteDiscoverFeed?: Resolver<ResolversTypes['DeleteDiscoverFeedResult'], ParentType, ContextType, RequireFields<MutationDeleteDiscoverFeedArgs, 'input'>>;
@ -6702,6 +6932,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
deleteIntegration?: Resolver<ResolversTypes['DeleteIntegrationResult'], ParentType, ContextType, RequireFields<MutationDeleteIntegrationArgs, 'id'>>;
deleteLabel?: Resolver<ResolversTypes['DeleteLabelResult'], ParentType, ContextType, RequireFields<MutationDeleteLabelArgs, 'id'>>;
deleteNewsletterEmail?: Resolver<ResolversTypes['DeleteNewsletterEmailResult'], ParentType, ContextType, RequireFields<MutationDeleteNewsletterEmailArgs, 'newsletterEmailId'>>;
deletePost?: Resolver<ResolversTypes['DeletePostResult'], ParentType, ContextType, RequireFields<MutationDeletePostArgs, 'id'>>;
deleteRule?: Resolver<ResolversTypes['DeleteRuleResult'], ParentType, ContextType, RequireFields<MutationDeleteRuleArgs, 'id'>>;
deleteWebhook?: Resolver<ResolversTypes['DeleteWebhookResult'], ParentType, ContextType, RequireFields<MutationDeleteWebhookArgs, 'id'>>;
editDiscoverFeed?: Resolver<ResolversTypes['EditDiscoverFeedResult'], ParentType, ContextType, RequireFields<MutationEditDiscoverFeedArgs, 'input'>>;
@ -6752,6 +6983,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
updateLabel?: Resolver<ResolversTypes['UpdateLabelResult'], ParentType, ContextType, RequireFields<MutationUpdateLabelArgs, 'input'>>;
updateNewsletterEmail?: Resolver<ResolversTypes['UpdateNewsletterEmailResult'], ParentType, ContextType, RequireFields<MutationUpdateNewsletterEmailArgs, 'input'>>;
updatePage?: Resolver<ResolversTypes['UpdatePageResult'], ParentType, ContextType, RequireFields<MutationUpdatePageArgs, 'input'>>;
updatePost?: Resolver<ResolversTypes['UpdatePostResult'], ParentType, ContextType, RequireFields<MutationUpdatePostArgs, 'input'>>;
updateSubscription?: Resolver<ResolversTypes['UpdateSubscriptionResult'], ParentType, ContextType, RequireFields<MutationUpdateSubscriptionArgs, 'input'>>;
updateUser?: Resolver<ResolversTypes['UpdateUserResult'], ParentType, ContextType, RequireFields<MutationUpdateUserArgs, 'input'>>;
updateUserProfile?: Resolver<ResolversTypes['UpdateUserProfileResult'], ParentType, ContextType, RequireFields<MutationUpdateUserProfileArgs, 'input'>>;
@ -6826,6 +7058,56 @@ export type PageInfoResolvers<ContextType = ResolverContext, ParentType extends
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type PostResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['Post'] = ResolversParentTypes['Post']> = {
author?: Resolver<ResolversTypes['User'], ParentType, ContextType>;
content?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
createdAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
highlights?: Resolver<Maybe<Array<ResolversTypes['Highlight']>>, ParentType, ContextType>;
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
libraryItems?: Resolver<Maybe<Array<ResolversTypes['Article']>>, ParentType, ContextType>;
ownedByViewer?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
thought?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
thumbnail?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
title?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
updatedAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type PostEdgeResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['PostEdge'] = ResolversParentTypes['PostEdge']> = {
cursor?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
node?: Resolver<ResolversTypes['Post'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type PostErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['PostError'] = ResolversParentTypes['PostError']> = {
errorCodes?: Resolver<Array<ResolversTypes['PostErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type PostResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['PostResult'] = ResolversParentTypes['PostResult']> = {
__resolveType: TypeResolveFn<'PostError' | 'PostSuccess', ParentType, ContextType>;
};
export type PostSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['PostSuccess'] = ResolversParentTypes['PostSuccess']> = {
post?: Resolver<ResolversTypes['Post'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type PostsErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['PostsError'] = ResolversParentTypes['PostsError']> = {
errorCodes?: Resolver<Array<ResolversTypes['PostsErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type PostsResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['PostsResult'] = ResolversParentTypes['PostsResult']> = {
__resolveType: TypeResolveFn<'PostsError' | 'PostsSuccess', ParentType, ContextType>;
};
export type PostsSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['PostsSuccess'] = ResolversParentTypes['PostsSuccess']> = {
edges?: Resolver<Array<ResolversTypes['PostEdge']>, ParentType, ContextType>;
pageInfo?: Resolver<ResolversTypes['PageInfo'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type ProfileResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['Profile'] = ResolversParentTypes['Profile']> = {
bio?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
@ -6857,6 +7139,8 @@ export type QueryResolvers<ContextType = ResolverContext, ParentType extends Res
labels?: Resolver<ResolversTypes['LabelsResult'], ParentType, ContextType>;
me?: Resolver<Maybe<ResolversTypes['User']>, ParentType, ContextType>;
newsletterEmails?: Resolver<ResolversTypes['NewsletterEmailsResult'], ParentType, ContextType>;
post?: Resolver<ResolversTypes['PostResult'], ParentType, ContextType, RequireFields<QueryPostArgs, 'id'>>;
posts?: Resolver<ResolversTypes['PostsResult'], ParentType, ContextType, RequireFields<QueryPostsArgs, 'userId'>>;
recentEmails?: Resolver<ResolversTypes['RecentEmailsResult'], ParentType, ContextType>;
recentSearches?: Resolver<ResolversTypes['RecentSearchesResult'], ParentType, ContextType>;
rules?: Resolver<ResolversTypes['RulesResult'], ParentType, ContextType, Partial<QueryRulesArgs>>;
@ -7695,6 +7979,20 @@ export type UpdatePageSuccessResolvers<ContextType = ResolverContext, ParentType
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type UpdatePostErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdatePostError'] = ResolversParentTypes['UpdatePostError']> = {
errorCodes?: Resolver<Array<ResolversTypes['UpdatePostErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type UpdatePostResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdatePostResult'] = ResolversParentTypes['UpdatePostResult']> = {
__resolveType: TypeResolveFn<'UpdatePostError' | 'UpdatePostSuccess', ParentType, ContextType>;
};
export type UpdatePostSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdatePostSuccess'] = ResolversParentTypes['UpdatePostSuccess']> = {
post?: Resolver<ResolversTypes['Post'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type UpdateReminderErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdateReminderError'] = ResolversParentTypes['UpdateReminderError']> = {
errorCodes?: Resolver<Array<ResolversTypes['UpdateReminderErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@ -7972,6 +8270,9 @@ export type Resolvers<ContextType = ResolverContext> = {
CreateNewsletterEmailError?: CreateNewsletterEmailErrorResolvers<ContextType>;
CreateNewsletterEmailResult?: CreateNewsletterEmailResultResolvers<ContextType>;
CreateNewsletterEmailSuccess?: CreateNewsletterEmailSuccessResolvers<ContextType>;
CreatePostError?: CreatePostErrorResolvers<ContextType>;
CreatePostResult?: CreatePostResultResolvers<ContextType>;
CreatePostSuccess?: CreatePostSuccessResolvers<ContextType>;
CreateReactionError?: CreateReactionErrorResolvers<ContextType>;
CreateReactionResult?: CreateReactionResultResolvers<ContextType>;
CreateReactionSuccess?: CreateReactionSuccessResolvers<ContextType>;
@ -8009,6 +8310,9 @@ export type Resolvers<ContextType = ResolverContext> = {
DeleteNewsletterEmailError?: DeleteNewsletterEmailErrorResolvers<ContextType>;
DeleteNewsletterEmailResult?: DeleteNewsletterEmailResultResolvers<ContextType>;
DeleteNewsletterEmailSuccess?: DeleteNewsletterEmailSuccessResolvers<ContextType>;
DeletePostError?: DeletePostErrorResolvers<ContextType>;
DeletePostResult?: DeletePostResultResolvers<ContextType>;
DeletePostSuccess?: DeletePostSuccessResolvers<ContextType>;
DeleteReactionError?: DeleteReactionErrorResolvers<ContextType>;
DeleteReactionResult?: DeleteReactionResultResolvers<ContextType>;
DeleteReactionSuccess?: DeleteReactionSuccessResolvers<ContextType>;
@ -8158,6 +8462,14 @@ export type Resolvers<ContextType = ResolverContext> = {
OptInFeatureSuccess?: OptInFeatureSuccessResolvers<ContextType>;
Page?: PageResolvers<ContextType>;
PageInfo?: PageInfoResolvers<ContextType>;
Post?: PostResolvers<ContextType>;
PostEdge?: PostEdgeResolvers<ContextType>;
PostError?: PostErrorResolvers<ContextType>;
PostResult?: PostResultResolvers<ContextType>;
PostSuccess?: PostSuccessResolvers<ContextType>;
PostsError?: PostsErrorResolvers<ContextType>;
PostsResult?: PostsResultResolvers<ContextType>;
PostsSuccess?: PostsSuccessResolvers<ContextType>;
Profile?: ProfileResolvers<ContextType>;
Query?: QueryResolvers<ContextType>;
Reaction?: ReactionResolvers<ContextType>;
@ -8305,6 +8617,9 @@ export type Resolvers<ContextType = ResolverContext> = {
UpdatePageError?: UpdatePageErrorResolvers<ContextType>;
UpdatePageResult?: UpdatePageResultResolvers<ContextType>;
UpdatePageSuccess?: UpdatePageSuccessResolvers<ContextType>;
UpdatePostError?: UpdatePostErrorResolvers<ContextType>;
UpdatePostResult?: UpdatePostResultResolvers<ContextType>;
UpdatePostSuccess?: UpdatePostSuccessResolvers<ContextType>;
UpdateReminderError?: UpdateReminderErrorResolvers<ContextType>;
UpdateReminderResult?: UpdateReminderResultResolvers<ContextType>;
UpdateReminderSuccess?: UpdateReminderSuccessResolvers<ContextType>;

View file

@ -455,6 +455,30 @@ type CreateNewsletterEmailSuccess {
newsletterEmail: NewsletterEmail!
}
type CreatePostError {
errorCodes: [CreatePostErrorCode!]!
}
enum CreatePostErrorCode {
BAD_REQUEST
UNAUTHORIZED
}
input CreatePostInput {
content: String!
highlightIds: [ID!]
libraryItemIds: [ID!]
thought: String
thumbnail: String
title: String!
}
union CreatePostResult = CreatePostError | CreatePostSuccess
type CreatePostSuccess {
post: Post!
}
type CreateReactionError {
errorCodes: [CreateReactionErrorCode!]!
}
@ -673,6 +697,21 @@ type DeleteNewsletterEmailSuccess {
newsletterEmail: NewsletterEmail!
}
type DeletePostError {
errorCodes: [DeletePostErrorCode!]!
}
enum DeletePostErrorCode {
BAD_REQUEST
UNAUTHORIZED
}
union DeletePostResult = DeletePostError | DeletePostSuccess
type DeletePostSuccess {
success: Boolean!
}
type DeleteReactionError {
errorCodes: [DeleteReactionErrorCode!]!
}
@ -1625,6 +1664,7 @@ type Mutation {
createHighlight(input: CreateHighlightInput!): CreateHighlightResult!
createLabel(input: CreateLabelInput!): CreateLabelResult!
createNewsletterEmail(input: CreateNewsletterEmailInput): CreateNewsletterEmailResult!
createPost(input: CreatePostInput!): CreatePostResult!
deleteAccount(userID: ID!): DeleteAccountResult!
deleteDiscoverArticle(input: DeleteDiscoverArticleInput!): DeleteDiscoverArticleResult!
deleteDiscoverFeed(input: DeleteDiscoverFeedInput!): DeleteDiscoverFeedResult!
@ -1634,6 +1674,7 @@ type Mutation {
deleteIntegration(id: ID!): DeleteIntegrationResult!
deleteLabel(id: ID!): DeleteLabelResult!
deleteNewsletterEmail(newsletterEmailId: ID!): DeleteNewsletterEmailResult!
deletePost(id: ID!): DeletePostResult!
deleteRule(id: ID!): DeleteRuleResult!
deleteWebhook(id: ID!): DeleteWebhookResult!
editDiscoverFeed(input: EditDiscoverFeedInput!): EditDiscoverFeedResult!
@ -1684,6 +1725,7 @@ type Mutation {
updateLabel(input: UpdateLabelInput!): UpdateLabelResult!
updateNewsletterEmail(input: UpdateNewsletterEmailInput!): UpdateNewsletterEmailResult!
updatePage(input: UpdatePageInput!): UpdatePageResult!
updatePost(input: UpdatePostInput!): UpdatePostResult!
updateSubscription(input: UpdateSubscriptionInput!): UpdateSubscriptionResult!
updateUser(input: UpdateUserInput!): UpdateUserResult!
updateUserProfile(input: UpdateUserProfileInput!): UpdateUserProfileResult!
@ -1800,6 +1842,56 @@ input ParseResult {
title: String!
}
type Post {
author: User!
content: String!
createdAt: Date!
highlights: [Highlight!]
id: ID!
libraryItems: [Article!]
ownedByViewer: Boolean!
thought: String
thumbnail: String
title: String!
updatedAt: Date!
}
type PostEdge {
cursor: String!
node: Post!
}
type PostError {
errorCodes: [PostErrorCode!]!
}
enum PostErrorCode {
BAD_REQUEST
UNAUTHORIZED
}
union PostResult = PostError | PostSuccess
type PostSuccess {
post: Post!
}
type PostsError {
errorCodes: [PostsErrorCode!]!
}
enum PostsErrorCode {
BAD_REQUEST
UNAUTHORIZED
}
union PostsResult = PostsError | PostsSuccess
type PostsSuccess {
edges: [PostEdge!]!
pageInfo: PageInfo!
}
input PreparedDocumentInput {
document: String!
pageInfo: PageInfoInput!
@ -1835,6 +1927,8 @@ type Query {
labels: LabelsResult!
me: User
newsletterEmails: NewsletterEmailsResult!
post(id: ID!): PostResult!
posts(after: String, first: Int, userId: ID!): PostsResult!
recentEmails: RecentEmailsResult!
recentSearches: RecentSearchesResult!
rules(enabled: Boolean): RulesResult!
@ -3068,6 +3162,31 @@ type UpdatePageSuccess {
updatedPage: Article!
}
type UpdatePostError {
errorCodes: [UpdatePostErrorCode!]!
}
enum UpdatePostErrorCode {
BAD_REQUEST
UNAUTHORIZED
}
input UpdatePostInput {
content: String
highlightIds: [ID!]
id: ID!
libraryItemIds: [ID!]
thought: String
thumbnail: String
title: String
}
union UpdatePostResult = UpdatePostError | UpdatePostSuccess
type UpdatePostSuccess {
post: Post!
}
enum UpdateReason {
CREATED
DELETED

View file

@ -150,6 +150,7 @@ import {
webhookResolver,
webhooksResolver,
} from './index'
import { postsResolver } from './posts'
import {
markEmailAsItemResolver,
recentEmailsResolver,
@ -352,6 +353,7 @@ export const functionResolvers = {
hiddenHomeSection: hiddenHomeSectionResolver,
highlights: highlightsResolver,
folderPolicies: folderPoliciesResolver,
posts: postsResolver,
},
User: {
async intercomHash(user: User) {
@ -777,6 +779,23 @@ export const functionResolvers = {
name: (recommendation: Recommendation) => recommendation.group.name,
recommendedAt: (recommendation: Recommendation) => recommendation.createdAt,
},
Post: {
author(post: { userId: string }, _: unknown, ctx: WithDataSourcesContext) {
return ctx.dataLoaders.users.load(post.userId)
},
ownedByViewer(post: { userId: string }, ctx: WithDataSourcesContext) {
return post.userId === ctx.uid
},
libraryItems(
post: { libraryItemIds: string[] },
ctx: WithDataSourcesContext
) {
return ctx.dataLoaders.libraryItems.loadMany(post.libraryItemIds)
},
highlights(post: { highlightIds: string[] }, ctx: WithDataSourcesContext) {
return ctx.dataLoaders.highlights.loadMany(post.highlightIds)
},
},
...resultResolveTypeResolver('Login'),
...resultResolveTypeResolver('LogOut'),
...resultResolveTypeResolver('GoogleSignup'),
@ -875,4 +894,5 @@ export const functionResolvers = {
...resultResolveTypeResolver('CreateFolderPolicy'),
...resultResolveTypeResolver('UpdateFolderPolicy'),
...resultResolveTypeResolver('DeleteFolderPolicy'),
...resultResolveTypeResolver('Posts'),
}

View file

@ -0,0 +1,63 @@
import { Post } from '../../entity/post'
import {
PostEdge,
PostsErrorCode,
PostsResult,
QueryPostsArgs,
ResolverFn,
} from '../../generated/graphql'
import { findPostsByUserId } from '../../services/post'
import { Merge } from '../../util'
import { ResolverContext } from '../types'
type PartialPostEdge = Merge<
PostEdge,
{
node: Post
}
>
type PartialPostsResult = Merge<
PostsResult,
{
edges?: Array<PartialPostEdge>
}
>
export const postsResolver: ResolverFn<
PartialPostsResult,
never,
ResolverContext,
QueryPostsArgs
> = async (_, { first, after, userId }, { log }) => {
const limit = first || 10
const offset = parseInt(after || '0')
if (isNaN(offset) || offset < 0 || limit > 50) {
log.error('Invalid args', { after, first })
return {
errorCodes: [PostsErrorCode.BadRequest],
}
}
const posts = await findPostsByUserId(userId, limit + 1, offset)
const hasNextPage = posts.length > limit
if (hasNextPage) {
posts.pop()
}
const endCursor = String(offset + posts.length)
const edges = posts.map((post) => ({
cursor: endCursor,
node: post,
}))
return {
edges,
pageInfo: {
startCursor: String(offset),
endCursor,
hasPreviousPage: offset > 0,
hasNextPage,
},
}
}

View file

@ -3339,6 +3339,120 @@ const schema = gql`
afterDays: Int
}
type Post {
id: ID!
title: String!
content: String!
author: User!
ownedByViewer: Boolean!
thumbnail: String
thought: String
libraryItems: [Article!]
highlights: [Highlight!]
createdAt: Date!
updatedAt: Date!
}
input CreatePostInput {
title: String!
content: String!
thumbnail: String
libraryItemIds: [ID!]
highlightIds: [ID!]
thought: String
}
union CreatePostResult = CreatePostSuccess | CreatePostError
type CreatePostSuccess {
post: Post!
}
type CreatePostError {
errorCodes: [CreatePostErrorCode!]!
}
enum CreatePostErrorCode {
UNAUTHORIZED
BAD_REQUEST
}
input UpdatePostInput {
id: ID!
title: String
content: String
thumbnail: String
libraryItemIds: [ID!]
highlightIds: [ID!]
thought: String
}
union UpdatePostResult = UpdatePostSuccess | UpdatePostError
type UpdatePostSuccess {
post: Post!
}
type UpdatePostError {
errorCodes: [UpdatePostErrorCode!]!
}
enum UpdatePostErrorCode {
UNAUTHORIZED
BAD_REQUEST
}
union DeletePostResult = DeletePostSuccess | DeletePostError
type DeletePostSuccess {
success: Boolean!
}
type DeletePostError {
errorCodes: [DeletePostErrorCode!]!
}
enum DeletePostErrorCode {
UNAUTHORIZED
BAD_REQUEST
}
union PostsResult = PostsSuccess | PostsError
type PostsSuccess {
edges: [PostEdge!]!
pageInfo: PageInfo!
}
type PostEdge {
cursor: String!
node: Post!
}
type PostsError {
errorCodes: [PostsErrorCode!]!
}
enum PostsErrorCode {
UNAUTHORIZED
BAD_REQUEST
}
union PostResult = PostSuccess | PostError
type PostSuccess {
post: Post!
}
type PostError {
errorCodes: [PostErrorCode!]!
}
enum PostErrorCode {
UNAUTHORIZED
BAD_REQUEST
}
# Mutations
type Mutation {
googleLogin(input: GoogleLoginInput!): LoginResult!
@ -3353,24 +3467,10 @@ const schema = gql`
mergeHighlight(input: MergeHighlightInput!): MergeHighlightResult!
updateHighlight(input: UpdateHighlightInput!): UpdateHighlightResult!
deleteHighlight(highlightId: ID!): DeleteHighlightResult!
# createHighlightReply(
# input: CreateHighlightReplyInput!
# ): CreateHighlightReplyResult!
# updateHighlightReply(
# input: UpdateHighlightReplyInput!
# ): UpdateHighlightReplyResult!
# deleteHighlightReply(highlightReplyId: ID!): DeleteHighlightReplyResult!
# createReaction(input: CreateReactionInput!): CreateReactionResult!
# deleteReaction(id: ID!): DeleteReactionResult!
uploadFileRequest(input: UploadFileRequestInput!): UploadFileRequestResult!
saveArticleReadingProgress(
input: SaveArticleReadingProgressInput!
): SaveArticleReadingProgressResult!
# setShareArticle(input: SetShareArticleInput!): SetShareArticleResult!
# updateSharedComment(
# input: UpdateSharedCommentInput!
# ): UpdateSharedCommentResult!
# setFollow(input: SetFollowInput!): SetFollowResult!
setBookmarkArticle(
input: SetBookmarkArticleInput!
): SetBookmarkArticleResult!
@ -3380,11 +3480,7 @@ const schema = gql`
createArticleSavingRequest(
input: CreateArticleSavingRequestInput!
): CreateArticleSavingRequestResult!
# setShareHighlight(input: SetShareHighlightInput!): SetShareHighlightResult!
reportItem(input: ReportItemInput!): ReportItemResult!
# updateLinkShareInfo(
# input: UpdateLinkShareInfoInput!
# ): UpdateLinkShareInfoResult!
setLinkArchived(input: ArchiveLinkInput!): ArchiveLinkResult!
createNewsletterEmail(
input: CreateNewsletterEmailInput
@ -3472,6 +3568,9 @@ const schema = gql`
input: UpdateFolderPolicyInput!
): UpdateFolderPolicyResult!
deleteFolderPolicy(id: ID!): DeleteFolderPolicyResult!
createPost(input: CreatePostInput!): CreatePostResult!
updatePost(input: UpdatePostInput!): UpdatePostResult!
deletePost(id: ID!): DeletePostResult!
}
# FIXME: remove sort from feedArticles after all cached tabs are closed
@ -3481,17 +3580,6 @@ const schema = gql`
me: User
user(userId: ID, username: String): UserResult!
article(username: String!, slug: String!, format: String): ArticleResult!
# sharedArticle(
# username: String!
# slug: String!
# selectedHighlightId: String
# ): SharedArticleResult!
# feedArticles(
# after: String
# first: Int
# sort: SortParams
# sharedByUser: ID
# ): FeedArticlesResult!
users: UsersResult!
validateUsername(username: String!): Boolean!
# getFollowers(userId: ID): GetFollowersResult!
@ -3547,6 +3635,8 @@ const schema = gql`
hiddenHomeSection: HiddenHomeSectionResult!
highlights(after: String, first: Int, query: String): HighlightsResult!
folderPolicies: FolderPoliciesResult!
posts(userId: ID!, after: String, first: Int): PostsResult!
post(id: ID!): PostResult!
}
schema {

View file

@ -0,0 +1,26 @@
import { Post } from '../entity/post'
import { getRepository } from '../repository'
export const findPostsByUserId = async (
userId: string,
limit: number,
offset: number
) => {
const posts = await getRepository(Post).find({
where: {
user: {
id: userId,
profile: {
private: false,
},
},
},
order: {
createdAt: 'DESC',
},
take: limit,
skip: offset,
})
return posts
}

View file

@ -19,6 +19,24 @@ CREATE TABLE omnivore.post (
CREATE INDEX post_user_id_idx ON omnivore.post(user_id);
ALTER TABLE omnivore.user_profile ALTER COLUMN private SET DEFAULT true;
GRANT SELECT, INSERT, UPDATE, DELETE ON omnivore.post TO omnivore_user;
ALTER TABLE omnivore.post ENABLE ROW LEVEL SECURITY;
CREATE POLICY read_post ON omnivore.post
FOR SELECT TO omnivore_user
USING (true);
CREATE POLICY write_post ON omnivore.post
FOR INSERT TO omnivore_user
WITH CHECK (user_id = omnivore.get_current_user_id());
CREATE POLICY update_post ON omnivore.post
FOR UPDATE TO omnivore_user
USING (user_id = omnivore.get_current_user_id());
CREATE POLICY delete_post ON omnivore.post
FOR DELETE TO omnivore_user
USING (user_id = omnivore.get_current_user_id());
COMMIT;

View file

@ -4,8 +4,6 @@
BEGIN;
ALTER TABLE omnivore.user_profile ALTER COLUMN private SET DEFAULT false;
DROP TABLE omnivore.post;
COMMIT;