Add saved filter api

This commit is contained in:
Hongbo Wu
2022-11-30 21:41:59 +08:00
parent 1d514a0530
commit 0487d8325c
9 changed files with 481 additions and 7 deletions

View File

@ -10,9 +10,9 @@ import {
} from 'typeorm'
import { User } from './user'
@Entity({ name: 'search_filters' })
@Unique('search_filter_unique_key', ['user', 'name'])
export class SearchFilter {
@Entity({ name: 'filters' })
@Unique('filter_unique_key', ['user', 'name'])
export class Filter {
@PrimaryGeneratedColumn('uuid')
id!: string

View File

@ -445,6 +445,24 @@ export type DeleteAccountSuccess = {
userID: Scalars['ID'];
};
export type DeleteFilterError = {
__typename?: 'DeleteFilterError';
errorCodes: Array<DeleteFilterErrorCode>;
};
export enum DeleteFilterErrorCode {
BadRequest = 'BAD_REQUEST',
NotFound = 'NOT_FOUND',
Unauthorized = 'UNAUTHORIZED'
}
export type DeleteFilterResult = DeleteFilterError | DeleteFilterSuccess;
export type DeleteFilterSuccess = {
__typename?: 'DeleteFilterSuccess';
filter: Filter;
};
export type DeleteHighlightError = {
__typename?: 'DeleteHighlightError';
errorCodes: Array<DeleteHighlightErrorCode>;
@ -679,6 +697,33 @@ export type FeedArticlesSuccess = {
pageInfo: PageInfo;
};
export type Filter = {
__typename?: 'Filter';
createdAt: Scalars['Date'];
description?: Maybe<Scalars['String']>;
filter: Scalars['String'];
id: Scalars['ID'];
name: Scalars['String'];
updatedAt: Scalars['Date'];
};
export type FiltersError = {
__typename?: 'FiltersError';
errorCodes: Array<FiltersErrorCode>;
};
export enum FiltersErrorCode {
BadRequest = 'BAD_REQUEST',
Unauthorized = 'UNAUTHORIZED'
}
export type FiltersResult = FiltersError | FiltersSuccess;
export type FiltersSuccess = {
__typename?: 'FiltersSuccess';
filters: Array<Filter>;
};
export type GenerateApiKeyError = {
__typename?: 'GenerateApiKeyError';
errorCodes: Array<GenerateApiKeyErrorCode>;
@ -1004,6 +1049,7 @@ export type Mutation = {
createReaction: CreateReactionResult;
createReminder: CreateReminderResult;
deleteAccount: DeleteAccountResult;
deleteFilter: DeleteFilterResult;
deleteHighlight: DeleteHighlightResult;
deleteHighlightReply: DeleteHighlightReplyResult;
deleteIntegration: DeleteIntegrationResult;
@ -1024,6 +1070,7 @@ export type Mutation = {
revokeApiKey: RevokeApiKeyResult;
saveArticleReadingProgress: SaveArticleReadingProgressResult;
saveFile: SaveResult;
saveFilter: SaveFilterResult;
savePage: SaveResult;
saveUrl: SaveResult;
setBookmarkArticle: SetBookmarkArticleResult;
@ -1098,6 +1145,11 @@ export type MutationDeleteAccountArgs = {
};
export type MutationDeleteFilterArgs = {
id: Scalars['ID'];
};
export type MutationDeleteHighlightArgs = {
highlightId: Scalars['ID'];
};
@ -1193,6 +1245,11 @@ export type MutationSaveFileArgs = {
};
export type MutationSaveFilterArgs = {
input: SaveFilterInput;
};
export type MutationSavePageArgs = {
input: SavePageInput;
};
@ -1436,6 +1493,7 @@ export type Query = {
articles: ArticlesResult;
deviceTokens: DeviceTokensResult;
feedArticles: FeedArticlesResult;
filters: FiltersResult;
getFollowers: GetFollowersResult;
getFollowing: GetFollowingResult;
getUserPersonalization: GetUserPersonalizationResult;
@ -1761,6 +1819,31 @@ export type SaveFileInput = {
url: Scalars['String'];
};
export type SaveFilterError = {
__typename?: 'SaveFilterError';
errorCodes: Array<SaveFilterErrorCode>;
};
export enum SaveFilterErrorCode {
BadRequest = 'BAD_REQUEST',
NotFound = 'NOT_FOUND',
Unauthorized = 'UNAUTHORIZED'
}
export type SaveFilterInput = {
description?: InputMaybe<Scalars['String']>;
filter: Scalars['String'];
id?: InputMaybe<Scalars['ID']>;
name: Scalars['String'];
};
export type SaveFilterResult = SaveFilterError | SaveFilterSuccess;
export type SaveFilterSuccess = {
__typename?: 'SaveFilterSuccess';
filter: Filter;
};
export type SavePageInput = {
clientRequestId: Scalars['ID'];
originalContent: Scalars['String'];
@ -2829,6 +2912,10 @@ export type ResolversTypes = {
DeleteAccountErrorCode: DeleteAccountErrorCode;
DeleteAccountResult: ResolversTypes['DeleteAccountError'] | ResolversTypes['DeleteAccountSuccess'];
DeleteAccountSuccess: ResolverTypeWrapper<DeleteAccountSuccess>;
DeleteFilterError: ResolverTypeWrapper<DeleteFilterError>;
DeleteFilterErrorCode: DeleteFilterErrorCode;
DeleteFilterResult: ResolversTypes['DeleteFilterError'] | ResolversTypes['DeleteFilterSuccess'];
DeleteFilterSuccess: ResolverTypeWrapper<DeleteFilterSuccess>;
DeleteHighlightError: ResolverTypeWrapper<DeleteHighlightError>;
DeleteHighlightErrorCode: DeleteHighlightErrorCode;
DeleteHighlightReplyError: ResolverTypeWrapper<DeleteHighlightReplyError>;
@ -2877,6 +2964,11 @@ export type ResolversTypes = {
FeedArticlesErrorCode: FeedArticlesErrorCode;
FeedArticlesResult: ResolversTypes['FeedArticlesError'] | ResolversTypes['FeedArticlesSuccess'];
FeedArticlesSuccess: ResolverTypeWrapper<FeedArticlesSuccess>;
Filter: ResolverTypeWrapper<Filter>;
FiltersError: ResolverTypeWrapper<FiltersError>;
FiltersErrorCode: FiltersErrorCode;
FiltersResult: ResolversTypes['FiltersError'] | ResolversTypes['FiltersSuccess'];
FiltersSuccess: ResolverTypeWrapper<FiltersSuccess>;
Float: ResolverTypeWrapper<Scalars['Float']>;
GenerateApiKeyError: ResolverTypeWrapper<GenerateApiKeyError>;
GenerateApiKeyErrorCode: GenerateApiKeyErrorCode;
@ -2990,6 +3082,11 @@ export type ResolversTypes = {
SaveError: ResolverTypeWrapper<SaveError>;
SaveErrorCode: SaveErrorCode;
SaveFileInput: SaveFileInput;
SaveFilterError: ResolverTypeWrapper<SaveFilterError>;
SaveFilterErrorCode: SaveFilterErrorCode;
SaveFilterInput: SaveFilterInput;
SaveFilterResult: ResolversTypes['SaveFilterError'] | ResolversTypes['SaveFilterSuccess'];
SaveFilterSuccess: ResolverTypeWrapper<SaveFilterSuccess>;
SavePageInput: SavePageInput;
SaveResult: ResolversTypes['SaveError'] | ResolversTypes['SaveSuccess'];
SaveSuccess: ResolverTypeWrapper<SaveSuccess>;
@ -3225,6 +3322,9 @@ export type ResolversParentTypes = {
DeleteAccountError: DeleteAccountError;
DeleteAccountResult: ResolversParentTypes['DeleteAccountError'] | ResolversParentTypes['DeleteAccountSuccess'];
DeleteAccountSuccess: DeleteAccountSuccess;
DeleteFilterError: DeleteFilterError;
DeleteFilterResult: ResolversParentTypes['DeleteFilterError'] | ResolversParentTypes['DeleteFilterSuccess'];
DeleteFilterSuccess: DeleteFilterSuccess;
DeleteHighlightError: DeleteHighlightError;
DeleteHighlightReplyError: DeleteHighlightReplyError;
DeleteHighlightReplyResult: ResolversParentTypes['DeleteHighlightReplyError'] | ResolversParentTypes['DeleteHighlightReplySuccess'];
@ -3262,6 +3362,10 @@ export type ResolversParentTypes = {
FeedArticlesError: FeedArticlesError;
FeedArticlesResult: ResolversParentTypes['FeedArticlesError'] | ResolversParentTypes['FeedArticlesSuccess'];
FeedArticlesSuccess: FeedArticlesSuccess;
Filter: Filter;
FiltersError: FiltersError;
FiltersResult: ResolversParentTypes['FiltersError'] | ResolversParentTypes['FiltersSuccess'];
FiltersSuccess: FiltersSuccess;
Float: Scalars['Float'];
GenerateApiKeyError: GenerateApiKeyError;
GenerateApiKeyInput: GenerateApiKeyInput;
@ -3352,6 +3456,10 @@ export type ResolversParentTypes = {
SaveArticleReadingProgressSuccess: SaveArticleReadingProgressSuccess;
SaveError: SaveError;
SaveFileInput: SaveFileInput;
SaveFilterError: SaveFilterError;
SaveFilterInput: SaveFilterInput;
SaveFilterResult: ResolversParentTypes['SaveFilterError'] | ResolversParentTypes['SaveFilterSuccess'];
SaveFilterSuccess: SaveFilterSuccess;
SavePageInput: SavePageInput;
SaveResult: ResolversParentTypes['SaveError'] | ResolversParentTypes['SaveSuccess'];
SaveSuccess: SaveSuccess;
@ -3784,6 +3892,20 @@ export type DeleteAccountSuccessResolvers<ContextType = ResolverContext, ParentT
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type DeleteFilterErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeleteFilterError'] = ResolversParentTypes['DeleteFilterError']> = {
errorCodes?: Resolver<Array<ResolversTypes['DeleteFilterErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type DeleteFilterResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeleteFilterResult'] = ResolversParentTypes['DeleteFilterResult']> = {
__resolveType: TypeResolveFn<'DeleteFilterError' | 'DeleteFilterSuccess', ParentType, ContextType>;
};
export type DeleteFilterSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeleteFilterSuccess'] = ResolversParentTypes['DeleteFilterSuccess']> = {
filter?: Resolver<ResolversTypes['Filter'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type DeleteHighlightErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeleteHighlightError'] = ResolversParentTypes['DeleteHighlightError']> = {
errorCodes?: Resolver<Array<ResolversTypes['DeleteHighlightErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@ -3977,6 +4099,30 @@ export type FeedArticlesSuccessResolvers<ContextType = ResolverContext, ParentTy
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type FilterResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['Filter'] = ResolversParentTypes['Filter']> = {
createdAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
description?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>;
filter?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
name?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
updatedAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type FiltersErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['FiltersError'] = ResolversParentTypes['FiltersError']> = {
errorCodes?: Resolver<Array<ResolversTypes['FiltersErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type FiltersResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['FiltersResult'] = ResolversParentTypes['FiltersResult']> = {
__resolveType: TypeResolveFn<'FiltersError' | 'FiltersSuccess', ParentType, ContextType>;
};
export type FiltersSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['FiltersSuccess'] = ResolversParentTypes['FiltersSuccess']> = {
filters?: Resolver<Array<ResolversTypes['Filter']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type GenerateApiKeyErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['GenerateApiKeyError'] = ResolversParentTypes['GenerateApiKeyError']> = {
errorCodes?: Resolver<Array<ResolversTypes['GenerateApiKeyErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
@ -4223,6 +4369,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
createReaction?: Resolver<ResolversTypes['CreateReactionResult'], ParentType, ContextType, RequireFields<MutationCreateReactionArgs, 'input'>>;
createReminder?: Resolver<ResolversTypes['CreateReminderResult'], ParentType, ContextType, RequireFields<MutationCreateReminderArgs, 'input'>>;
deleteAccount?: Resolver<ResolversTypes['DeleteAccountResult'], ParentType, ContextType, RequireFields<MutationDeleteAccountArgs, 'userID'>>;
deleteFilter?: Resolver<ResolversTypes['DeleteFilterResult'], ParentType, ContextType, RequireFields<MutationDeleteFilterArgs, 'id'>>;
deleteHighlight?: Resolver<ResolversTypes['DeleteHighlightResult'], ParentType, ContextType, RequireFields<MutationDeleteHighlightArgs, 'highlightId'>>;
deleteHighlightReply?: Resolver<ResolversTypes['DeleteHighlightReplyResult'], ParentType, ContextType, RequireFields<MutationDeleteHighlightReplyArgs, 'highlightReplyId'>>;
deleteIntegration?: Resolver<ResolversTypes['DeleteIntegrationResult'], ParentType, ContextType, RequireFields<MutationDeleteIntegrationArgs, 'id'>>;
@ -4243,6 +4390,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
revokeApiKey?: Resolver<ResolversTypes['RevokeApiKeyResult'], ParentType, ContextType, RequireFields<MutationRevokeApiKeyArgs, 'id'>>;
saveArticleReadingProgress?: Resolver<ResolversTypes['SaveArticleReadingProgressResult'], ParentType, ContextType, RequireFields<MutationSaveArticleReadingProgressArgs, 'input'>>;
saveFile?: Resolver<ResolversTypes['SaveResult'], ParentType, ContextType, RequireFields<MutationSaveFileArgs, 'input'>>;
saveFilter?: Resolver<ResolversTypes['SaveFilterResult'], ParentType, ContextType, RequireFields<MutationSaveFilterArgs, 'input'>>;
savePage?: Resolver<ResolversTypes['SaveResult'], ParentType, ContextType, RequireFields<MutationSavePageArgs, 'input'>>;
saveUrl?: Resolver<ResolversTypes['SaveResult'], ParentType, ContextType, RequireFields<MutationSaveUrlArgs, 'input'>>;
setBookmarkArticle?: Resolver<ResolversTypes['SetBookmarkArticleResult'], ParentType, ContextType, RequireFields<MutationSetBookmarkArticleArgs, 'input'>>;
@ -4349,6 +4497,7 @@ export type QueryResolvers<ContextType = ResolverContext, ParentType extends Res
articles?: Resolver<ResolversTypes['ArticlesResult'], ParentType, ContextType, Partial<QueryArticlesArgs>>;
deviceTokens?: Resolver<ResolversTypes['DeviceTokensResult'], ParentType, ContextType>;
feedArticles?: Resolver<ResolversTypes['FeedArticlesResult'], ParentType, ContextType, Partial<QueryFeedArticlesArgs>>;
filters?: Resolver<ResolversTypes['FiltersResult'], ParentType, ContextType>;
getFollowers?: Resolver<ResolversTypes['GetFollowersResult'], ParentType, ContextType, Partial<QueryGetFollowersArgs>>;
getFollowing?: Resolver<ResolversTypes['GetFollowingResult'], ParentType, ContextType, Partial<QueryGetFollowingArgs>>;
getUserPersonalization?: Resolver<ResolversTypes['GetUserPersonalizationResult'], ParentType, ContextType>;
@ -4503,6 +4652,20 @@ export type SaveErrorResolvers<ContextType = ResolverContext, ParentType extends
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type SaveFilterErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SaveFilterError'] = ResolversParentTypes['SaveFilterError']> = {
errorCodes?: Resolver<Array<ResolversTypes['SaveFilterErrorCode']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type SaveFilterResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SaveFilterResult'] = ResolversParentTypes['SaveFilterResult']> = {
__resolveType: TypeResolveFn<'SaveFilterError' | 'SaveFilterSuccess', ParentType, ContextType>;
};
export type SaveFilterSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SaveFilterSuccess'] = ResolversParentTypes['SaveFilterSuccess']> = {
filter?: Resolver<ResolversTypes['Filter'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};
export type SaveResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SaveResult'] = ResolversParentTypes['SaveResult']> = {
__resolveType: TypeResolveFn<'SaveError' | 'SaveSuccess', ParentType, ContextType>;
};
@ -5144,6 +5307,9 @@ export type Resolvers<ContextType = ResolverContext> = {
DeleteAccountError?: DeleteAccountErrorResolvers<ContextType>;
DeleteAccountResult?: DeleteAccountResultResolvers<ContextType>;
DeleteAccountSuccess?: DeleteAccountSuccessResolvers<ContextType>;
DeleteFilterError?: DeleteFilterErrorResolvers<ContextType>;
DeleteFilterResult?: DeleteFilterResultResolvers<ContextType>;
DeleteFilterSuccess?: DeleteFilterSuccessResolvers<ContextType>;
DeleteHighlightError?: DeleteHighlightErrorResolvers<ContextType>;
DeleteHighlightReplyError?: DeleteHighlightReplyErrorResolvers<ContextType>;
DeleteHighlightReplyResult?: DeleteHighlightReplyResultResolvers<ContextType>;
@ -5181,6 +5347,10 @@ export type Resolvers<ContextType = ResolverContext> = {
FeedArticlesError?: FeedArticlesErrorResolvers<ContextType>;
FeedArticlesResult?: FeedArticlesResultResolvers<ContextType>;
FeedArticlesSuccess?: FeedArticlesSuccessResolvers<ContextType>;
Filter?: FilterResolvers<ContextType>;
FiltersError?: FiltersErrorResolvers<ContextType>;
FiltersResult?: FiltersResultResolvers<ContextType>;
FiltersSuccess?: FiltersSuccessResolvers<ContextType>;
GenerateApiKeyError?: GenerateApiKeyErrorResolvers<ContextType>;
GenerateApiKeyResult?: GenerateApiKeyResultResolvers<ContextType>;
GenerateApiKeySuccess?: GenerateApiKeySuccessResolvers<ContextType>;
@ -5256,6 +5426,9 @@ export type Resolvers<ContextType = ResolverContext> = {
SaveArticleReadingProgressResult?: SaveArticleReadingProgressResultResolvers<ContextType>;
SaveArticleReadingProgressSuccess?: SaveArticleReadingProgressSuccessResolvers<ContextType>;
SaveError?: SaveErrorResolvers<ContextType>;
SaveFilterError?: SaveFilterErrorResolvers<ContextType>;
SaveFilterResult?: SaveFilterResultResolvers<ContextType>;
SaveFilterSuccess?: SaveFilterSuccessResolvers<ContextType>;
SaveResult?: SaveResultResolvers<ContextType>;
SaveSuccess?: SaveSuccessResolvers<ContextType>;
SearchError?: SearchErrorResolvers<ContextType>;

View File

@ -390,6 +390,22 @@ type DeleteAccountSuccess {
userID: ID!
}
type DeleteFilterError {
errorCodes: [DeleteFilterErrorCode!]!
}
enum DeleteFilterErrorCode {
BAD_REQUEST
NOT_FOUND
UNAUTHORIZED
}
union DeleteFilterResult = DeleteFilterError | DeleteFilterSuccess
type DeleteFilterSuccess {
filter: Filter!
}
type DeleteHighlightError {
errorCodes: [DeleteHighlightErrorCode!]!
}
@ -598,6 +614,30 @@ type FeedArticlesSuccess {
pageInfo: PageInfo!
}
type Filter {
createdAt: Date!
description: String
filter: String!
id: ID!
name: String!
updatedAt: Date!
}
type FiltersError {
errorCodes: [FiltersErrorCode!]!
}
enum FiltersErrorCode {
BAD_REQUEST
UNAUTHORIZED
}
union FiltersResult = FiltersError | FiltersSuccess
type FiltersSuccess {
filters: [Filter!]!
}
type GenerateApiKeyError {
errorCodes: [GenerateApiKeyErrorCode!]!
}
@ -893,6 +933,7 @@ type Mutation {
createReaction(input: CreateReactionInput!): CreateReactionResult!
createReminder(input: CreateReminderInput!): CreateReminderResult!
deleteAccount(userID: ID!): DeleteAccountResult!
deleteFilter(id: ID!): DeleteFilterResult!
deleteHighlight(highlightId: ID!): DeleteHighlightResult!
deleteHighlightReply(highlightReplyId: ID!): DeleteHighlightReplyResult!
deleteIntegration(id: ID!): DeleteIntegrationResult!
@ -913,6 +954,7 @@ type Mutation {
revokeApiKey(id: ID!): RevokeApiKeyResult!
saveArticleReadingProgress(input: SaveArticleReadingProgressInput!): SaveArticleReadingProgressResult!
saveFile(input: SaveFileInput!): SaveResult!
saveFilter(input: SaveFilterInput!): SaveFilterResult!
savePage(input: SavePageInput!): SaveResult!
saveUrl(input: SaveUrlInput!): SaveResult!
setBookmarkArticle(input: SetBookmarkArticleInput!): SetBookmarkArticleResult!
@ -1046,6 +1088,7 @@ type Query {
articles(after: String, first: Int, includePending: Boolean, query: String, sharedOnly: Boolean, sort: SortParams): ArticlesResult!
deviceTokens: DeviceTokensResult!
feedArticles(after: String, first: Int, sharedByUser: ID, sort: SortParams): FeedArticlesResult!
filters: FiltersResult!
getFollowers(userId: ID): GetFollowersResult!
getFollowing(userId: ID): GetFollowingResult!
getUserPersonalization: GetUserPersonalizationResult!
@ -1255,6 +1298,29 @@ input SaveFileInput {
url: String!
}
type SaveFilterError {
errorCodes: [SaveFilterErrorCode!]!
}
enum SaveFilterErrorCode {
BAD_REQUEST
NOT_FOUND
UNAUTHORIZED
}
input SaveFilterInput {
description: String
filter: String!
id: ID
name: String!
}
union SaveFilterResult = SaveFilterError | SaveFilterSuccess
type SaveFilterSuccess {
filter: Filter!
}
input SavePageInput {
clientRequestId: ID!
originalContent: String!

View File

@ -0,0 +1,159 @@
import { authorized } from '../../utils/helpers'
import {
DeleteFilterError,
DeleteFilterErrorCode,
DeleteFilterSuccess,
FiltersError,
FiltersErrorCode,
FiltersSuccess,
MutationDeleteFilterArgs,
MutationSaveFilterArgs,
SaveFilterError,
SaveFilterErrorCode,
SaveFilterSuccess,
} from '../../generated/graphql'
import { Filter } from '../../entity/filter'
import { getRepository } from '../../entity/utils'
import { User } from '../../entity/user'
export const saveFilterResolver = authorized<
SaveFilterSuccess,
SaveFilterError,
MutationSaveFilterArgs
>(async (_, { input }, { claims, log }) => {
log.info('Saving filters', {
input,
labels: {
source: 'resolver',
resolver: 'saveFilterResolver',
uid: claims.uid,
},
})
try {
const user = await getRepository(User).findOneBy({ id: claims.uid })
if (!user) {
return {
errorCodes: [SaveFilterErrorCode.Unauthorized],
}
}
const filter = await getRepository(Filter).save({
...input,
id: input.id ?? undefined,
user: { id: claims.uid },
})
return {
filter,
}
} catch (error) {
log.error('Error saving filters', {
error,
labels: {
source: 'resolver',
resolver: 'saveFilterResolver',
uid: claims.uid,
},
})
return {
errorCodes: [SaveFilterErrorCode.BadRequest],
}
}
})
export const deleteFilterResolver = authorized<
DeleteFilterSuccess,
DeleteFilterError,
MutationDeleteFilterArgs
>(async (_, { id }, { claims, log }) => {
log.info('Deleting filters', {
id,
labels: {
source: 'resolver',
resolver: 'deleteFilterResolver',
uid: claims.uid,
},
})
try {
const user = await getRepository(User).findOneBy({ id: claims.uid })
if (!user) {
return {
errorCodes: [DeleteFilterErrorCode.Unauthorized],
}
}
const filter = await getRepository(Filter).findOneBy({
id,
user: { id: claims.uid },
})
if (!filter) {
return {
errorCodes: [DeleteFilterErrorCode.NotFound],
}
}
await getRepository(Filter).delete({ id })
return {
filter,
}
} catch (error) {
log.error('Error deleting filters', {
error,
labels: {
source: 'resolver',
resolver: 'deleteFilterResolver',
uid: claims.uid,
},
})
return {
errorCodes: [DeleteFilterErrorCode.BadRequest],
}
}
})
export const filtersResolver = authorized<FiltersSuccess, FiltersError>(
async (_, __, { claims, log }) => {
log.info('Getting filters', {
labels: {
source: 'resolver',
resolver: 'filtersResolver',
uid: claims.uid,
},
})
try {
const user = await getRepository(User).findOneBy({ id: claims.uid })
if (!user) {
return {
errorCodes: [FiltersErrorCode.Unauthorized],
}
}
const filters = await getRepository(Filter).findBy({
user: { id: claims.uid },
})
return {
filters,
}
} catch (error) {
log.error('Error getting filters', {
error,
labels: {
source: 'resolver',
resolver: 'filtersResolver',
uid: claims.uid,
},
})
return {
errorCodes: [FiltersErrorCode.BadRequest],
}
}
}
)

View File

@ -31,6 +31,7 @@ import {
createNewsletterEmailResolver,
createReminderResolver,
deleteAccountResolver,
deleteFilterResolver,
deleteHighlightResolver,
deleteIntegrationResolver,
deleteLabelResolver,
@ -39,6 +40,7 @@ import {
deleteRuleResolver,
deleteWebhookResolver,
deviceTokensResolver,
filtersResolver,
generateApiKeyResolver,
getAllUsersResolver,
getArticleResolver,
@ -64,6 +66,7 @@ import {
rulesResolver,
saveArticleReadingProgressResolver,
saveFileResolver,
saveFilterResolver,
savePageResolver,
saveUrlResolver,
searchResolver,
@ -179,6 +182,8 @@ export const functionResolvers = {
optInFeature: optInFeatureResolver,
setRule: setRuleResolver,
deleteRule: deleteRuleResolver,
saveFilter: saveFilterResolver,
deleteFilter: deleteFilterResolver,
},
Query: {
me: getMeUserResolver,
@ -208,6 +213,7 @@ export const functionResolvers = {
recentSearches: recentSearchesResolver,
rules: rulesResolver,
deviceTokens: deviceTokensResolver,
filters: filtersResolver,
},
User: {
async sharedArticles(
@ -622,4 +628,7 @@ export const functionResolvers = {
...resultResolveTypeResolver('Rules'),
...resultResolveTypeResolver('DeviceTokens'),
...resultResolveTypeResolver('DeleteRule'),
...resultResolveTypeResolver('SaveFilter'),
...resultResolveTypeResolver('Filters'),
...resultResolveTypeResolver('DeleteFilter'),
}

View File

@ -22,3 +22,4 @@ export * from './webhooks'
export * from './api_key'
export * from './integrations'
export * from './rules'
export * from './filters'

View File

@ -2051,6 +2051,69 @@ const schema = gql`
BAD_REQUEST
}
input SaveFilterInput {
id: ID
name: String!
filter: String!
description: String
}
union SaveFilterResult = SaveFilterSuccess | SaveFilterError
type SaveFilterSuccess {
filter: Filter!
}
type Filter {
id: ID!
name: String!
filter: String!
description: String
createdAt: Date!
updatedAt: Date!
}
type SaveFilterError {
errorCodes: [SaveFilterErrorCode!]!
}
enum SaveFilterErrorCode {
UNAUTHORIZED
BAD_REQUEST
NOT_FOUND
}
union FiltersResult = FiltersSuccess | FiltersError
type FiltersSuccess {
filters: [Filter!]!
}
type FiltersError {
errorCodes: [FiltersErrorCode!]!
}
enum FiltersErrorCode {
UNAUTHORIZED
BAD_REQUEST
}
union DeleteFilterResult = DeleteFilterSuccess | DeleteFilterError
type DeleteFilterSuccess {
filter: Filter!
}
type DeleteFilterError {
errorCodes: [DeleteFilterErrorCode!]!
}
enum DeleteFilterErrorCode {
UNAUTHORIZED
BAD_REQUEST
NOT_FOUND
}
# Mutations
type Mutation {
googleLogin(input: GoogleLoginInput!): LoginResult!
@ -2125,6 +2188,8 @@ const schema = gql`
optInFeature(input: OptInFeatureInput!): OptInFeatureResult!
setRule(input: SetRuleInput!): SetRuleResult!
deleteRule(id: ID!): DeleteRuleResult!
saveFilter(input: SaveFilterInput!): SaveFilterResult!
deleteFilter(id: ID!): DeleteFilterResult!
}
# FIXME: remove sort from feedArticles after all cached tabs are closed
@ -2179,6 +2244,7 @@ const schema = gql`
recentSearches: RecentSearchesResult!
rules(enabled: Boolean): RulesResult!
deviceTokens: DeviceTokensResult!
filters: FiltersResult!
}
`

View File

@ -4,7 +4,7 @@
BEGIN;
CREATE TABLE omnivore.search_filters (
CREATE TABLE omnivore.filters (
id uuid PRIMARY KEY DEFAULT uuid_generate_v1mc(),
user_id uuid NOT NULL REFERENCES omnivore.user ON DELETE CASCADE,
name character varying(255) NOT NULL,
@ -15,9 +15,9 @@ CREATE TABLE omnivore.search_filters (
UNIQUE (user_id, name)
);
CREATE TRIGGER search_filters_modtime BEFORE UPDATE ON omnivore.search_filters
CREATE TRIGGER filters_modtime BEFORE UPDATE ON omnivore.filters
FOR EACH ROW EXECUTE PROCEDURE update_updated_at_column();
GRANT SELECT, INSERT, UPDATE, DELETE ON omnivore.search_filters TO omnivore_user;
GRANT SELECT, INSERT, UPDATE, DELETE ON omnivore.filters TO omnivore_user;
COMMIT;

View File

@ -4,6 +4,6 @@
BEGIN;
DROP TABLE IF EXISTS omnivore.search_filters;
DROP TABLE IF EXISTS omnivore.filters;
COMMIT;