add reply to email API which replies Okay to the sender
This commit is contained in:
@ -1616,6 +1616,7 @@ export type Mutation = {
|
||||
optInFeature: OptInFeatureResult;
|
||||
recommend: RecommendResult;
|
||||
recommendHighlights: RecommendHighlightsResult;
|
||||
replyToEmail: ReplyToEmailResult;
|
||||
reportItem: ReportItemResult;
|
||||
revokeApiKey: RevokeApiKeyResult;
|
||||
saveArticleReadingProgress: SaveArticleReadingProgressResult;
|
||||
@ -1836,6 +1837,12 @@ export type MutationRecommendHighlightsArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationReplyToEmailArgs = {
|
||||
recentEmailId: Scalars['ID'];
|
||||
reply: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationReportItemArgs = {
|
||||
input: ReportItemInput;
|
||||
};
|
||||
@ -2430,6 +2437,22 @@ export type ReminderSuccess = {
|
||||
reminder: Reminder;
|
||||
};
|
||||
|
||||
export type ReplyToEmailError = {
|
||||
__typename?: 'ReplyToEmailError';
|
||||
errorCodes: Array<ReplyToEmailErrorCode>;
|
||||
};
|
||||
|
||||
export enum ReplyToEmailErrorCode {
|
||||
Unauthorized = 'UNAUTHORIZED'
|
||||
}
|
||||
|
||||
export type ReplyToEmailResult = ReplyToEmailError | ReplyToEmailSuccess;
|
||||
|
||||
export type ReplyToEmailSuccess = {
|
||||
__typename?: 'ReplyToEmailSuccess';
|
||||
success: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type ReportItemInput = {
|
||||
itemUrl: Scalars['String'];
|
||||
pageId: Scalars['ID'];
|
||||
@ -4245,6 +4268,10 @@ export type ResolversTypes = {
|
||||
ReminderErrorCode: ReminderErrorCode;
|
||||
ReminderResult: ResolversTypes['ReminderError'] | ResolversTypes['ReminderSuccess'];
|
||||
ReminderSuccess: ResolverTypeWrapper<ReminderSuccess>;
|
||||
ReplyToEmailError: ResolverTypeWrapper<ReplyToEmailError>;
|
||||
ReplyToEmailErrorCode: ReplyToEmailErrorCode;
|
||||
ReplyToEmailResult: ResolversTypes['ReplyToEmailError'] | ResolversTypes['ReplyToEmailSuccess'];
|
||||
ReplyToEmailSuccess: ResolverTypeWrapper<ReplyToEmailSuccess>;
|
||||
ReportItemInput: ReportItemInput;
|
||||
ReportItemResult: ResolverTypeWrapper<ReportItemResult>;
|
||||
ReportType: ReportType;
|
||||
@ -4763,6 +4790,9 @@ export type ResolversParentTypes = {
|
||||
ReminderError: ReminderError;
|
||||
ReminderResult: ResolversParentTypes['ReminderError'] | ResolversParentTypes['ReminderSuccess'];
|
||||
ReminderSuccess: ReminderSuccess;
|
||||
ReplyToEmailError: ReplyToEmailError;
|
||||
ReplyToEmailResult: ResolversParentTypes['ReplyToEmailError'] | ResolversParentTypes['ReplyToEmailSuccess'];
|
||||
ReplyToEmailSuccess: ReplyToEmailSuccess;
|
||||
ReportItemInput: ReportItemInput;
|
||||
ReportItemResult: ReportItemResult;
|
||||
RevokeApiKeyError: RevokeApiKeyError;
|
||||
@ -6128,6 +6158,7 @@ export type MutationResolvers<ContextType = ResolverContext, ParentType extends
|
||||
optInFeature?: Resolver<ResolversTypes['OptInFeatureResult'], ParentType, ContextType, RequireFields<MutationOptInFeatureArgs, 'input'>>;
|
||||
recommend?: Resolver<ResolversTypes['RecommendResult'], ParentType, ContextType, RequireFields<MutationRecommendArgs, 'input'>>;
|
||||
recommendHighlights?: Resolver<ResolversTypes['RecommendHighlightsResult'], ParentType, ContextType, RequireFields<MutationRecommendHighlightsArgs, 'input'>>;
|
||||
replyToEmail?: Resolver<ResolversTypes['ReplyToEmailResult'], ParentType, ContextType, RequireFields<MutationReplyToEmailArgs, 'recentEmailId' | 'reply'>>;
|
||||
reportItem?: Resolver<ResolversTypes['ReportItemResult'], ParentType, ContextType, RequireFields<MutationReportItemArgs, 'input'>>;
|
||||
revokeApiKey?: Resolver<ResolversTypes['RevokeApiKeyResult'], ParentType, ContextType, RequireFields<MutationRevokeApiKeyArgs, 'id'>>;
|
||||
saveArticleReadingProgress?: Resolver<ResolversTypes['SaveArticleReadingProgressResult'], ParentType, ContextType, RequireFields<MutationSaveArticleReadingProgressArgs, 'input'>>;
|
||||
@ -6417,6 +6448,20 @@ export type ReminderSuccessResolvers<ContextType = ResolverContext, ParentType e
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type ReplyToEmailErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ReplyToEmailError'] = ResolversParentTypes['ReplyToEmailError']> = {
|
||||
errorCodes?: Resolver<Array<ResolversTypes['ReplyToEmailErrorCode']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type ReplyToEmailResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ReplyToEmailResult'] = ResolversParentTypes['ReplyToEmailResult']> = {
|
||||
__resolveType: TypeResolveFn<'ReplyToEmailError' | 'ReplyToEmailSuccess', ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type ReplyToEmailSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ReplyToEmailSuccess'] = ResolversParentTypes['ReplyToEmailSuccess']> = {
|
||||
success?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type ReportItemResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['ReportItemResult'] = ResolversParentTypes['ReportItemResult']> = {
|
||||
message?: Resolver<ResolversTypes['String'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
@ -7488,6 +7533,9 @@ export type Resolvers<ContextType = ResolverContext> = {
|
||||
ReminderError?: ReminderErrorResolvers<ContextType>;
|
||||
ReminderResult?: ReminderResultResolvers<ContextType>;
|
||||
ReminderSuccess?: ReminderSuccessResolvers<ContextType>;
|
||||
ReplyToEmailError?: ReplyToEmailErrorResolvers<ContextType>;
|
||||
ReplyToEmailResult?: ReplyToEmailResultResolvers<ContextType>;
|
||||
ReplyToEmailSuccess?: ReplyToEmailSuccessResolvers<ContextType>;
|
||||
ReportItemResult?: ReportItemResultResolvers<ContextType>;
|
||||
RevokeApiKeyError?: RevokeApiKeyErrorResolvers<ContextType>;
|
||||
RevokeApiKeyResult?: RevokeApiKeyResultResolvers<ContextType>;
|
||||
|
||||
@ -1454,6 +1454,7 @@ type Mutation {
|
||||
optInFeature(input: OptInFeatureInput!): OptInFeatureResult!
|
||||
recommend(input: RecommendInput!): RecommendResult!
|
||||
recommendHighlights(input: RecommendHighlightsInput!): RecommendHighlightsResult!
|
||||
replyToEmail(recentEmailId: ID!, reply: String!): ReplyToEmailResult!
|
||||
reportItem(input: ReportItemInput!): ReportItemResult!
|
||||
revokeApiKey(id: ID!): RevokeApiKeyResult!
|
||||
saveArticleReadingProgress(input: SaveArticleReadingProgressInput!): SaveArticleReadingProgressResult!
|
||||
@ -1811,6 +1812,20 @@ type ReminderSuccess {
|
||||
reminder: Reminder!
|
||||
}
|
||||
|
||||
type ReplyToEmailError {
|
||||
errorCodes: [ReplyToEmailErrorCode!]!
|
||||
}
|
||||
|
||||
enum ReplyToEmailErrorCode {
|
||||
UNAUTHORIZED
|
||||
}
|
||||
|
||||
union ReplyToEmailResult = ReplyToEmailError | ReplyToEmailSuccess
|
||||
|
||||
type ReplyToEmailSuccess {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
input ReportItemInput {
|
||||
itemUrl: String!
|
||||
pageId: ID!
|
||||
|
||||
@ -150,7 +150,11 @@ import {
|
||||
webhookResolver,
|
||||
webhooksResolver,
|
||||
} from './index'
|
||||
import { markEmailAsItemResolver, recentEmailsResolver } from './recent_emails'
|
||||
import {
|
||||
markEmailAsItemResolver,
|
||||
recentEmailsResolver,
|
||||
replyToEmailResolver,
|
||||
} from './recent_emails'
|
||||
import { recentSearchesResolver } from './recent_searches'
|
||||
import { WithDataSourcesContext } from './types'
|
||||
import { updateEmailResolver } from './user'
|
||||
@ -316,6 +320,7 @@ export const functionResolvers = {
|
||||
emptyTrash: emptyTrashResolver,
|
||||
fetchContent: fetchContentResolver,
|
||||
exportToIntegration: exportToIntegrationResolver,
|
||||
replyToEmail: replyToEmailResolver,
|
||||
},
|
||||
Query: {
|
||||
me: getMeUserResolver,
|
||||
@ -680,4 +685,5 @@ export const functionResolvers = {
|
||||
...resultResolveTypeResolver('FetchContent'),
|
||||
...resultResolveTypeResolver('Integration'),
|
||||
...resultResolveTypeResolver('ExportToIntegration'),
|
||||
...resultResolveTypeResolver('ReplyToEmail'),
|
||||
}
|
||||
|
||||
@ -7,10 +7,14 @@ import {
|
||||
MarkEmailAsItemErrorCode,
|
||||
MarkEmailAsItemSuccess,
|
||||
MutationMarkEmailAsItemArgs,
|
||||
MutationReplyToEmailArgs,
|
||||
RecentEmailsError,
|
||||
RecentEmailsErrorCode,
|
||||
RecentEmailsSuccess,
|
||||
ReplyToEmailError,
|
||||
ReplyToEmailErrorCode,
|
||||
ReplyToEmailSuccess,
|
||||
} from '../../generated/graphql'
|
||||
import { getRepository } from '../../repository'
|
||||
import { updateReceivedEmail } from '../../services/received_emails'
|
||||
import { saveNewsletter } from '../../services/save_newsletter_email'
|
||||
import { authorized } from '../../utils/gql-utils'
|
||||
@ -20,27 +24,19 @@ import { sendEmail } from '../../utils/sendEmail'
|
||||
export const recentEmailsResolver = authorized<
|
||||
RecentEmailsSuccess,
|
||||
RecentEmailsError
|
||||
>(async (_, __, { authTrx, log, uid }) => {
|
||||
try {
|
||||
const recentEmails = await authTrx((t) =>
|
||||
t.getRepository(ReceivedEmail).find({
|
||||
where: {
|
||||
user: { id: uid },
|
||||
},
|
||||
order: { createdAt: 'DESC' },
|
||||
take: 20,
|
||||
})
|
||||
)
|
||||
>(async (_, __, { authTrx, uid }) => {
|
||||
const recentEmails = await authTrx((t) =>
|
||||
t.getRepository(ReceivedEmail).find({
|
||||
where: {
|
||||
user: { id: uid },
|
||||
},
|
||||
order: { createdAt: 'DESC' },
|
||||
take: 20,
|
||||
})
|
||||
)
|
||||
|
||||
return {
|
||||
recentEmails,
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('Error getting recent emails', error)
|
||||
|
||||
return {
|
||||
errorCodes: [RecentEmailsErrorCode.BadRequest],
|
||||
}
|
||||
return {
|
||||
recentEmails,
|
||||
}
|
||||
})
|
||||
|
||||
@ -49,87 +45,109 @@ export const markEmailAsItemResolver = authorized<
|
||||
MarkEmailAsItemError,
|
||||
MutationMarkEmailAsItemArgs
|
||||
>(async (_, { recentEmailId }, { authTrx, uid, log }) => {
|
||||
try {
|
||||
const recentEmail = await authTrx((t) =>
|
||||
t.getRepository(ReceivedEmail).findOneBy({
|
||||
id: recentEmailId,
|
||||
const recentEmail = await authTrx((t) =>
|
||||
t.getRepository(ReceivedEmail).findOneBy({
|
||||
id: recentEmailId,
|
||||
user: { id: uid },
|
||||
type: 'non-article',
|
||||
})
|
||||
)
|
||||
if (!recentEmail) {
|
||||
log.info('no recent email', recentEmailId)
|
||||
|
||||
return {
|
||||
errorCodes: [MarkEmailAsItemErrorCode.Unauthorized],
|
||||
}
|
||||
}
|
||||
|
||||
const newsletterEmail = await authTrx((t) =>
|
||||
t.getRepository(NewsletterEmail).findOne({
|
||||
where: {
|
||||
user: { id: uid },
|
||||
type: 'non-article',
|
||||
})
|
||||
)
|
||||
if (!recentEmail) {
|
||||
log.info('no recent email', recentEmailId)
|
||||
|
||||
return {
|
||||
errorCodes: [MarkEmailAsItemErrorCode.Unauthorized],
|
||||
}
|
||||
}
|
||||
|
||||
const newsletterEmail = await authTrx((t) =>
|
||||
t.getRepository(NewsletterEmail).findOne({
|
||||
where: {
|
||||
user: { id: uid },
|
||||
address: ILike(recentEmail.to),
|
||||
},
|
||||
relations: ['user'],
|
||||
})
|
||||
)
|
||||
if (!newsletterEmail) {
|
||||
log.info('no newsletter email for', {
|
||||
id: recentEmail.id,
|
||||
to: recentEmail.to,
|
||||
from: recentEmail.from,
|
||||
})
|
||||
|
||||
return {
|
||||
errorCodes: [MarkEmailAsItemErrorCode.NotFound],
|
||||
}
|
||||
}
|
||||
|
||||
const success = await saveNewsletter(
|
||||
{
|
||||
from: recentEmail.from,
|
||||
email: recentEmail.to,
|
||||
title: recentEmail.subject,
|
||||
content: recentEmail.html,
|
||||
url: generateUniqueUrl(),
|
||||
author: parseEmailAddress(recentEmail.from).name,
|
||||
receivedEmailId: recentEmail.id,
|
||||
address: ILike(recentEmail.to),
|
||||
},
|
||||
newsletterEmail
|
||||
)
|
||||
if (!success) {
|
||||
log.info('newsletter not created', recentEmail.id)
|
||||
|
||||
return {
|
||||
errorCodes: [MarkEmailAsItemErrorCode.BadRequest],
|
||||
}
|
||||
}
|
||||
|
||||
// update received email type
|
||||
await updateReceivedEmail(recentEmail.id, 'article', uid)
|
||||
|
||||
const text = `A recent email marked as a library item
|
||||
by: ${uid}
|
||||
from: ${recentEmail.from}
|
||||
subject: ${recentEmail.subject}`
|
||||
|
||||
// email us to let us know that an email failed to parse as an article
|
||||
await sendEmail({
|
||||
to: env.sender.feedback,
|
||||
subject: 'A recent email marked as a library item',
|
||||
text,
|
||||
from: env.sender.message,
|
||||
relations: ['user'],
|
||||
})
|
||||
)
|
||||
if (!newsletterEmail) {
|
||||
log.info('no newsletter email for', {
|
||||
id: recentEmail.id,
|
||||
to: recentEmail.to,
|
||||
from: recentEmail.from,
|
||||
})
|
||||
|
||||
return {
|
||||
success,
|
||||
errorCodes: [MarkEmailAsItemErrorCode.NotFound],
|
||||
}
|
||||
} catch (error) {
|
||||
log.error('Error marking email as item', error)
|
||||
}
|
||||
|
||||
const success = await saveNewsletter(
|
||||
{
|
||||
from: recentEmail.from,
|
||||
email: recentEmail.to,
|
||||
title: recentEmail.subject,
|
||||
content: recentEmail.html,
|
||||
url: generateUniqueUrl(),
|
||||
author: parseEmailAddress(recentEmail.from).name,
|
||||
receivedEmailId: recentEmail.id,
|
||||
},
|
||||
newsletterEmail
|
||||
)
|
||||
if (!success) {
|
||||
log.info('newsletter not created', recentEmail.id)
|
||||
|
||||
return {
|
||||
errorCodes: [MarkEmailAsItemErrorCode.BadRequest],
|
||||
}
|
||||
}
|
||||
|
||||
// update received email type
|
||||
await updateReceivedEmail(recentEmail.id, 'article', uid)
|
||||
|
||||
const text = `A recent email marked as a library item
|
||||
by: ${uid}
|
||||
from: ${recentEmail.from}
|
||||
subject: ${recentEmail.subject}`
|
||||
|
||||
// email us to let us know that an email failed to parse as an article
|
||||
await sendEmail({
|
||||
to: env.sender.feedback,
|
||||
subject: 'A recent email marked as a library item',
|
||||
text,
|
||||
from: env.sender.message,
|
||||
})
|
||||
|
||||
return {
|
||||
success,
|
||||
}
|
||||
})
|
||||
|
||||
export const replyToEmailResolver = authorized<
|
||||
ReplyToEmailSuccess,
|
||||
ReplyToEmailError,
|
||||
MutationReplyToEmailArgs
|
||||
>(async (_, { recentEmailId }, { uid, log }) => {
|
||||
const recentEmail = await getRepository(ReceivedEmail).findOneBy({
|
||||
id: recentEmailId,
|
||||
user: { id: uid },
|
||||
})
|
||||
|
||||
if (!recentEmail) {
|
||||
log.info('no recent email', recentEmailId)
|
||||
|
||||
return {
|
||||
errorCodes: [ReplyToEmailErrorCode.Unauthorized],
|
||||
}
|
||||
}
|
||||
|
||||
const result = await sendEmail({
|
||||
to: recentEmail.from,
|
||||
subject: 'Re: ' + recentEmail.subject,
|
||||
text: 'Okay',
|
||||
from: recentEmail.to,
|
||||
})
|
||||
|
||||
return {
|
||||
success: result,
|
||||
}
|
||||
})
|
||||
|
||||
@ -3066,6 +3066,20 @@ const schema = gql`
|
||||
FAILED_TO_CREATE_TASK
|
||||
}
|
||||
|
||||
union ReplyToEmailResult = ReplyToEmailSuccess | ReplyToEmailError
|
||||
|
||||
type ReplyToEmailSuccess {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type ReplyToEmailError {
|
||||
errorCodes: [ReplyToEmailErrorCode!]!
|
||||
}
|
||||
|
||||
enum ReplyToEmailErrorCode {
|
||||
UNAUTHORIZED
|
||||
}
|
||||
|
||||
# Mutations
|
||||
type Mutation {
|
||||
googleLogin(input: GoogleLoginInput!): LoginResult!
|
||||
@ -3165,6 +3179,7 @@ const schema = gql`
|
||||
contentType: String!
|
||||
): UploadImportFileResult!
|
||||
markEmailAsItem(recentEmailId: ID!): MarkEmailAsItemResult!
|
||||
replyToEmail(recentEmailId: ID!, reply: String!): ReplyToEmailResult!
|
||||
bulkAction(
|
||||
query: String!
|
||||
action: BulkActionType!
|
||||
|
||||
Reference in New Issue
Block a user