-
Notifications
You must be signed in to change notification settings - Fork 264
Expand file tree
/
Copy pathactions.ts
More file actions
106 lines (97 loc) · 3.65 KB
/
actions.ts
File metadata and controls
106 lines (97 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
'use server';
import { sew, withAuth, withOrgMembership } from "@/actions";
import { OrgRole } from "@sourcebot/db";
import { prisma } from "@/prisma";
import { ServiceError } from "@/lib/serviceError";
import { AnalyticsResponse } from "./types";
import { hasEntitlement } from "@sourcebot/shared";
import { ErrorCode } from "@/lib/errorCodes";
import { StatusCodes } from "http-status-codes";
export const getAnalytics = async (domain: string, apiKey: string | undefined = undefined): Promise<AnalyticsResponse | ServiceError> => sew(() =>
withAuth((userId, _apiKeyHash) =>
withOrgMembership(userId, domain, async ({ org }) => {
if (!hasEntitlement("analytics")) {
return {
statusCode: StatusCodes.FORBIDDEN,
errorCode: ErrorCode.INSUFFICIENT_PERMISSIONS,
message: "Analytics is not available in your current plan",
} satisfies ServiceError;
}
const rows = await prisma.$queryRaw<AnalyticsResponse>`
WITH core AS (
SELECT
date_trunc('day', "timestamp") AS day,
date_trunc('week', "timestamp") AS week,
date_trunc('month', "timestamp") AS month,
action,
"actorId"
FROM "Audit"
WHERE "orgId" = ${org.id}
AND action IN (
'user.performed_code_search',
'user.performed_find_references',
'user.performed_goto_definition',
'user.created_ask_chat'
)
),
periods AS (
SELECT unnest(array['day', 'week', 'month']) AS period
),
buckets AS (
SELECT
generate_series(
date_trunc('day', (SELECT MIN("timestamp") FROM "Audit" WHERE "orgId" = ${org.id})),
date_trunc('day', CURRENT_DATE),
interval '1 day'
) AS bucket,
'day' AS period
UNION ALL
SELECT
generate_series(
date_trunc('week', (SELECT MIN("timestamp") FROM "Audit" WHERE "orgId" = ${org.id})),
date_trunc('week', CURRENT_DATE),
interval '1 week'
),
'week'
UNION ALL
SELECT
generate_series(
date_trunc('month', (SELECT MIN("timestamp") FROM "Audit" WHERE "orgId" = ${org.id})),
date_trunc('month', CURRENT_DATE),
interval '1 month'
),
'month'
),
aggregated AS (
SELECT
b.period,
CASE b.period
WHEN 'day' THEN c.day
WHEN 'week' THEN c.week
ELSE c.month
END AS bucket,
COUNT(*) FILTER (WHERE c.action = 'user.performed_code_search') AS code_searches,
COUNT(*) FILTER (WHERE c.action IN ('user.performed_find_references', 'user.performed_goto_definition')) AS navigations,
COUNT(*) FILTER (WHERE c.action = 'user.created_ask_chat') AS ask_chats,
COUNT(DISTINCT c."actorId") AS active_users
FROM core c
JOIN LATERAL (
SELECT unnest(array['day', 'week', 'month']) AS period
) b ON true
GROUP BY b.period, bucket
)
SELECT
b.period,
b.bucket,
COALESCE(a.code_searches, 0)::int AS code_searches,
COALESCE(a.navigations, 0)::int AS navigations,
COALESCE(a.ask_chats, 0)::int AS ask_chats,
COALESCE(a.active_users, 0)::int AS active_users
FROM buckets b
LEFT JOIN aggregated a
ON a.period = b.period AND a.bucket = b.bucket
ORDER BY b.period, b.bucket;
`;
return rows;
}, /* minRequiredRole = */ OrgRole.MEMBER), /* allowAnonymousAccess = */ true, apiKey ? { apiKey, domain } : undefined)
);