feat(medusa): add analytics config (#2442)

**What**
- Adds new entity AnalyticsConfig
- Adds new service AnalyticsConfigService
- Adds new repository AnalyticsConfigRepository
- Adds new endpoints to get, create, update, and delete analytics configs

**Why**
As we begin gathering usage insights to help us improve Medusa, we want to give each individual users the ability to control what data they share with us, or not share any data with us at all. The AnalyticsConfig holds information that is used to check if the user wishes for their data to be anonymized or if they have opted out of sharing usage data.

The entire feature can be disabled on a store level by setting the feature flag `MEDUSA_FF_ANALYTICS=false` in their environment variables, the feature is enabled by default. 

**Testing**
Adds integration test for each of the new endpoints

Resolves CORE-656, CORE-655, CORE-654

Also resolves CORE-574
This commit is contained in:
Kasper Fabricius Kristensen
2022-10-21 15:04:46 +02:00
committed by GitHub
parent f83c238a26
commit 4de4f20b46
28 changed files with 842 additions and 40 deletions

View File

@@ -7,9 +7,20 @@ const { initDb, useDb } = require("../../../helpers/use-db")
const userSeeder = require("../../helpers/user-seeder")
const adminSeeder = require("../../helpers/admin-seeder")
const {
simpleAnalyticsConfigFactory,
} = require("../../factories/simple-analytics-config-factory")
const startServerWithEnvironment =
require("../../../helpers/start-server-with-environment").default
jest.setTimeout(30000)
const adminReqConfig = {
headers: {
Authorization: "Bearer test_token",
},
}
describe("/admin/users", () => {
let medusaProcess
let dbConnection
@@ -17,7 +28,7 @@ describe("/admin/users", () => {
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
dbConnection = await initDb({ cwd })
medusaProcess = await setupServer({ cwd })
medusaProcess = await setupServer({ cwd, verbose: false })
})
afterAll(async () => {
@@ -40,9 +51,7 @@ describe("/admin/users", () => {
it("returns user by id", async () => {
const api = useApi()
const response = await api.get("/admin/users/admin_user", {
headers: { Authorization: "Bearer test_token " },
})
const response = await api.get("/admin/users/admin_user", adminReqConfig)
expect(response.status).toEqual(200)
expect(response.data.user).toMatchSnapshot({
@@ -59,11 +68,7 @@ describe("/admin/users", () => {
const api = useApi()
const response = await api
.get("/admin/users", {
headers: {
Authorization: "Bearer test_token",
},
})
.get("/admin/users", adminReqConfig)
.catch((err) => {
console.log(err)
})
@@ -107,9 +112,7 @@ describe("/admin/users", () => {
role: "member",
password: "test123453",
},
{
headers: { Authorization: "Bearer test_token" },
}
adminReqConfig
)
.catch((err) => console.log(err))
@@ -131,9 +134,7 @@ describe("/admin/users", () => {
}
const response = await api
.post("/admin/users", payload, {
headers: { Authorization: "Bearer test_token" },
})
.post("/admin/users", payload, adminReqConfig)
.catch((err) => console.log(err))
expect(response.status).toEqual(200)
@@ -153,9 +154,7 @@ describe("/admin/users", () => {
.post(
"/admin/users/member-user",
{ first_name: "karl" },
{
headers: { Authorization: "Bearer test_token " },
}
adminReqConfig
)
.catch((err) => console.log(err.response.data.message))
@@ -314,26 +313,22 @@ describe("/admin/users", () => {
const userId = "member-user"
const usersBeforeDeleteResponse = await api.get("/admin/users", {
headers: {
Authorization: "Bearer test_token",
},
})
const usersBeforeDeleteResponse = await api.get(
"/admin/users",
adminReqConfig
)
const usersBeforeDelete = usersBeforeDeleteResponse.data.users
const response = await api
.delete(`/admin/users/${userId}`, {
headers: { Authorization: "Bearer test_token" },
})
.catch((err) => console.log(err))
const usersAfterDeleteResponse = await api.get("/admin/users", {
headers: {
Authorization: "Bearer test_token",
},
const response = await api.delete(`/admin/users/${userId}`, {
headers: { Authorization: "Bearer test_token" },
})
const usersAfterDeleteResponse = await api.get(
"/admin/users",
adminReqConfig
)
expect(response.status).toEqual(200)
expect(response.data).toEqual({
id: userId,
@@ -354,3 +349,75 @@ describe("/admin/users", () => {
})
})
})
describe("[MEDUSA_FF_ANALYTICS] /admin/analytics-config", () => {
let medusaProcess
let dbConnection
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", ".."))
const [process, connection] = await startServerWithEnvironment({
cwd,
env: { MEDUSA_FF_ANALYTICS: true },
})
dbConnection = connection
medusaProcess = process
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
medusaProcess.kill()
})
describe("DELETE /admin/users", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
await userSeeder(dbConnection)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("Deletes a user and their analytics config", async () => {
const api = useApi()
const userId = "member-user"
await simpleAnalyticsConfigFactory(dbConnection, {
user_id: userId,
})
const response = await api.delete(
`/admin/users/${userId}`,
adminReqConfig
)
expect(response.status).toEqual(200)
expect(response.data).toEqual({
id: userId,
object: "user",
deleted: true,
})
const configs = await dbConnection.manager.query(
`SELECT * FROM public.analytics_config WHERE user_id = '${userId}'`
)
expect(configs).toMatchSnapshot([
{
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: expect.any(Date),
id: expect.any(String),
user_id: userId,
opt_out: false,
anonymize: false,
},
])
})
})
})