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:
@@ -16,6 +16,7 @@ export default (container, config) => {
|
||||
}
|
||||
|
||||
// Admin
|
||||
export * from "./routes/admin/analytics-configs"
|
||||
export * from "./routes/admin/auth"
|
||||
export * from "./routes/admin/batch"
|
||||
export * from "./routes/admin/collections"
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { IsBoolean } from "class-validator"
|
||||
import { Request, Response } from "express"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { AnalyticsConfigService } from "../../../../services"
|
||||
import { CreateAnalyticsConfig } from "../../../../types/analytics-config"
|
||||
|
||||
// No OAS for this route, for internal use only.
|
||||
export default async (req: Request, res: Response) => {
|
||||
const userId = (req.user?.userId ?? req.user?.id)!
|
||||
const validatedBody = req.validatedBody as CreateAnalyticsConfig
|
||||
const analyticsConfigService: AnalyticsConfigService = req.scope.resolve(
|
||||
"analyticsConfigService"
|
||||
)
|
||||
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
const analyticsConfig = await manager.transaction(
|
||||
async (transactionManager) => {
|
||||
return await analyticsConfigService
|
||||
.withTransaction(transactionManager)
|
||||
.create(userId, validatedBody)
|
||||
}
|
||||
)
|
||||
|
||||
res.status(200).json({ analytics_config: analyticsConfig })
|
||||
}
|
||||
|
||||
export class AdminPostAnalyticsConfigReq {
|
||||
@IsBoolean()
|
||||
opt_out: boolean
|
||||
|
||||
@IsBoolean()
|
||||
anonymize?: boolean = false
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Request, Response } from "express"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { AnalyticsConfigService } from "../../../../services"
|
||||
|
||||
// No OAS for this route, for internal use only.
|
||||
export default async (req: Request, res: Response) => {
|
||||
const userId = (req.user?.userId ?? req.user?.id)!
|
||||
|
||||
const analyticsConfigService: AnalyticsConfigService = req.scope.resolve(
|
||||
"analyticsConfigService"
|
||||
)
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
|
||||
await manager.transaction(async (transactionManager) => {
|
||||
return await analyticsConfigService
|
||||
.withTransaction(transactionManager)
|
||||
.delete(userId)
|
||||
})
|
||||
|
||||
res
|
||||
.status(200)
|
||||
.json({ user_id: userId, object: "analytics_config", deleted: true })
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Request, Response } from "express"
|
||||
import { AnalyticsConfigService } from "../../../../services"
|
||||
|
||||
// No OAS for this route, for internal use only.
|
||||
export default async (req: Request, res: Response): Promise<void> => {
|
||||
const userId = (req.user?.userId ?? req.user?.id)!
|
||||
|
||||
const analyticsConfigService: AnalyticsConfigService = req.scope.resolve(
|
||||
"analyticsConfigService"
|
||||
)
|
||||
|
||||
const analyticsConfig = await analyticsConfigService.retrieve(userId)
|
||||
res.status(200).json({ analytics_config: analyticsConfig })
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Router } from "express"
|
||||
import { AnalyticsConfig } from "../../../.."
|
||||
import { DeleteResponse } from "../../../../types/common"
|
||||
import middlewares, { transformBody } from "../../../middlewares"
|
||||
import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled"
|
||||
import { AdminPostAnalyticsConfigReq } from "./create-analytics-config"
|
||||
import { AdminPostAnalyticsConfigAnalyticsConfigReq } from "./update-analytics-config"
|
||||
|
||||
const route = Router()
|
||||
|
||||
export default (app: Router) => {
|
||||
app.use("/analytics-configs", isFeatureFlagEnabled("analytics"), route)
|
||||
|
||||
route.get("/", middlewares.wrap(require("./get-analytics-config").default))
|
||||
|
||||
route.post(
|
||||
"/",
|
||||
transformBody(AdminPostAnalyticsConfigReq),
|
||||
middlewares.wrap(require("./create-analytics-config").default)
|
||||
)
|
||||
|
||||
route.post(
|
||||
"/update",
|
||||
transformBody(AdminPostAnalyticsConfigAnalyticsConfigReq),
|
||||
middlewares.wrap(require("./update-analytics-config").default)
|
||||
)
|
||||
|
||||
route.delete(
|
||||
"/",
|
||||
middlewares.wrap(require("./delete-analytics-config").default)
|
||||
)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
export type AdminAnalyticsConfigRes = {
|
||||
analytics_config: AnalyticsConfig
|
||||
}
|
||||
|
||||
export type AdminAnalyticsConfigDeleteRes = DeleteResponse
|
||||
|
||||
export * from "./create-analytics-config"
|
||||
export * from "./update-analytics-config"
|
||||
@@ -0,0 +1,35 @@
|
||||
import { IsBoolean, IsOptional } from "class-validator"
|
||||
import { Request, Response } from "express"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { AnalyticsConfigService } from "../../../../services"
|
||||
import { UpdateAnalyticsConfig } from "../../../../types/analytics-config"
|
||||
|
||||
// No OAS for this route, for internal use only.
|
||||
export default async (req: Request, res: Response) => {
|
||||
const userId = (req.user?.userId ?? req.user?.id)!
|
||||
const validatedBody = req.validatedBody as UpdateAnalyticsConfig
|
||||
const analyticsConfigService: AnalyticsConfigService = req.scope.resolve(
|
||||
"analyticsConfigService"
|
||||
)
|
||||
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
const analyticsConfig = await manager.transaction(
|
||||
async (transactionManager) => {
|
||||
return await analyticsConfigService
|
||||
.withTransaction(transactionManager)
|
||||
.update(userId, validatedBody)
|
||||
}
|
||||
)
|
||||
|
||||
res.status(200).json({ analytics_config: analyticsConfig })
|
||||
}
|
||||
|
||||
export class AdminPostAnalyticsConfigAnalyticsConfigReq {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
opt_out?: boolean
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
anonymize?: boolean
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import cors from "cors"
|
||||
import { Router } from "express"
|
||||
import middlewares from "../../middlewares"
|
||||
import analyticsConfigs from "./analytics-configs"
|
||||
import appRoutes from "./apps"
|
||||
import authRoutes from "./auth"
|
||||
import batchRoutes from "./batch"
|
||||
@@ -67,6 +68,7 @@ export default (app, container, config) => {
|
||||
// Calls all middleware that has been registered to run after authentication.
|
||||
middlewareService.usePostAuthentication(app)
|
||||
|
||||
analyticsConfigs(route)
|
||||
appRoutes(route)
|
||||
batchRoutes(route)
|
||||
collectionRoutes(route)
|
||||
|
||||
Reference in New Issue
Block a user