Skip to content

Commit 2c9b1b7

Browse files
committed
feat: tests
1 parent 6c07a98 commit 2c9b1b7

File tree

5 files changed

+151
-14
lines changed

5 files changed

+151
-14
lines changed

__tests__/routes/webhooks/apple.ts

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
User,
1212
UserSubscriptionStatus,
1313
} from '../../../src/entity';
14-
import { saveFixtures } from '../../helpers';
14+
import { createMockNjordTransport, saveFixtures } from '../../helpers';
1515
import {
1616
NotificationTypeV2,
1717
Subtype,
@@ -23,6 +23,11 @@ import nock from 'nock';
2323
import { env } from 'process';
2424
import { deleteRedisKey, getRedisHash } from '../../../src/redis';
2525
import { StorageKey } from '../../../src/config';
26+
import { createClient } from '@connectrpc/connect';
27+
import { Credits } from '@dailydotdev/schema';
28+
import * as njordCommon from '../../..//src/common/njord';
29+
import { getTransactionForProviderId } from '../../../src/common/paddle';
30+
import { UserTransactionProcessor } from '../../../src/entity/user/UserTransaction';
2631

2732
function createSignedData(payload): string {
2833
const keyPairOptions: ECKeyPairOptions<'pem', 'pem'> = {
@@ -407,4 +412,124 @@ describe('POST /webhooks/apple/notifications', () => {
407412
GBP: '0.8',
408413
});
409414
});
415+
416+
describe('cores', () => {
417+
const mockTransport = createMockNjordTransport();
418+
419+
beforeEach(async () => {
420+
jest
421+
.spyOn(njordCommon, 'getNjordClient')
422+
.mockImplementation(() => createClient(Credits, mockTransport));
423+
424+
await saveFixtures(con, User, [
425+
{
426+
id: 'storekit-user-c-1',
427+
username: 'storekit-user-c-1',
428+
subscriptionFlags: {
429+
appAccountToken: '18138f83-b4d3-456a-831f-1f3f7bcbb0bd',
430+
},
431+
coresRole: 3,
432+
},
433+
{
434+
id: 'storekit-user-c-2',
435+
username: 'storekit-user-c-2',
436+
subscriptionFlags: {
437+
appAccountToken: 'd9db8906-9b8b-44bc-bc35-3ac0515bad0c',
438+
},
439+
coresRole: 0,
440+
},
441+
{
442+
id: 'storekit-user-c-3',
443+
username: 'storekit-user-c-3',
444+
subscriptionFlags: {
445+
appAccountToken: 'edd16b7c-9717-4a2b-8b51-13ed104d7296',
446+
},
447+
coresRole: 1,
448+
},
449+
]);
450+
});
451+
452+
it('should purchase cores', async () => {
453+
await request(app.server)
454+
.post('/webhooks/apple/notifications')
455+
.send({
456+
signedPayload: signedPayload({
457+
notificationType: NotificationTypeV2.ONE_TIME_CHARGE,
458+
data: {
459+
signedTransactionInfo: {
460+
productId: 'cores_100',
461+
quantity: 1,
462+
type: 'Consumable',
463+
appAccountToken: '18138f83-b4d3-456a-831f-1f3f7bcbb0bd',
464+
transactionId: '220698',
465+
},
466+
},
467+
}),
468+
})
469+
.expect(200);
470+
471+
const userTransaction = await getTransactionForProviderId({
472+
con,
473+
providerId: '220698',
474+
});
475+
476+
expect(userTransaction).toEqual({
477+
id: expect.any(String),
478+
createdAt: expect.any(Date),
479+
fee: 0,
480+
flags: {
481+
providerId: '220698',
482+
},
483+
processor: UserTransactionProcessor.AppleStoreKit,
484+
productId: null,
485+
receiverId: 'storekit-user-c-1',
486+
request: {},
487+
senderId: null,
488+
status: 0,
489+
updatedAt: expect.any(Date),
490+
value: 100,
491+
valueIncFees: 100,
492+
});
493+
});
494+
495+
it('transaction completed throw if user coresRole is none', async () => {
496+
await request(app.server)
497+
.post('/webhooks/apple/notifications')
498+
.send({
499+
signedPayload: signedPayload({
500+
notificationType: NotificationTypeV2.ONE_TIME_CHARGE,
501+
data: {
502+
signedTransactionInfo: {
503+
productId: 'cores_100',
504+
quantity: 1,
505+
type: 'Consumable',
506+
appAccountToken: 'd9db8906-9b8b-44bc-bc35-3ac0515bad0c',
507+
transactionId: '220698',
508+
},
509+
},
510+
}),
511+
})
512+
.expect(500);
513+
});
514+
515+
it('transaction completed throw if user coresRole is readonly', async () => {
516+
await request(app.server)
517+
.post('/webhooks/apple/notifications')
518+
.send({
519+
signedPayload: signedPayload({
520+
notificationType: NotificationTypeV2.ONE_TIME_CHARGE,
521+
data: {
522+
signedTransactionInfo: {
523+
productId: 'cores_100',
524+
quantity: 1,
525+
type: 'Consumable',
526+
appAccountToken: 'edd16b7c-9717-4a2b-8b51-13ed104d7296',
527+
transactionId: '220698',
528+
},
529+
},
530+
}),
531+
})
532+
.expect(500);
533+
});
534+
});
410535
});

src/common/apple/purchase.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
} from '../utils';
2323
import type { Block, KnownBlock } from '@slack/web-api';
2424
import { webhooks } from '../slack';
25+
import { checkUserCoresAccess } from '../user';
26+
import { CoresRole } from '../../types';
2527

2628
export const isCorePurchaseApple = ({
2729
transactionInfo,
@@ -43,7 +45,7 @@ export const notifyNewStoreKitPurchase = async ({
4345
}: {
4446
data: JWSTransactionDecodedPayload;
4547
transaction: UserTransaction;
46-
user: User;
48+
user: Pick<User, 'id' | 'subscriptionFlags' | 'coresRole'>;
4749
currencyInUSD: number;
4850
}) => {
4951
if (isTest) {
@@ -143,7 +145,7 @@ export const handleCoresPurchase = async ({
143145
user,
144146
}: {
145147
transactionInfo: JWSTransactionDecodedPayload;
146-
user: User;
148+
user: Pick<User, 'id' | 'subscriptionFlags' | 'coresRole'>;
147149
environment: Environment;
148150
notification: ResponseBodyV2DecodedPayload;
149151
}): Promise<UserTransaction> => {
@@ -155,6 +157,15 @@ export const handleCoresPurchase = async ({
155157
throw new Error('Missing productId in transactionInfo');
156158
}
157159

160+
if (
161+
checkUserCoresAccess({
162+
user,
163+
requiredRole: CoresRole.User,
164+
}) === false
165+
) {
166+
throw new Error('User does not have access to cores purchase');
167+
}
168+
158169
const con = await createOrGetConnection();
159170

160171
// TODO feat/cores-iap load from api metadata/new endpoint

src/common/apple/subscription.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const getSubscriptionStatus = (
6565

6666
export const notifyNewStoreKitSubscription = async (
6767
data: JWSRenewalInfoDecodedPayload,
68-
user: User,
68+
user: Pick<User, 'id' | 'subscriptionFlags' | 'coresRole'>,
6969
currencyInUSD: number,
7070
) => {
7171
if (isTest) {
@@ -188,7 +188,7 @@ export const handleAppleSubscription = async ({
188188
}: {
189189
transactionInfo: JWSTransactionDecodedPayload;
190190
renewalInfo: JWSRenewalInfoDecodedPayload;
191-
user: User;
191+
user: Pick<User, 'id' | 'subscriptionFlags' | 'coresRole'>;
192192
environment: Environment;
193193
notification: ResponseBodyV2DecodedPayload;
194194
}) => {

src/common/apple/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const logAppleAnalyticsEvent = async (
5858
transactionInfo: JWSTransactionDecodedPayload,
5959
renewalInfo: JWSRenewalInfoDecodedPayload,
6060
eventName: AnalyticsEventName,
61-
user: User,
61+
user: Pick<User, 'id' | 'subscriptionFlags' | 'coresRole'>,
6262
currencyInUSD: number,
6363
) => {
6464
if (!transactionInfo || isTest) {

src/routes/webhooks/apple.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,15 @@ const handleNotifcationRequest = async (
8181
}
8282

8383
const con = await createOrGetConnection();
84-
const user = await con.getRepository(User).findOne({
85-
select: ['id', 'subscriptionFlags'],
86-
where: {
87-
subscriptionFlags: JsonContains({
88-
appAccountToken: transactionInfo.appAccountToken,
89-
}),
90-
},
91-
});
84+
const user: Pick<User, 'id' | 'subscriptionFlags' | 'coresRole'> | null =
85+
await con.getRepository(User).findOne({
86+
select: ['id', 'subscriptionFlags', 'coresRole'],
87+
where: {
88+
subscriptionFlags: JsonContains({
89+
appAccountToken: transactionInfo.appAccountToken,
90+
}),
91+
},
92+
});
9293

9394
if (!user) {
9495
logger.error(

0 commit comments

Comments
 (0)