mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
fixed merge conflicts
This commit is contained in:
commit
d42b0c244c
7 changed files with 187 additions and 0 deletions
|
|
@ -1484,6 +1484,25 @@ export type SearchSuccess = {
|
|||
pageInfo: PageInfo;
|
||||
};
|
||||
|
||||
export type SendInstallInstructionsError = {
|
||||
__typename?: 'SendInstallInstructionsError';
|
||||
errorCodes: Array<SendInstallInstructionsErrorCode>;
|
||||
};
|
||||
|
||||
export enum SendInstallInstructionsErrorCode {
|
||||
BadRequest = 'BAD_REQUEST',
|
||||
Forbidden = 'FORBIDDEN',
|
||||
NotFound = 'NOT_FOUND',
|
||||
Unauthorized = 'UNAUTHORIZED'
|
||||
}
|
||||
|
||||
export type SendInstallInstructionsResult = SendInstallInstructionsError | SendInstallInstructionsSuccess;
|
||||
|
||||
export type SendInstallInstructionsSuccess = {
|
||||
__typename?: 'SendInstallInstructionsSuccess';
|
||||
sent: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type SetBookmarkArticleError = {
|
||||
__typename?: 'SetBookmarkArticleError';
|
||||
errorCodes: Array<SetBookmarkArticleErrorCode>;
|
||||
|
|
@ -2462,6 +2481,10 @@ export type ResolversTypes = {
|
|||
SearchItemEdge: ResolverTypeWrapper<SearchItemEdge>;
|
||||
SearchResult: ResolversTypes['SearchError'] | ResolversTypes['SearchSuccess'];
|
||||
SearchSuccess: ResolverTypeWrapper<SearchSuccess>;
|
||||
SendInstallInstructionsError: ResolverTypeWrapper<SendInstallInstructionsError>;
|
||||
SendInstallInstructionsErrorCode: SendInstallInstructionsErrorCode;
|
||||
SendInstallInstructionsResult: ResolversTypes['SendInstallInstructionsError'] | ResolversTypes['SendInstallInstructionsSuccess'];
|
||||
SendInstallInstructionsSuccess: ResolverTypeWrapper<SendInstallInstructionsSuccess>;
|
||||
SetBookmarkArticleError: ResolverTypeWrapper<SetBookmarkArticleError>;
|
||||
SetBookmarkArticleErrorCode: SetBookmarkArticleErrorCode;
|
||||
SetBookmarkArticleInput: SetBookmarkArticleInput;
|
||||
|
|
@ -2760,6 +2783,9 @@ export type ResolversParentTypes = {
|
|||
SearchItemEdge: SearchItemEdge;
|
||||
SearchResult: ResolversParentTypes['SearchError'] | ResolversParentTypes['SearchSuccess'];
|
||||
SearchSuccess: SearchSuccess;
|
||||
SendInstallInstructionsError: SendInstallInstructionsError;
|
||||
SendInstallInstructionsResult: ResolversParentTypes['SendInstallInstructionsError'] | ResolversParentTypes['SendInstallInstructionsSuccess'];
|
||||
SendInstallInstructionsSuccess: SendInstallInstructionsSuccess;
|
||||
SetBookmarkArticleError: SetBookmarkArticleError;
|
||||
SetBookmarkArticleInput: SetBookmarkArticleInput;
|
||||
SetBookmarkArticleResult: ResolversParentTypes['SetBookmarkArticleError'] | ResolversParentTypes['SetBookmarkArticleSuccess'];
|
||||
|
|
@ -3716,6 +3742,20 @@ export type SearchSuccessResolvers<ContextType = ResolverContext, ParentType ext
|
|||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type SendInstallInstructionsErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SendInstallInstructionsError'] = ResolversParentTypes['SendInstallInstructionsError']> = {
|
||||
errorCodes?: Resolver<Array<ResolversTypes['SendInstallInstructionsErrorCode']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type SendInstallInstructionsResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SendInstallInstructionsResult'] = ResolversParentTypes['SendInstallInstructionsResult']> = {
|
||||
__resolveType: TypeResolveFn<'SendInstallInstructionsError' | 'SendInstallInstructionsSuccess', ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type SendInstallInstructionsSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SendInstallInstructionsSuccess'] = ResolversParentTypes['SendInstallInstructionsSuccess']> = {
|
||||
sent?: Resolver<ResolversTypes['Boolean'], ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type SetBookmarkArticleErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['SetBookmarkArticleError'] = ResolversParentTypes['SetBookmarkArticleError']> = {
|
||||
errorCodes?: Resolver<Array<ResolversTypes['SetBookmarkArticleErrorCode']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
|
|
@ -4290,6 +4330,9 @@ export type Resolvers<ContextType = ResolverContext> = {
|
|||
SearchItemEdge?: SearchItemEdgeResolvers<ContextType>;
|
||||
SearchResult?: SearchResultResolvers<ContextType>;
|
||||
SearchSuccess?: SearchSuccessResolvers<ContextType>;
|
||||
SendInstallInstructionsError?: SendInstallInstructionsErrorResolvers<ContextType>;
|
||||
SendInstallInstructionsResult?: SendInstallInstructionsResultResolvers<ContextType>;
|
||||
SendInstallInstructionsSuccess?: SendInstallInstructionsSuccessResolvers<ContextType>;
|
||||
SetBookmarkArticleError?: SetBookmarkArticleErrorResolvers<ContextType>;
|
||||
SetBookmarkArticleResult?: SetBookmarkArticleResultResolvers<ContextType>;
|
||||
SetBookmarkArticleSuccess?: SetBookmarkArticleSuccessResolvers<ContextType>;
|
||||
|
|
|
|||
|
|
@ -1055,6 +1055,23 @@ type SearchSuccess {
|
|||
pageInfo: PageInfo!
|
||||
}
|
||||
|
||||
type SendInstallInstructionsError {
|
||||
errorCodes: [SendInstallInstructionsErrorCode!]!
|
||||
}
|
||||
|
||||
enum SendInstallInstructionsErrorCode {
|
||||
BAD_REQUEST
|
||||
FORBIDDEN
|
||||
NOT_FOUND
|
||||
UNAUTHORIZED
|
||||
}
|
||||
|
||||
union SendInstallInstructionsResult = SendInstallInstructionsError | SendInstallInstructionsSuccess
|
||||
|
||||
type SendInstallInstructionsSuccess {
|
||||
sent: Boolean!
|
||||
}
|
||||
|
||||
type SetBookmarkArticleError {
|
||||
errorCodes: [SetBookmarkArticleErrorCode!]!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ import {
|
|||
savePageResolver,
|
||||
saveUrlResolver,
|
||||
searchResolver,
|
||||
sendInstallInstructionsResolver,
|
||||
setBookmarkArticleResolver,
|
||||
setDeviceTokenResolver,
|
||||
setFollowResolver,
|
||||
|
|
@ -176,6 +177,7 @@ export const functionResolvers = {
|
|||
labels: labelsResolver,
|
||||
search: searchResolver,
|
||||
subscriptions: subscriptionsResolver,
|
||||
sendInstallInstructions: sendInstallInstructionsResolver,
|
||||
webhooks: webhooksResolver,
|
||||
webhook: webhookResolver,
|
||||
},
|
||||
|
|
@ -568,6 +570,7 @@ export const functionResolvers = {
|
|||
...resultResolveTypeResolver('Subscriptions'),
|
||||
...resultResolveTypeResolver('Unsubscribe'),
|
||||
...resultResolveTypeResolver('UpdateLabel'),
|
||||
...resultResolveTypeResolver('SendInstallInstructions'),
|
||||
...resultResolveTypeResolver('UpdatePage'),
|
||||
...resultResolveTypeResolver('Subscribe'),
|
||||
...resultResolveTypeResolver('AddPopularRead'),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export * from './report'
|
|||
export * from './links'
|
||||
export * from './newsletters'
|
||||
export * from './save'
|
||||
export * from './send_install_instructions'
|
||||
export * from './reminders'
|
||||
export * from './user_device_tokens'
|
||||
export * from './labels'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
import {
|
||||
SendInstallInstructionsError,
|
||||
SendInstallInstructionsErrorCode,
|
||||
SendInstallInstructionsSuccess,
|
||||
} from '../../generated/graphql'
|
||||
import { authorized } from '../../utils/helpers'
|
||||
import { sendEmail } from '../../utils/sendEmail'
|
||||
import { AppDataSource } from '../../server'
|
||||
import { User } from '../../entity/user'
|
||||
|
||||
const INSTALL_INSTRUCTIONS_EMAIL_TEMPLATE_ID =
|
||||
'd-c576bdc3b9a849dab250655ba14c7794'
|
||||
|
||||
export const sendInstallInstructionsResolver = authorized<
|
||||
SendInstallInstructionsSuccess,
|
||||
SendInstallInstructionsError
|
||||
>(async (_parent, _args, { claims }) => {
|
||||
try {
|
||||
const user = await AppDataSource.getRepository(User).findOneBy({
|
||||
id: claims.uid,
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
return { errorCodes: [SendInstallInstructionsErrorCode.Unauthorized] }
|
||||
}
|
||||
|
||||
const sendInstallInstructions = await sendEmail({
|
||||
from: 'msgs@omnivore.app',
|
||||
templateId: INSTALL_INSTRUCTIONS_EMAIL_TEMPLATE_ID,
|
||||
to: user?.email,
|
||||
})
|
||||
|
||||
return {
|
||||
sent: sendInstallInstructions,
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
|
||||
return {
|
||||
errorCodes: [SendInstallInstructionsErrorCode.BadRequest],
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -1255,6 +1255,25 @@ const schema = gql`
|
|||
errorCodes: [DeleteReminderErrorCode!]!
|
||||
}
|
||||
|
||||
type SendInstallInstructionsSuccess {
|
||||
sent: Boolean!
|
||||
}
|
||||
|
||||
enum SendInstallInstructionsErrorCode {
|
||||
UNAUTHORIZED
|
||||
BAD_REQUEST
|
||||
NOT_FOUND
|
||||
FORBIDDEN
|
||||
}
|
||||
|
||||
type SendInstallInstructionsError {
|
||||
errorCodes: [SendInstallInstructionsErrorCode!]!
|
||||
}
|
||||
|
||||
union SendInstallInstructionsResult =
|
||||
SendInstallInstructionsSuccess
|
||||
| SendInstallInstructionsError
|
||||
|
||||
input SetDeviceTokenInput {
|
||||
id: ID
|
||||
token: String
|
||||
|
|
@ -1776,6 +1795,7 @@ const schema = gql`
|
|||
labels: LabelsResult!
|
||||
search(after: String, first: Int, query: String): SearchResult!
|
||||
subscriptions(sort: SortParams): SubscriptionsResult!
|
||||
sendInstallInstructions: SendInstallInstructionsResult!
|
||||
webhooks: WebhooksResult!
|
||||
webhook(id: ID!): WebhookResult!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
import {
|
||||
createTestUser,
|
||||
deleteTestUser,
|
||||
} from '../db'
|
||||
import { graphqlRequest, request } from '../util'
|
||||
import 'mocha'
|
||||
|
||||
describe('Send Install Instructions API', () => {
|
||||
const username = 'fakeUser'
|
||||
|
||||
let authToken: string
|
||||
|
||||
before(async () => {
|
||||
// create test user and login
|
||||
const user = await createTestUser(username)
|
||||
const res = await request
|
||||
.post('/local/debug/fake-user-login')
|
||||
.send({ fakeEmail: user.email })
|
||||
|
||||
authToken = res.body.authToken
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
// clean up
|
||||
await deleteTestUser(username)
|
||||
})
|
||||
|
||||
describe('Send install instructions', () => {
|
||||
const query = `
|
||||
query SendInstallInstructions {
|
||||
sendInstallInstructions {
|
||||
... on SendInstallInstructionsSuccess {
|
||||
sent
|
||||
}
|
||||
}
|
||||
|
||||
sendInstallInstructions {
|
||||
... on SendInstallInstructionsError {
|
||||
errorCodes
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
it('responds status code 400 when invalid query', async () => {
|
||||
const invalidQuery = `
|
||||
query {
|
||||
sendInstallInstructions {
|
||||
}
|
||||
}
|
||||
`
|
||||
return graphqlRequest(invalidQuery, authToken).expect(400)
|
||||
})
|
||||
|
||||
it('responds status code 500 when invalid user', async () => {
|
||||
const invalidAuthToken = 'Fake token'
|
||||
return graphqlRequest(query, invalidAuthToken).expect(500)
|
||||
})
|
||||
})
|
||||
})
|
||||
Loading…
Reference in a new issue