mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
fix(api): clear the perks-sanitized latch when premium returns (#2963)
This commit is contained in:
@@ -14,7 +14,7 @@ import {createRequestCache} from '@app/api/middleware/RequestCacheMiddleware';
|
||||
import {addGiftCodeDuration} from '@app/api/models/GiftCode';
|
||||
import type {User} from '@app/api/models/User';
|
||||
import type {IUserRepository} from '@app/api/user/IUserRepository';
|
||||
import {createPremiumClearPatch, getEffectivePremiumUntil} from '@app/api/user/UserHelpers';
|
||||
import {clearPerksSanitizedFlag, createPremiumClearPatch, getEffectivePremiumUntil} from '@app/api/user/UserHelpers';
|
||||
import {mapUserToPrivateResponse} from '@app/api/user/UserMappers';
|
||||
import {UserPremiumTypes} from '@fluxer/constants/src/UserConstants';
|
||||
import {MissingAccessError} from '@fluxer/errors/src/domains/core/MissingAccessError';
|
||||
@@ -62,6 +62,7 @@ export class StripePremiumService {
|
||||
premium_will_cancel: false,
|
||||
premium_billing_cycle: billingCycle,
|
||||
premium_grace_ends_at: null,
|
||||
premium_flags: clearPerksSanitizedFlag(user.premiumFlags),
|
||||
},
|
||||
user.toRow(),
|
||||
);
|
||||
@@ -90,6 +91,7 @@ export class StripePremiumService {
|
||||
premium_since: this.resolvePremiumSince(user.premiumSince, premiumSinceAnchor, now),
|
||||
premium_until: null,
|
||||
premium_lifetime_sequence: visionarySequence,
|
||||
premium_flags: clearPerksSanitizedFlag(user.premiumFlags),
|
||||
has_ever_purchased: hasEverPurchased,
|
||||
premium_will_cancel: false,
|
||||
premium_billing_cycle: null,
|
||||
@@ -127,6 +129,7 @@ export class StripePremiumService {
|
||||
};
|
||||
if ((user.premiumType ?? 0) <= 0) {
|
||||
patch.premium_type = premiumType;
|
||||
patch.premium_flags = clearPerksSanitizedFlag(user.premiumFlags);
|
||||
patch.premium_since = this.resolvePremiumSince(user.premiumSince, null, now);
|
||||
}
|
||||
if (hasEverPurchased && !user.hasEverPurchased) {
|
||||
|
||||
@@ -275,6 +275,10 @@ export function createPremiumClearPatch(): Partial<UserRow> {
|
||||
return mapExpiredPremiumFields(() => null) as Partial<UserRow>;
|
||||
}
|
||||
|
||||
export function clearPerksSanitizedFlag(premiumFlags: number): number {
|
||||
return premiumFlags & ~PremiumFlags.PERKS_SANITIZED;
|
||||
}
|
||||
|
||||
const PROFILE_SUBSTRING_EXEMPT_FLAGS = UserFlags.STAFF;
|
||||
|
||||
export function isProfileSubstringExempt(user: Pick<PremiumCheckable, 'flags'>): boolean {
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
getSubscriptionPremiumPeriodEnd,
|
||||
getSubscriptionStartDate,
|
||||
} from '@app/api/stripe/StripeSubscriptionPeriod';
|
||||
import {createPremiumClearPatch, getEffectivePremiumUntil} from '@app/api/user/UserHelpers';
|
||||
import {clearPerksSanitizedFlag, createPremiumClearPatch, getEffectivePremiumUntil} from '@app/api/user/UserHelpers';
|
||||
import {mapUserToPrivateResponse} from '@app/api/user/UserMappers';
|
||||
import {getWorkerDependencies} from '@app/api/worker/WorkerContext';
|
||||
import {PremiumFlags, UserPremiumTypes} from '@fluxer/constants/src/UserConstants';
|
||||
@@ -73,6 +73,10 @@ function buildStripePremiumRepairPatch(user: User, subscription: Stripe.Subscrip
|
||||
if (user.stripeSubscriptionId !== subscription.id) {
|
||||
patch.stripe_subscription_id = subscription.id;
|
||||
}
|
||||
const clearedPremiumFlags = clearPerksSanitizedFlag(user.premiumFlags);
|
||||
if (user.premiumFlags !== clearedPremiumFlags) {
|
||||
patch.premium_flags = clearedPremiumFlags;
|
||||
}
|
||||
if (subscriptionCustomerId && user.stripeCustomerId !== subscriptionCustomerId) {
|
||||
patch.stripe_customer_id = subscriptionCustomerId;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import {NoopLogger} from '@app/api/test/mocks/NoopLogger';
|
||||
import type {UserRepository} from '@app/api/user/repositories/UserRepository';
|
||||
import processPremiumStateReconciliationQueue from '@app/api/worker/tasks/ProcessPremiumStateReconciliationQueue';
|
||||
import {clearWorkerDependencies, setWorkerDependenciesForTest} from '@app/api/worker/WorkerContext';
|
||||
import {PremiumFlags} from '@fluxer/constants/src/UserConstants';
|
||||
import type {WorkerTaskHelpers} from '@pkgs/worker/src/contracts/WorkerTask';
|
||||
import type Stripe from 'stripe';
|
||||
import {afterEach, describe, expect, test} from 'vitest';
|
||||
@@ -48,6 +49,28 @@ function createCancelledSubscription(endedAtMs: number): Stripe.Subscription {
|
||||
} as unknown as Stripe.Subscription;
|
||||
}
|
||||
|
||||
function createActiveSubscription(periodEndMs: number): Stripe.Subscription {
|
||||
return {
|
||||
id: 'sub_test',
|
||||
status: 'active',
|
||||
customer: 'cus_test',
|
||||
ended_at: null,
|
||||
canceled_at: null,
|
||||
cancel_at: null,
|
||||
cancel_at_period_end: false,
|
||||
trial_end: null,
|
||||
start_date: Math.floor((Date.now() - 200 * ONE_DAY_MS) / 1000),
|
||||
items: {
|
||||
data: [
|
||||
{
|
||||
current_period_end: Math.floor(periodEndMs / 1000),
|
||||
price: {recurring: {interval: 'month'}},
|
||||
},
|
||||
],
|
||||
},
|
||||
} as unknown as Stripe.Subscription;
|
||||
}
|
||||
|
||||
function createPaidInvoice(periodEndMs: number): Stripe.Invoice {
|
||||
return {
|
||||
id: 'in_test',
|
||||
@@ -299,4 +322,27 @@ describe('processPremiumStateReconciliationQueue', () => {
|
||||
expect(patches[0].premium_until).toBeNull();
|
||||
expect(patches[0].premium_since).toBeNull();
|
||||
});
|
||||
test('clears the perks-sanitized latch once the subscription is active again', async () => {
|
||||
const queueService = createQueueService();
|
||||
await queueService.enqueueUser(USER_ID, new Date(Date.now() - 1000));
|
||||
|
||||
const periodEndMs = Math.floor((Date.now() + 20 * ONE_DAY_MS) / 1000) * 1000;
|
||||
const user = createPremiumUser({
|
||||
premium_until: new Date(periodEndMs),
|
||||
premium_flags: PremiumFlags.PERKS_SANITIZED,
|
||||
});
|
||||
const {userRepository, patches, extras} = createCapturingDeps(user);
|
||||
|
||||
setWorkerDependenciesForTest({
|
||||
premiumStateReconciliationQueueService: queueService,
|
||||
stripe: createStripeStub(createActiveSubscription(periodEndMs), []),
|
||||
userRepository,
|
||||
...extras,
|
||||
});
|
||||
|
||||
await processPremiumStateReconciliationQueue({}, createHelpers());
|
||||
|
||||
expect(patches).toHaveLength(1);
|
||||
expect(patches[0].premium_flags).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user