Add get device tokens api
This commit is contained in:
@ -614,6 +614,23 @@ export type DeviceToken = {
|
||||
token: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DeviceTokensError = {
|
||||
__typename?: 'DeviceTokensError';
|
||||
errorCodes: Array<DeviceTokensErrorCode>;
|
||||
};
|
||||
|
||||
export enum DeviceTokensErrorCode {
|
||||
BadRequest = 'BAD_REQUEST',
|
||||
Unauthorized = 'UNAUTHORIZED'
|
||||
}
|
||||
|
||||
export type DeviceTokensResult = DeviceTokensError | DeviceTokensSuccess;
|
||||
|
||||
export type DeviceTokensSuccess = {
|
||||
__typename?: 'DeviceTokensSuccess';
|
||||
deviceTokens: Array<DeviceToken>;
|
||||
};
|
||||
|
||||
export type Feature = {
|
||||
__typename?: 'Feature';
|
||||
createdAt: Scalars['Date'];
|
||||
@ -1416,6 +1433,7 @@ export type Query = {
|
||||
article: ArticleResult;
|
||||
articleSavingRequest: ArticleSavingRequestResult;
|
||||
articles: ArticlesResult;
|
||||
deviceTokens: DeviceTokensResult;
|
||||
feedArticles: FeedArticlesResult;
|
||||
getFollowers: GetFollowersResult;
|
||||
getFollowing: GetFollowingResult;
|
||||
@ -2844,6 +2862,10 @@ export type ResolversTypes = {
|
||||
DeleteWebhookResult: ResolversTypes['DeleteWebhookError'] | ResolversTypes['DeleteWebhookSuccess'];
|
||||
DeleteWebhookSuccess: ResolverTypeWrapper<DeleteWebhookSuccess>;
|
||||
DeviceToken: ResolverTypeWrapper<DeviceToken>;
|
||||
DeviceTokensError: ResolverTypeWrapper<DeviceTokensError>;
|
||||
DeviceTokensErrorCode: DeviceTokensErrorCode;
|
||||
DeviceTokensResult: ResolversTypes['DeviceTokensError'] | ResolversTypes['DeviceTokensSuccess'];
|
||||
DeviceTokensSuccess: ResolverTypeWrapper<DeviceTokensSuccess>;
|
||||
Feature: ResolverTypeWrapper<Feature>;
|
||||
FeedArticle: ResolverTypeWrapper<FeedArticle>;
|
||||
FeedArticleEdge: ResolverTypeWrapper<FeedArticleEdge>;
|
||||
@ -3227,6 +3249,9 @@ export type ResolversParentTypes = {
|
||||
DeleteWebhookResult: ResolversParentTypes['DeleteWebhookError'] | ResolversParentTypes['DeleteWebhookSuccess'];
|
||||
DeleteWebhookSuccess: DeleteWebhookSuccess;
|
||||
DeviceToken: DeviceToken;
|
||||
DeviceTokensError: DeviceTokensError;
|
||||
DeviceTokensResult: ResolversParentTypes['DeviceTokensError'] | ResolversParentTypes['DeviceTokensSuccess'];
|
||||
DeviceTokensSuccess: DeviceTokensSuccess;
|
||||
Feature: Feature;
|
||||
FeedArticle: FeedArticle;
|
||||
FeedArticleEdge: FeedArticleEdge;
|
||||
@ -3888,6 +3913,20 @@ export type DeviceTokenResolvers<ContextType = ResolverContext, ParentType exten
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type DeviceTokensErrorResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeviceTokensError'] = ResolversParentTypes['DeviceTokensError']> = {
|
||||
errorCodes?: Resolver<Array<ResolversTypes['DeviceTokensErrorCode']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type DeviceTokensResultResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeviceTokensResult'] = ResolversParentTypes['DeviceTokensResult']> = {
|
||||
__resolveType: TypeResolveFn<'DeviceTokensError' | 'DeviceTokensSuccess', ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type DeviceTokensSuccessResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['DeviceTokensSuccess'] = ResolversParentTypes['DeviceTokensSuccess']> = {
|
||||
deviceTokens?: Resolver<Array<ResolversTypes['DeviceToken']>, ParentType, ContextType>;
|
||||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
|
||||
};
|
||||
|
||||
export type FeatureResolvers<ContextType = ResolverContext, ParentType extends ResolversParentTypes['Feature'] = ResolversParentTypes['Feature']> = {
|
||||
createdAt?: Resolver<ResolversTypes['Date'], ParentType, ContextType>;
|
||||
expiresAt?: Resolver<Maybe<ResolversTypes['Date']>, ParentType, ContextType>;
|
||||
@ -4303,6 +4342,7 @@ export type QueryResolvers<ContextType = ResolverContext, ParentType extends Res
|
||||
article?: Resolver<ResolversTypes['ArticleResult'], ParentType, ContextType, RequireFields<QueryArticleArgs, 'slug' | 'username'>>;
|
||||
articleSavingRequest?: Resolver<ResolversTypes['ArticleSavingRequestResult'], ParentType, ContextType, RequireFields<QueryArticleSavingRequestArgs, 'id'>>;
|
||||
articles?: Resolver<ResolversTypes['ArticlesResult'], ParentType, ContextType, Partial<QueryArticlesArgs>>;
|
||||
deviceTokens?: Resolver<ResolversTypes['DeviceTokensResult'], ParentType, ContextType>;
|
||||
feedArticles?: Resolver<ResolversTypes['FeedArticlesResult'], ParentType, ContextType, Partial<QueryFeedArticlesArgs>>;
|
||||
getFollowers?: Resolver<ResolversTypes['GetFollowersResult'], ParentType, ContextType, Partial<QueryGetFollowersArgs>>;
|
||||
getFollowing?: Resolver<ResolversTypes['GetFollowingResult'], ParentType, ContextType, Partial<QueryGetFollowingArgs>>;
|
||||
@ -5127,6 +5167,9 @@ export type Resolvers<ContextType = ResolverContext> = {
|
||||
DeleteWebhookResult?: DeleteWebhookResultResolvers<ContextType>;
|
||||
DeleteWebhookSuccess?: DeleteWebhookSuccessResolvers<ContextType>;
|
||||
DeviceToken?: DeviceTokenResolvers<ContextType>;
|
||||
DeviceTokensError?: DeviceTokensErrorResolvers<ContextType>;
|
||||
DeviceTokensResult?: DeviceTokensResultResolvers<ContextType>;
|
||||
DeviceTokensSuccess?: DeviceTokensSuccessResolvers<ContextType>;
|
||||
Feature?: FeatureResolvers<ContextType>;
|
||||
FeedArticle?: FeedArticleResolvers<ContextType>;
|
||||
FeedArticleEdge?: FeedArticleEdgeResolvers<ContextType>;
|
||||
|
||||
@ -540,6 +540,21 @@ type DeviceToken {
|
||||
token: String!
|
||||
}
|
||||
|
||||
type DeviceTokensError {
|
||||
errorCodes: [DeviceTokensErrorCode!]!
|
||||
}
|
||||
|
||||
enum DeviceTokensErrorCode {
|
||||
BAD_REQUEST
|
||||
UNAUTHORIZED
|
||||
}
|
||||
|
||||
union DeviceTokensResult = DeviceTokensError | DeviceTokensSuccess
|
||||
|
||||
type DeviceTokensSuccess {
|
||||
deviceTokens: [DeviceToken!]!
|
||||
}
|
||||
|
||||
type Feature {
|
||||
createdAt: Date!
|
||||
expiresAt: Date
|
||||
@ -1028,6 +1043,7 @@ type Query {
|
||||
article(slug: String!, username: String!): ArticleResult!
|
||||
articleSavingRequest(id: ID!): ArticleSavingRequestResult!
|
||||
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!
|
||||
getFollowers(userId: ID): GetFollowersResult!
|
||||
getFollowing(userId: ID): GetFollowingResult!
|
||||
|
||||
@ -37,6 +37,7 @@ import {
|
||||
deleteNewsletterEmailResolver,
|
||||
deleteReminderResolver,
|
||||
deleteWebhookResolver,
|
||||
deviceTokensResolver,
|
||||
generateApiKeyResolver,
|
||||
getAllUsersResolver,
|
||||
getArticleResolver,
|
||||
@ -204,6 +205,7 @@ export const functionResolvers = {
|
||||
integrations: integrationsResolver,
|
||||
recentSearches: recentSearchesResolver,
|
||||
rules: rulesResolver,
|
||||
deviceTokens: deviceTokensResolver,
|
||||
},
|
||||
User: {
|
||||
async sharedArticles(
|
||||
@ -616,4 +618,5 @@ export const functionResolvers = {
|
||||
...resultResolveTypeResolver('OptInFeature'),
|
||||
...resultResolveTypeResolver('SetRule'),
|
||||
...resultResolveTypeResolver('Rules'),
|
||||
...resultResolveTypeResolver('DeviceTokens'),
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import { authorized } from '../../utils/helpers'
|
||||
import {
|
||||
DeviceToken,
|
||||
DeviceTokensError,
|
||||
DeviceTokensErrorCode,
|
||||
DeviceTokensSuccess,
|
||||
MutationSetDeviceTokenArgs,
|
||||
SetDeviceTokenError,
|
||||
SetDeviceTokenErrorCode,
|
||||
@ -13,6 +16,7 @@ import {
|
||||
deleteDeviceToken,
|
||||
getDeviceToken,
|
||||
getDeviceTokenByToken,
|
||||
getDeviceTokensByUserId,
|
||||
} from '../../services/user_device_tokens'
|
||||
import { UserDeviceToken } from '../../entity/user_device_tokens'
|
||||
import { QueryFailedError } from 'typeorm'
|
||||
@ -122,6 +126,41 @@ export const setDeviceTokenResolver = authorized<
|
||||
}
|
||||
})
|
||||
|
||||
export const deviceTokensResolver = authorized<
|
||||
DeviceTokensSuccess,
|
||||
DeviceTokensError
|
||||
>(async (_parent, _args, { claims: { uid }, log }) => {
|
||||
try {
|
||||
log.info('deviceTokensResolver', {
|
||||
labels: {
|
||||
source: 'resolver',
|
||||
resolver: 'deviceTokensResolver',
|
||||
uid,
|
||||
},
|
||||
})
|
||||
|
||||
const deviceTokens = await getDeviceTokensByUserId(uid)
|
||||
console.log('deviceTokens', deviceTokens)
|
||||
|
||||
return {
|
||||
deviceTokens: deviceTokens.map(deviceTokenToData),
|
||||
}
|
||||
} catch (e) {
|
||||
log.error('Error getting device tokens', {
|
||||
e,
|
||||
labels: {
|
||||
source: 'resolver',
|
||||
resolver: 'rulesResolver',
|
||||
uid,
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
errorCodes: [DeviceTokensErrorCode.BadRequest],
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const deviceTokenToData = (deviceToken: UserDeviceToken): DeviceToken => {
|
||||
return {
|
||||
id: deviceToken.id,
|
||||
|
||||
@ -2033,6 +2033,21 @@ const schema = gql`
|
||||
NOT_FOUND
|
||||
}
|
||||
|
||||
union DeviceTokensResult = DeviceTokensSuccess | DeviceTokensError
|
||||
|
||||
type DeviceTokensSuccess {
|
||||
deviceTokens: [DeviceToken!]!
|
||||
}
|
||||
|
||||
type DeviceTokensError {
|
||||
errorCodes: [DeviceTokensErrorCode!]!
|
||||
}
|
||||
|
||||
enum DeviceTokensErrorCode {
|
||||
UNAUTHORIZED
|
||||
BAD_REQUEST
|
||||
}
|
||||
|
||||
# Mutations
|
||||
type Mutation {
|
||||
googleLogin(input: GoogleLoginInput!): LoginResult!
|
||||
@ -2155,6 +2170,7 @@ const schema = gql`
|
||||
integrations: IntegrationsResult!
|
||||
recentSearches: RecentSearchesResult!
|
||||
rules(enabled: Boolean): RulesResult!
|
||||
deviceTokens: DeviceTokensResult!
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ export const getDeviceTokenByToken = async (
|
||||
|
||||
export const getDeviceTokensByUserId = async (
|
||||
userId: string
|
||||
): Promise<UserDeviceToken[] | undefined> => {
|
||||
): Promise<UserDeviceToken[]> => {
|
||||
return getRepository(UserDeviceToken).find({
|
||||
where: { user: { id: userId } },
|
||||
})
|
||||
|
||||
@ -9,16 +9,19 @@ import { expect } from 'chai'
|
||||
import { UserDeviceToken } from '../../src/entity/user_device_tokens'
|
||||
import { SetDeviceTokenErrorCode } from '../../src/generated/graphql'
|
||||
import 'mocha'
|
||||
import { User } from '../../src/entity/user'
|
||||
import { getRepository } from '../../src/entity/utils'
|
||||
|
||||
describe('Device tokens API', () => {
|
||||
const username = 'fakeUser'
|
||||
|
||||
let authToken: string
|
||||
let deviceToken: UserDeviceToken
|
||||
let user: User
|
||||
|
||||
before(async () => {
|
||||
// create test user and login
|
||||
const user = await createTestUser(username)
|
||||
user = await createTestUser(username)
|
||||
const res = await request
|
||||
.post('/local/debug/fake-user-login')
|
||||
.send({ fakeEmail: user.email })
|
||||
@ -63,6 +66,11 @@ describe('Device tokens API', () => {
|
||||
`
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
// clean up
|
||||
await getRepository(UserDeviceToken).delete({ user: { id: user.id } })
|
||||
})
|
||||
|
||||
context('when id in input is not null', () => {
|
||||
context('when token exists', () => {
|
||||
before(() => {
|
||||
@ -137,4 +145,43 @@ describe('Device tokens API', () => {
|
||||
return graphqlRequest(query, invalidAuthToken).expect(500)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Get device tokens', () => {
|
||||
const token = 'Some token'
|
||||
|
||||
const query = `
|
||||
query {
|
||||
deviceTokens {
|
||||
... on DeviceTokensSuccess {
|
||||
deviceTokens {
|
||||
id
|
||||
token
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
... on DeviceTokensError {
|
||||
errorCodes
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
before(async () => {
|
||||
// create test device token
|
||||
await getRepository(UserDeviceToken).save({
|
||||
user: { id: user.id },
|
||||
token,
|
||||
})
|
||||
})
|
||||
|
||||
after(async () => {
|
||||
// clean up
|
||||
await getRepository(UserDeviceToken).delete({ token })
|
||||
})
|
||||
|
||||
it('responds with status code 200 and returns all device tokens', async () => {
|
||||
const response = await graphqlRequest(query, authToken).expect(200)
|
||||
expect(response.body.data.deviceTokens.deviceTokens).to.have.lengthOf(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user