Skip to content

Commit

Permalink
Implement getSubscriptionFeatures endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelbsky committed Dec 1, 2024
1 parent d5d9667 commit 0b75704
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Server } from '../../../../lexicon'
import AppContext from '../../../../context'
import { Features } from '../../../../lexicon/types/app/bsky/subscription/getSubscriptionFeatures'

export default function (server: Server, ctx: AppContext) {
server.app.bsky.subscription.getSubscriptionFeatures({
auth: ctx.authVerifier.standard,
handler: async ({ auth }) => {
const viewer = auth.credentials.iss

const features = await getFeaturesForViewerSubscription(viewer, ctx)

return {
encoding: 'application/json',
body: {
features,
},
}
},
})
}

const getFeaturesForViewerSubscription = async (
viewerDid: string,
ctx: AppContext,
) => {
const { subscriptionEntitlements } =
await ctx.dataplane.getSubscriptionEntitlement({ dids: [viewerDid] })

const gatedFeatures: Features = {
customProfileColor: false,
}

if (subscriptionEntitlements?.length === 0) {
return gatedFeatures
}

const { entitlements } = subscriptionEntitlements[0]

return entitlements.reduce((acc, entitlement) => {
if (!entitlementFeatures[entitlement]) {
return acc
}
return {
...acc,
...entitlementFeatures[entitlement],
}
}, gatedFeatures)
}

type EntitlementFeatures = {
[entitlementIdentifier: string]: {
[k: keyof Features]: true
}
}

const entitlementFeatures: EntitlementFeatures = {
core: {
customProfileColor: true,
},
}
2 changes: 2 additions & 0 deletions packages/bsky/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import listNotifications from './app/bsky/notification/listNotifications'
import updateSeen from './app/bsky/notification/updateSeen'
import putPreferences from './app/bsky/notification/putPreferences'
import registerPush from './app/bsky/notification/registerPush'
import getSubscriptionFeatures from './app/bsky/subscription/getSubscriptionFeatures'
import getConfig from './app/bsky/unspecced/getConfig'
import getPopularFeedGenerators from './app/bsky/unspecced/getPopularFeedGenerators'
import getTaggedSuggestions from './app/bsky/unspecced/getTaggedSuggestions'
Expand Down Expand Up @@ -115,6 +116,7 @@ export default function (server: Server, ctx: AppContext) {
updateSeen(server, ctx)
putPreferences(server, ctx)
registerPush(server, ctx)
getSubscriptionFeatures(server, ctx)
getConfig(server, ctx)
getPopularFeedGenerators(server, ctx)
getTaggedSuggestions(server, ctx)
Expand Down
68 changes: 68 additions & 0 deletions packages/bsky/tests/views/subscriptions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { AtUri, AtpAgent } from '@atproto/api'
import { TestNetwork, SeedClient, basicSeed } from '@atproto/dev-env'
import { ids } from '../../src/lexicon/lexicons'

describe('subscriptions views', () => {
let network: TestNetwork
let agent: AtpAgent
let pdsAgent: AtpAgent
let sc: SeedClient

// account dids, for convenience
let alice: string
let bob: string

beforeAll(async () => {
network = await TestNetwork.create({
dbPostgresSchema: 'bsky_views_subscriptions',
})
agent = network.bsky.getClient()
pdsAgent = network.pds.getClient()
sc = network.getSeedClient()
await basicSeed(sc)
await network.processAll()
alice = sc.dids.alice
bob = sc.dids.bob
})

afterAll(async () => {
await network.close()
})

it('returns features for user with subscription', async () => {
await network.bsky.db.db
.insertInto('subscription_entitlement')
.values({ did: alice, entitlements: JSON.stringify(['core']) })
.execute()

const {
data: { features },
} = await agent.app.bsky.subscription.getSubscriptionFeatures(
{},
{
headers: await network.serviceHeaders(
alice,
ids.AppBskySubscriptionGetSubscriptionFeatures,
),
},
)

expect(features).toStrictEqual({ customProfileColor: true })
})

it('returns features for user without subscription', async () => {
const {
data: { features },
} = await agent.app.bsky.subscription.getSubscriptionFeatures(
{},
{
headers: await network.serviceHeaders(
bob,
ids.AppBskySubscriptionGetSubscriptionFeatures,
),
},
)

expect(features).toStrictEqual({ customProfileColor: false })
})
})

0 comments on commit 0b75704

Please sign in to comment.