Still fetch flags when the user is not logged in.
This commit is contained in:
parent
abd7b3b84e
commit
20f55e3795
|
@ -1,7 +1,8 @@
|
||||||
import env from "../environment"
|
import env from "../environment"
|
||||||
|
import * as crypto from "crypto"
|
||||||
import * as context from "../context"
|
import * as context from "../context"
|
||||||
import { PostHog, PostHogOptions } from "posthog-node"
|
import { PostHog, PostHogOptions } from "posthog-node"
|
||||||
import { FeatureFlag, IdentityType, UserCtx } from "@budibase/types"
|
import { FeatureFlag, UserCtx } from "@budibase/types"
|
||||||
import tracer from "dd-trace"
|
import tracer from "dd-trace"
|
||||||
import { Duration } from "../utils"
|
import { Duration } from "../utils"
|
||||||
|
|
||||||
|
@ -224,24 +225,29 @@ export class FlagSet<V extends Flag<any>, T extends { [key: string]: V }> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const identity = context.getIdentity()
|
const identity = context.getIdentity()
|
||||||
tags[`identity.type`] = identity?.type
|
|
||||||
tags[`identity.tenantId`] = identity?.tenantId
|
|
||||||
tags[`identity._id`] = identity?._id
|
|
||||||
|
|
||||||
if (posthog && identity?.type === IdentityType.USER) {
|
let userId = identity?._id
|
||||||
|
if (!userId && ctx?.ip) {
|
||||||
|
userId = crypto.createHash("sha512").update(ctx.ip).digest("hex")
|
||||||
|
}
|
||||||
|
|
||||||
|
let tenantId = identity?.tenantId
|
||||||
|
if (!tenantId) {
|
||||||
|
tenantId = currentTenantId
|
||||||
|
}
|
||||||
|
|
||||||
|
tags[`identity.type`] = identity?.type
|
||||||
|
tags[`identity._id`] = identity?._id
|
||||||
|
tags[`tenantId`] = tenantId
|
||||||
|
tags[`userId`] = userId
|
||||||
|
|
||||||
|
if (posthog && userId) {
|
||||||
tags[`readFromPostHog`] = true
|
tags[`readFromPostHog`] = true
|
||||||
|
|
||||||
const personProperties: Record<string, string> = {}
|
const personProperties: Record<string, string> = { tenantId }
|
||||||
if (identity.tenantId) {
|
const posthogFlags = await posthog.getAllFlagsAndPayloads(userId, {
|
||||||
personProperties.tenantId = identity.tenantId
|
|
||||||
}
|
|
||||||
|
|
||||||
const posthogFlags = await posthog.getAllFlagsAndPayloads(
|
|
||||||
identity._id,
|
|
||||||
{
|
|
||||||
personProperties,
|
personProperties,
|
||||||
}
|
})
|
||||||
)
|
|
||||||
|
|
||||||
for (const [name, value] of Object.entries(posthogFlags.featureFlags)) {
|
for (const [name, value] of Object.entries(posthogFlags.featureFlags)) {
|
||||||
if (!this.isFlagName(name)) {
|
if (!this.isFlagName(name)) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import * as context from "../../context"
|
||||||
import environment, { withEnv } from "../../environment"
|
import environment, { withEnv } from "../../environment"
|
||||||
import nodeFetch from "node-fetch"
|
import nodeFetch from "node-fetch"
|
||||||
import nock from "nock"
|
import nock from "nock"
|
||||||
|
import * as crypto from "crypto"
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
TEST_BOOLEAN: Flag.boolean(false),
|
TEST_BOOLEAN: Flag.boolean(false),
|
||||||
|
@ -27,10 +28,14 @@ interface PostHogFlags {
|
||||||
featureFlagPayloads?: Record<string, string>
|
featureFlagPayloads?: Record<string, string>
|
||||||
}
|
}
|
||||||
|
|
||||||
function mockPosthogFlags(flags: PostHogFlags) {
|
function mockPosthogFlags(
|
||||||
|
flags: PostHogFlags,
|
||||||
|
opts?: { token?: string; distinct_id?: string }
|
||||||
|
) {
|
||||||
|
const { token = "test", distinct_id = "us_1234" } = opts || {}
|
||||||
nock("https://us.i.posthog.com")
|
nock("https://us.i.posthog.com")
|
||||||
.post("/decide/?v=3", body => {
|
.post("/decide/?v=3", body => {
|
||||||
return body.token === "test" && body.distinct_id === "us_1234"
|
return body.token === token && body.distinct_id === distinct_id
|
||||||
})
|
})
|
||||||
.reply(200, flags)
|
.reply(200, flags)
|
||||||
.persist()
|
.persist()
|
||||||
|
@ -214,6 +219,14 @@ describe("feature flags", () => {
|
||||||
lastName: "User",
|
lastName: "User",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We need to pass in node-fetch here otherwise nock won't get used
|
||||||
|
// because posthog-node uses axios under the hood.
|
||||||
|
init({
|
||||||
|
fetch: (url, opts) => {
|
||||||
|
return nodeFetch(url, opts)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
nock("https://us.i.posthog.com")
|
nock("https://us.i.posthog.com")
|
||||||
.post("/decide/?v=3", body => {
|
.post("/decide/?v=3", body => {
|
||||||
return body.token === "test" && body.distinct_id === "us_1234"
|
return body.token === "test" && body.distinct_id === "us_1234"
|
||||||
|
@ -230,4 +243,42 @@ describe("feature flags", () => {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should still get flags when user is logged out", async () => {
|
||||||
|
const env: Partial<typeof environment> = {
|
||||||
|
SELF_HOSTED: false,
|
||||||
|
POSTHOG_FEATURE_FLAGS_ENABLED: "true",
|
||||||
|
POSTHOG_API_HOST: "https://us.i.posthog.com",
|
||||||
|
POSTHOG_TOKEN: "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = { ip: "127.0.0.1" } as UserCtx
|
||||||
|
const hashedIp = crypto.createHash("sha512").update(ctx.ip).digest("hex")
|
||||||
|
|
||||||
|
await withEnv(env, async () => {
|
||||||
|
mockPosthogFlags(
|
||||||
|
{
|
||||||
|
featureFlags: { TEST_BOOLEAN: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
distinct_id: hashedIp,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// We need to pass in node-fetch here otherwise nock won't get used
|
||||||
|
// because posthog-node uses axios under the hood.
|
||||||
|
init({
|
||||||
|
fetch: (url, opts) => {
|
||||||
|
return nodeFetch(url, opts)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await context.doInTenant("default", async () => {
|
||||||
|
const result = await flags.fetch(ctx)
|
||||||
|
expect(result.TEST_BOOLEAN).toBe(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
shutdown()
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue