diff --git a/fluxer_api/src/api/user/UserHelpers.test.ts b/fluxer_api/src/api/user/UserHelpers.test.ts index 83f29bd42..bcf7648b4 100644 --- a/fluxer_api/src/api/user/UserHelpers.test.ts +++ b/fluxer_api/src/api/user/UserHelpers.test.ts @@ -3,6 +3,7 @@ import { canOwnerRunBots, checkIsPremium, + getBadgePremiumType, getEffectivePremiumUntil, getPremiumPaymentRecoveryGraceMs, isSignInRefused, @@ -61,6 +62,31 @@ describe('checkIsPremium', () => { }); }); +describe('getBadgePremiumType', () => { + it('shows a subscription badge for a backend premium override', () => { + expect(getBadgePremiumType({premiumType: null, premiumFlags: PremiumFlags.ENABLED_OVERRIDE})).toBe( + UserPremiumTypes.SUBSCRIPTION, + ); + expect(getBadgePremiumType({premiumType: UserPremiumTypes.NONE, premiumFlags: PremiumFlags.ENABLED_OVERRIDE})).toBe( + UserPremiumTypes.SUBSCRIPTION, + ); + }); + it('keeps the stored premium type', () => { + expect( + getBadgePremiumType({premiumType: UserPremiumTypes.LIFETIME, premiumFlags: PremiumFlags.ENABLED_OVERRIDE}), + ).toBe(UserPremiumTypes.LIFETIME); + }); + it('shows no badge without premium or while perks are disabled', () => { + expect(getBadgePremiumType({premiumType: null, premiumFlags: 0})).toBeUndefined(); + expect( + getBadgePremiumType({ + premiumType: null, + premiumFlags: PremiumFlags.ENABLED_OVERRIDE | PremiumFlags.PERKS_DISABLED, + }), + ).toBeUndefined(); + }); +}); + describe('account standing', () => { const hour = 3_600_000; function standing(flags: bigint, tempBannedUntil: Date | null = null, deletionStartedAt: Date | null = null) { diff --git a/fluxer_api/src/api/user/UserHelpers.ts b/fluxer_api/src/api/user/UserHelpers.ts index 0be717750..da7658a5b 100644 --- a/fluxer_api/src/api/user/UserHelpers.ts +++ b/fluxer_api/src/api/user/UserHelpers.ts @@ -9,6 +9,8 @@ import { PREMIUM_PAYMENT_RECOVERY_GRACE_DAYS, PremiumFlags, UserFlags, + type UserPremiumType, + UserPremiumTypes, } from '@fluxer/constants/src/UserConstants'; import {MS_PER_DAY} from '@fluxer/date_utils/src/DateConstants'; import {snowflakeToDate} from '@fluxer/snowflake/src/Snowflake'; @@ -121,6 +123,21 @@ export function checkIsPremium(user: PremiumCheckable): boolean { return false; } +export function getBadgePremiumType( + user: Pick, +): UserPremiumType | undefined { + if (user.premiumType != null && user.premiumType !== UserPremiumTypes.NONE) { + return user.premiumType as UserPremiumType; + } + if ( + (user.premiumFlags & (PremiumFlags.ENABLED_OVERRIDE | PremiumFlags.PERKS_DISABLED)) === + PremiumFlags.ENABLED_OVERRIDE + ) { + return UserPremiumTypes.SUBSCRIPTION; + } + return undefined; +} + const PREMIUM_CLEAR_FIELDS = [ 'premium_type', 'premium_since', diff --git a/fluxer_api/src/api/user/services/UserAccountLookupService.ts b/fluxer_api/src/api/user/services/UserAccountLookupService.ts index e555d1332..f327df4e3 100644 --- a/fluxer_api/src/api/user/services/UserAccountLookupService.ts +++ b/fluxer_api/src/api/user/services/UserAccountLookupService.ts @@ -11,6 +11,7 @@ import type {GuildMember} from '@app/api/models/GuildMember'; import type {User} from '@app/api/models/User'; import type {UserRepository} from '@app/api/user/repositories/UserRepository'; import {isUsernameTaken} from '@app/api/user/UniqueUsernames'; +import {getBadgePremiumType} from '@app/api/user/UserHelpers'; import {hasFixedDiscriminator} from '@app/api/user/UserTag'; import {ChannelTypes} from '@fluxer/constants/src/ChannelConstants'; import { @@ -100,7 +101,7 @@ export class UserAccountLookupService { } } } - let premiumType = user.premiumType ?? undefined; + let premiumType = getBadgePremiumType(user); let premiumSince = user.premiumSince ?? undefined; let premiumLifetimeSequence = user.premiumLifetimeSequence ?? undefined; if (restrictProfile || user.premiumFlags & PremiumFlags.BADGE_HIDDEN) {