feat: update newsletter email api
This commit is contained in:
@ -1391,6 +1391,7 @@ export type Mutation = {
|
||||
updateFilter: UpdateFilterResult;
|
||||
updateHighlight: UpdateHighlightResult;
|
||||
updateLabel: UpdateLabelResult;
|
||||
updateNewsletterEmail: UpdateNewsletterEmailResult;
|
||||
updatePage: UpdatePageResult;
|
||||
updateSubscription: UpdateSubscriptionResult;
|
||||
updateUser: UpdateUserResult;
|
||||
@ -1677,6 +1678,11 @@ export type MutationUpdateLabelArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateNewsletterEmailArgs = {
|
||||
input: UpdateNewsletterEmailInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdatePageArgs = {
|
||||
input: UpdatePageInput;
|
||||
};
|
||||
@ -3059,6 +3065,30 @@ export type UpdateLinkShareInfoSuccess = {
|
||||
message: Scalars['String'];
|
||||
};
|
||||
|
||||
export type UpdateNewsletterEmailError = {
|
||||
__typename?: 'UpdateNewsletterEmailError';
|
||||
errorCodes: Array<UpdateNewsletterEmailErrorCode>;
|
||||
};
|
||||
|
||||
export enum UpdateNewsletterEmailErrorCode {
|
||||
BadRequest = 'BAD_REQUEST',
|
||||
Unauthorized = 'UNAUTHORIZED'
|
||||
}
|
||||
|
||||
export type UpdateNewsletterEmailInput = {
|
||||
description?: InputMaybe<Scalars['String']>;
|
||||
folder?: InputMaybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type UpdateNewsletterEmailResult = UpdateNewsletterEmailError | UpdateNewsletterEmailSuccess;
|
||||
|
||||
export type UpdateNewsletterEmailSuccess = {
|
||||
__typename?: 'UpdateNewsletterEmailSuccess';
|
||||
newsletterEmail: NewsletterEmail;
|
||||
};
|
||||
|
||||
export type UpdatePageError = {
|
||||
__typename?: 'UpdatePageError';
|
||||
errorCodes: Array<UpdatePageErrorCode>;
|
||||
@ -3962,6 +3992,11 @@ export type ResolversTypes = {
|
||||
UpdateLinkShareInfoInput: UpdateLinkShareInfoInput;
|
||||
UpdateLinkShareInfoResult: ResolversTypes['UpdateLinkShareInfoError'] | ResolversTypes['UpdateLinkShareInfoSuccess'];
|
||||
UpdateLinkShareInfoSuccess: ResolverTypeWrapper<UpdateLinkShareInfoSuccess>;
|
||||
UpdateNewsletterEmailError: ResolverTypeWrapper<UpdateNewsletterEmailError>;
|
||||
UpdateNewsletterEmailErrorCode: UpdateNewsletterEmailErrorCode;
|
||||
UpdateNewsletterEmailInput: UpdateNewsletterEmailInput;
|
||||
UpdateNewsletterEmailResult: ResolversTypes['UpdateNewsletterEmailError'] | ResolversTypes['UpdateNewsletterEmailSuccess'];
|
||||
UpdateNewsletterEmailSuccess: ResolverTypeWrapper<UpdateNewsletterEmailSuccess>;
|
||||
UpdatePageError: ResolverTypeWrapper<UpdatePageError>;
|
||||
UpdatePageErrorCode: UpdatePageErrorCode;
|
||||
UpdatePageInput: UpdatePageInput;
|
||||
@ -4392,6 +4427,10 @@ export type ResolversParentTypes = {
|
||||
UpdateLinkShareInfoInput: UpdateLinkShareInfoInput;
|
||||
UpdateLinkShareInfoResult: ResolversParentTypes['UpdateLinkShareInfoError'] | ResolversParentTypes['UpdateLinkShareInfoSuccess'];
|
||||
UpdateLinkShareInfoSuccess: UpdateLinkShareInfoSuccess;
|
||||
UpdateNewsletterEmailError: UpdateNewsletterEmailError;
|
||||
UpdateNewsletterEmailInput: UpdateNewsletterEmailInput;
|
||||
UpdateNewsletterEmailResult: ResolversParentTypes['UpdateNewsletterEmailError'] | ResolversParentTypes['UpdateNewsletterEmailSuccess'];
|
||||
UpdateNewsletterEmailSuccess: UpdateNewsletterEmailSuccess;
|
||||
UpdatePageError: UpdatePageError;
|
||||
UpdatePageInput: UpdatePageInput;
|
||||
UpdatePageResult: ResolversParentTypes['UpdatePageError'] | ResolversParentTypes['UpdatePageSuccess'];
|
||||
@ -5460,6 +5499,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
|
||||
updateFilter?: Resolver<ResolversTypes['UpdateFilterResult'], ParentType, ContextType, RequireFields<MutationUpdateFilterArgs, 'input'>>;
|
||||
updateHighlight?: Resolver<ResolversTypes['UpdateHighlightResult'], ParentType, ContextType, RequireFields<MutationUpdateHighlightArgs, 'input'>>;
|
||||
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'>>;
|
||||
updateSubscription?: Resolver<ResolversTypes['UpdateSubscriptionResult'], ParentType, ContextType, RequireFields<MutationUpdateSubscriptionArgs, 'input'>>;
|
||||
updateUser?: Resolver<ResolversTypes['UpdateUserResult'], ParentType, ContextType, RequireFields<MutationUpdateUserArgs, 'input'>>;
|
||||
@ -6267,6 +6307,20 @@ export type UpdateLinkShareInfoSuccessResolvers<ContextType = ResolverContext, P
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type UpdateNewsletterEmailErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdateNewsletterEmailError'] = ResolversParentTypes['UpdateNewsletterEmailError']> = {
|
||||
errorCodes?: Resolver<Array<ResolversTypes['UpdateNewsletterEmailErrorCode']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type UpdateNewsletterEmailResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdateNewsletterEmailResult'] = ResolversParentTypes['UpdateNewsletterEmailResult']> = {
|
||||
__resolveType: TypeResolveFn<'UpdateNewsletterEmailError' | 'UpdateNewsletterEmailSuccess', ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type UpdateNewsletterEmailSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdateNewsletterEmailSuccess'] = ResolversParentTypes['UpdateNewsletterEmailSuccess']> = {
|
||||
newsletterEmail?: Resolver<ResolversTypes['NewsletterEmail'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type UpdatePageErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['UpdatePageError'] = ResolversParentTypes['UpdatePageError']> = {
|
||||
errorCodes?: Resolver<Array<ResolversTypes['UpdatePageErrorCode']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
@ -6807,6 +6861,9 @@ export type Resolvers<ContextType = ResolverContext> = {
|
||||
UpdateLinkShareInfoError?: UpdateLinkShareInfoErrorResolvers<ContextType>;
|
||||
UpdateLinkShareInfoResult?: UpdateLinkShareInfoResultResolvers<ContextType>;
|
||||
UpdateLinkShareInfoSuccess?: UpdateLinkShareInfoSuccessResolvers<ContextType>;
|
||||
UpdateNewsletterEmailError?: UpdateNewsletterEmailErrorResolvers<ContextType>;
|
||||
UpdateNewsletterEmailResult?: UpdateNewsletterEmailResultResolvers<ContextType>;
|
||||
UpdateNewsletterEmailSuccess?: UpdateNewsletterEmailSuccessResolvers<ContextType>;
|
||||
UpdatePageError?: UpdatePageErrorResolvers<ContextType>;
|
||||
UpdatePageResult?: UpdatePageResultResolvers<ContextType>;
|
||||
UpdatePageSuccess?: UpdatePageSuccessResolvers<ContextType>;
|
||||
|
||||
@ -1252,6 +1252,7 @@ type Mutation {
|
||||
updateFilter(input: UpdateFilterInput!): UpdateFilterResult!
|
||||
updateHighlight(input: UpdateHighlightInput!): UpdateHighlightResult!
|
||||
updateLabel(input: UpdateLabelInput!): UpdateLabelResult!
|
||||
updateNewsletterEmail(input: UpdateNewsletterEmailInput!): UpdateNewsletterEmailResult!
|
||||
updatePage(input: UpdatePageInput!): UpdatePageResult!
|
||||
updateSubscription(input: UpdateSubscriptionInput!): UpdateSubscriptionResult!
|
||||
updateUser(input: UpdateUserInput!): UpdateUserResult!
|
||||
@ -2442,6 +2443,28 @@ type UpdateLinkShareInfoSuccess {
|
||||
message: String!
|
||||
}
|
||||
|
||||
type UpdateNewsletterEmailError {
|
||||
errorCodes: [UpdateNewsletterEmailErrorCode!]!
|
||||
}
|
||||
|
||||
enum UpdateNewsletterEmailErrorCode {
|
||||
BAD_REQUEST
|
||||
UNAUTHORIZED
|
||||
}
|
||||
|
||||
input UpdateNewsletterEmailInput {
|
||||
description: String
|
||||
folder: String
|
||||
id: ID!
|
||||
name: String
|
||||
}
|
||||
|
||||
union UpdateNewsletterEmailResult = UpdateNewsletterEmailError | UpdateNewsletterEmailSuccess
|
||||
|
||||
type UpdateNewsletterEmailSuccess {
|
||||
newsletterEmail: NewsletterEmail!
|
||||
}
|
||||
|
||||
type UpdatePageError {
|
||||
errorCodes: [UpdatePageErrorCode!]!
|
||||
}
|
||||
|
||||
@ -131,6 +131,7 @@ import {
|
||||
validateUsernameResolver,
|
||||
webhookResolver,
|
||||
webhooksResolver,
|
||||
updateNewsletterEmailResolver,
|
||||
} from './index'
|
||||
import { markEmailAsItemResolver, recentEmailsResolver } from './recent_emails'
|
||||
import { recentSearchesResolver } from './recent_searches'
|
||||
@ -226,6 +227,7 @@ export const functionResolvers = {
|
||||
updateFilter: updateFilterResolver,
|
||||
updateEmail: updateEmailResolver,
|
||||
moveToFolder: moveToFolderResolver,
|
||||
updateNewsletterEmail: updateNewsletterEmailResolver,
|
||||
},
|
||||
Query: {
|
||||
me: getMeUserResolver,
|
||||
@ -445,8 +447,12 @@ export const functionResolvers = {
|
||||
subscription.icon && createImageProxyUrl(subscription.icon, 128, 128)
|
||||
)
|
||||
},
|
||||
folder(subscription: { folder?: string | null }) {
|
||||
return subscription.folder || DEFAULT_SUBSCRIPTION_FOLDER
|
||||
folder(subscription: Subscription) {
|
||||
return (
|
||||
subscription.folder ||
|
||||
subscription.newsletterEmail?.folder ||
|
||||
DEFAULT_SUBSCRIPTION_FOLDER
|
||||
)
|
||||
},
|
||||
},
|
||||
NewsletterEmail: {
|
||||
@ -550,4 +556,5 @@ export const functionResolvers = {
|
||||
...resultResolveTypeResolver('UpdateEmail'),
|
||||
...resultResolveTypeResolver('ScanFeeds'),
|
||||
...resultResolveTypeResolver('MoveToFolder'),
|
||||
...resultResolveTypeResolver('UpdateNewsletterEmail'),
|
||||
}
|
||||
|
||||
@ -12,15 +12,20 @@ import {
|
||||
DeleteNewsletterEmailSuccess,
|
||||
MutationCreateNewsletterEmailArgs,
|
||||
MutationDeleteNewsletterEmailArgs,
|
||||
MutationUpdateNewsletterEmailArgs,
|
||||
NewsletterEmailsError,
|
||||
NewsletterEmailsErrorCode,
|
||||
NewsletterEmailsSuccess,
|
||||
UpdateNewsletterEmailError,
|
||||
UpdateNewsletterEmailErrorCode,
|
||||
UpdateNewsletterEmailSuccess,
|
||||
} from '../../generated/graphql'
|
||||
import { getRepository } from '../../repository'
|
||||
import {
|
||||
createNewsletterEmail,
|
||||
deleteNewsletterEmail,
|
||||
getNewsletterEmails,
|
||||
updateNewsletterEmail,
|
||||
} from '../../services/newsletters'
|
||||
import { unsubscribeAll } from '../../services/subscriptions'
|
||||
import { Merge } from '../../util'
|
||||
@ -143,3 +148,39 @@ export const deleteNewsletterEmailResolver = authorized<
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export type UpdateNewsletterEmailSuccessPartial = Merge<
|
||||
UpdateNewsletterEmailSuccess,
|
||||
{ newsletterEmail: NewsletterEmail }
|
||||
>
|
||||
export const updateNewsletterEmailResolver = authorized<
|
||||
UpdateNewsletterEmailSuccessPartial,
|
||||
UpdateNewsletterEmailError,
|
||||
MutationUpdateNewsletterEmailArgs
|
||||
>(async (_parent, { input }, { uid, log }) => {
|
||||
analytics.track({
|
||||
userId: uid,
|
||||
event: 'newsletter_email_updated',
|
||||
properties: {
|
||||
env: env.server.apiEnv,
|
||||
...input,
|
||||
},
|
||||
})
|
||||
|
||||
const updatedNewsletterEmail = await updateNewsletterEmail(input.id, uid, {
|
||||
name: input.name,
|
||||
description: input.description,
|
||||
folder: input.folder,
|
||||
})
|
||||
if (!updatedNewsletterEmail) {
|
||||
log.error('failed to update newsletter email')
|
||||
|
||||
return {
|
||||
errorCodes: [UpdateNewsletterEmailErrorCode.Unauthorized],
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
newsletterEmail: updatedNewsletterEmail,
|
||||
}
|
||||
})
|
||||
|
||||
@ -2737,6 +2737,30 @@ const schema = gql`
|
||||
BAD_REQUEST
|
||||
}
|
||||
|
||||
input UpdateNewsletterEmailInput {
|
||||
id: ID!
|
||||
name: String
|
||||
description: String
|
||||
folder: String
|
||||
}
|
||||
|
||||
union UpdateNewsletterEmailResult =
|
||||
UpdateNewsletterEmailSuccess
|
||||
| UpdateNewsletterEmailError
|
||||
|
||||
type UpdateNewsletterEmailSuccess {
|
||||
newsletterEmail: NewsletterEmail!
|
||||
}
|
||||
|
||||
type UpdateNewsletterEmailError {
|
||||
errorCodes: [UpdateNewsletterEmailErrorCode!]!
|
||||
}
|
||||
|
||||
enum UpdateNewsletterEmailErrorCode {
|
||||
UNAUTHORIZED
|
||||
BAD_REQUEST
|
||||
}
|
||||
|
||||
# Mutations
|
||||
type Mutation {
|
||||
googleLogin(input: GoogleLoginInput!): LoginResult!
|
||||
@ -2845,6 +2869,9 @@ const schema = gql`
|
||||
): UpdateSubscriptionResult!
|
||||
moveToFolder(id: ID!, folder: String!): MoveToFolderResult!
|
||||
fetchContent(id: ID!): FetchContentResult!
|
||||
updateNewsletterEmail(
|
||||
input: UpdateNewsletterEmailInput!
|
||||
): UpdateNewsletterEmailResult!
|
||||
}
|
||||
|
||||
# FIXME: remove sort from feedArticles after all cached tabs are closed
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
} from '../generated/graphql'
|
||||
import { getRepository } from '../repository'
|
||||
import { userRepository } from '../repository/user'
|
||||
import { keysToCamelCase } from '../utils/helpers'
|
||||
import addressparser = require('nodemailer/lib/addressparser')
|
||||
|
||||
const parsedAddress = (emailAddress: string) => {
|
||||
@ -114,3 +115,28 @@ export const findNewsletterEmailById = async (
|
||||
): Promise<NewsletterEmail | null> => {
|
||||
return getRepository(NewsletterEmail).findOneBy({ id })
|
||||
}
|
||||
|
||||
export const updateNewsletterEmail = async (
|
||||
id: string,
|
||||
userId: string,
|
||||
newsletterEmail: Partial<NewsletterEmail>
|
||||
): Promise<NewsletterEmail | null> => {
|
||||
const repo = getRepository(NewsletterEmail)
|
||||
const result = await repo
|
||||
.createQueryBuilder()
|
||||
.where('id = :id', { id })
|
||||
.andWhere('user_id = :userId', { userId })
|
||||
.update(newsletterEmail)
|
||||
.returning('*')
|
||||
.execute()
|
||||
|
||||
if (
|
||||
!result.affected ||
|
||||
!Array.isArray(result.raw) ||
|
||||
result.raw.length === 0
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
return keysToCamelCase(result.raw[0]) as NewsletterEmail
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
import { getRepository } from '../../src/repository'
|
||||
import {
|
||||
createNewsletterEmail,
|
||||
deleteNewsletterEmail,
|
||||
findNewsletterEmailByAddress,
|
||||
findNewsletterEmailById,
|
||||
} from '../../src/services/newsletters'
|
||||
@ -286,4 +287,57 @@ describe('Newsletters API', () => {
|
||||
return graphqlRequest(query, invalidAuthToken).expect(500)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Update newsletter email', () => {
|
||||
const query = `
|
||||
mutation UpdateNewsletterEmail($input: UpdateNewsletterEmailInput!) {
|
||||
updateNewsletterEmail(input: $input) {
|
||||
... on UpdateNewsletterEmailSuccess {
|
||||
newsletterEmail {
|
||||
id
|
||||
address
|
||||
folder
|
||||
}
|
||||
}
|
||||
... on UpdateNewsletterEmailError {
|
||||
errorCodes
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
context('when newsletter email exists', () => {
|
||||
let newsletterEmailId = 'Newsletter email id'
|
||||
|
||||
before(async () => {
|
||||
// create test newsletter emails
|
||||
const newsletterEmail = await createNewsletterEmail(
|
||||
user.id,
|
||||
undefined,
|
||||
'inbox'
|
||||
)
|
||||
newsletterEmailId = newsletterEmail.id
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
// clean up
|
||||
await deleteNewsletterEmail(newsletterEmailId)
|
||||
})
|
||||
|
||||
it('responds with status code 200', async () => {
|
||||
const folder = 'following'
|
||||
const response = await graphqlRequest(query, authToken, {
|
||||
input: {
|
||||
id: newsletterEmailId,
|
||||
folder,
|
||||
},
|
||||
}).expect(200)
|
||||
expect(
|
||||
response.body.data.updateNewsletterEmail.newsletterEmail.folder
|
||||
).to.eql(folder)
|
||||
const newsletterEmail = await findNewsletterEmailById(newsletterEmailId)
|
||||
expect(newsletterEmail?.folder).to.eql(folder)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user