feat: telemetry add workspaceId and eventName
This commit is contained in:
parent
bd15e47765
commit
66f713e8f6
@ -106,7 +106,6 @@ model WebsiteEvent {
|
|||||||
id String @id() @default(uuid()) @db.Uuid
|
id String @id() @default(uuid()) @db.Uuid
|
||||||
websiteId String @db.Uuid
|
websiteId String @db.Uuid
|
||||||
sessionId String @db.Uuid
|
sessionId String @db.Uuid
|
||||||
createdAt DateTime? @default(now()) @db.Timestamptz(6)
|
|
||||||
urlPath String @db.VarChar(500)
|
urlPath String @db.VarChar(500)
|
||||||
urlQuery String? @db.VarChar(500)
|
urlQuery String? @db.VarChar(500)
|
||||||
referrerPath String? @db.VarChar(500)
|
referrerPath String? @db.VarChar(500)
|
||||||
@ -115,6 +114,7 @@ model WebsiteEvent {
|
|||||||
pageTitle String? @db.VarChar(500)
|
pageTitle String? @db.VarChar(500)
|
||||||
eventType Int @default(1) @db.Integer
|
eventType Int @default(1) @db.Integer
|
||||||
eventName String? @db.VarChar(50)
|
eventName String? @db.VarChar(50)
|
||||||
|
createdAt DateTime? @default(now()) @db.Timestamptz(6)
|
||||||
|
|
||||||
eventData WebsiteEventData[]
|
eventData WebsiteEventData[]
|
||||||
session WebsiteSession @relation(fields: [sessionId], references: [id])
|
session WebsiteSession @relation(fields: [sessionId], references: [id])
|
||||||
@ -173,6 +173,7 @@ model WebsiteSessionData {
|
|||||||
|
|
||||||
model TelemetrySession {
|
model TelemetrySession {
|
||||||
id String @id @unique @db.Uuid
|
id String @id @unique @db.Uuid
|
||||||
|
workspaceId String @db.Uuid
|
||||||
hostname String? @db.VarChar(100)
|
hostname String? @db.VarChar(100)
|
||||||
browser String? @db.VarChar(20)
|
browser String? @db.VarChar(20)
|
||||||
os String? @db.VarChar(20)
|
os String? @db.VarChar(20)
|
||||||
@ -185,17 +186,22 @@ model TelemetrySession {
|
|||||||
telemetryEvent TelemetryEvent[]
|
telemetryEvent TelemetryEvent[]
|
||||||
|
|
||||||
@@index([createdAt])
|
@@index([createdAt])
|
||||||
|
@@index([workspaceId, createdAt])
|
||||||
}
|
}
|
||||||
|
|
||||||
model TelemetryEvent {
|
model TelemetryEvent {
|
||||||
id String @id() @default(uuid()) @db.Uuid
|
id String @id() @default(uuid()) @db.Uuid
|
||||||
sessionId String @db.Uuid
|
sessionId String @db.Uuid
|
||||||
createdAt DateTime? @default(now()) @db.Timestamptz(6)
|
workspaceId String @db.Uuid
|
||||||
|
eventName String? @db.VarChar(100)
|
||||||
urlOrigin String @db.VarChar(500)
|
urlOrigin String @db.VarChar(500)
|
||||||
urlPath String @db.VarChar(500)
|
urlPath String @db.VarChar(500)
|
||||||
|
createdAt DateTime? @default(now()) @db.Timestamptz(6)
|
||||||
|
|
||||||
session TelemetrySession @relation(fields: [sessionId], references: [id])
|
session TelemetrySession @relation(fields: [sessionId], references: [id])
|
||||||
|
|
||||||
@@index([createdAt])
|
@@index([createdAt])
|
||||||
@@index([sessionId])
|
@@index([sessionId])
|
||||||
|
@@index([workspaceId])
|
||||||
|
@@index([workspaceId, createdAt])
|
||||||
}
|
}
|
||||||
|
@ -9,17 +9,25 @@ export async function recordTelemetryEvent(req: Request) {
|
|||||||
if (!(url && typeof url === 'string')) {
|
if (!(url && typeof url === 'string')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const eventName = req.query.name ? String(req.query.name) : undefined;
|
||||||
|
|
||||||
const session = await findSession(req, url);
|
const session = await findSession(req, url);
|
||||||
if (!session) {
|
if (!session) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const workspaceId = req.params.workspaceId;
|
||||||
|
if (!workspaceId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { origin, pathname } = new URL(url);
|
const { origin, pathname } = new URL(url);
|
||||||
|
|
||||||
await prisma.telemetryEvent.create({
|
await prisma.telemetryEvent.create({
|
||||||
data: {
|
data: {
|
||||||
sessionId: session.id,
|
sessionId: session.id,
|
||||||
|
workspaceId,
|
||||||
|
eventName,
|
||||||
urlOrigin: origin,
|
urlOrigin: origin,
|
||||||
urlPath: pathname,
|
urlPath: pathname,
|
||||||
},
|
},
|
||||||
@ -32,10 +40,19 @@ export async function sumTelemetryEvent(req: Request): Promise<number> {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const eventName = req.query.name ? String(req.query.name) : undefined;
|
||||||
|
|
||||||
|
const workspaceId = req.params.workspaceId;
|
||||||
|
if (!workspaceId) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const { origin, pathname } = new URL(url);
|
const { origin, pathname } = new URL(url);
|
||||||
|
|
||||||
const number = await prisma.telemetryEvent.count({
|
const number = await prisma.telemetryEvent.count({
|
||||||
where: {
|
where: {
|
||||||
|
workspaceId,
|
||||||
|
eventName,
|
||||||
urlOrigin: origin,
|
urlOrigin: origin,
|
||||||
urlPath: pathname,
|
urlPath: pathname,
|
||||||
},
|
},
|
||||||
@ -46,6 +63,10 @@ export async function sumTelemetryEvent(req: Request): Promise<number> {
|
|||||||
|
|
||||||
async function findSession(req: Request, url: string) {
|
async function findSession(req: Request, url: string) {
|
||||||
const { hostname } = new URL(url);
|
const { hostname } = new URL(url);
|
||||||
|
const workspaceId = req.params.workspaceId;
|
||||||
|
if (!workspaceId) {
|
||||||
|
throw new Error('Not found workspaceId');
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
userAgent,
|
userAgent,
|
||||||
@ -58,7 +79,7 @@ async function findSession(req: Request, url: string) {
|
|||||||
city,
|
city,
|
||||||
} = await getRequestInfo(req);
|
} = await getRequestInfo(req);
|
||||||
|
|
||||||
const sessionId = hashUuid(hostname, ip, userAgent!);
|
const sessionId = hashUuid(workspaceId, hostname, ip, userAgent!);
|
||||||
|
|
||||||
let session = await loadSession(sessionId);
|
let session = await loadSession(sessionId);
|
||||||
if (!session) {
|
if (!session) {
|
||||||
@ -66,6 +87,7 @@ async function findSession(req: Request, url: string) {
|
|||||||
session = await prisma.telemetrySession.create({
|
session = await prisma.telemetrySession.create({
|
||||||
data: {
|
data: {
|
||||||
id: sessionId,
|
id: sessionId,
|
||||||
|
workspaceId,
|
||||||
hostname,
|
hostname,
|
||||||
browser,
|
browser,
|
||||||
os,
|
os,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { prisma } from './_client';
|
import { prisma } from './_client';
|
||||||
import { QueryFilters, parseFilters, getDateQuery } from '../utils/prisma';
|
import { QueryFilters, parseFilters, getDateQuery } from '../utils/prisma';
|
||||||
import { DEFAULT_RESET_DATE, EVENT_TYPE } from '../utils/const';
|
import { DEFAULT_RESET_DATE, EVENT_TYPE } from '../utils/const';
|
||||||
import { Prisma } from '@prisma/client';
|
|
||||||
|
|
||||||
export async function getWorkspaceUser(workspaceId: string, userId: string) {
|
export async function getWorkspaceUser(workspaceId: string, userId: string) {
|
||||||
const info = await prisma.workspacesOnUsers.findFirst({
|
const info = await prisma.workspacesOnUsers.findFirst({
|
||||||
@ -27,6 +26,14 @@ export async function checkIsWorkspaceUser(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getWorkspace(workspaceId: string) {
|
||||||
|
return prisma.workspace.findUnique({
|
||||||
|
where: {
|
||||||
|
id: workspaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function getWorkspaceWebsites(workspaceId: string) {
|
export async function getWorkspaceWebsites(workspaceId: string) {
|
||||||
const workspace = await prisma.workspace.findUnique({
|
const workspace = await prisma.workspace.findUnique({
|
||||||
where: {
|
where: {
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
import { Router } from 'express';
|
import { Router } from 'express';
|
||||||
|
import { query, validate } from '../middleware/validate';
|
||||||
import { recordTelemetryEvent, sumTelemetryEvent } from '../model/telemetry';
|
import { recordTelemetryEvent, sumTelemetryEvent } from '../model/telemetry';
|
||||||
import { numify } from '../utils/common';
|
import { numify } from '../utils/common';
|
||||||
const openBadge = require('openbadge');
|
const openBadge = require('openbadge');
|
||||||
|
|
||||||
export const telemetryRouter = Router();
|
export const telemetryRouter = Router();
|
||||||
|
|
||||||
telemetryRouter.get('/blank.gif', async (req, res) => {
|
telemetryRouter.get(
|
||||||
|
'/:workspaceId/blank.gif',
|
||||||
|
validate(
|
||||||
|
query('name').optional().isString(),
|
||||||
|
query('url').optional().isURL()
|
||||||
|
),
|
||||||
|
async (req, res) => {
|
||||||
const buffer = Buffer.from(
|
const buffer = Buffer.from(
|
||||||
'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
|
'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
|
||||||
'base64'
|
'base64'
|
||||||
@ -14,9 +21,16 @@ telemetryRouter.get('/blank.gif', async (req, res) => {
|
|||||||
recordTelemetryEvent(req);
|
recordTelemetryEvent(req);
|
||||||
|
|
||||||
res.header('Content-Type', 'image/gif').send(buffer);
|
res.header('Content-Type', 'image/gif').send(buffer);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
telemetryRouter.get('/badge.svg', async (req, res) => {
|
telemetryRouter.get(
|
||||||
|
'/:workspaceId/badge.svg',
|
||||||
|
validate(
|
||||||
|
query('name').optional().isString(),
|
||||||
|
query('url').optional().isURL()
|
||||||
|
),
|
||||||
|
async (req, res) => {
|
||||||
const title = req.query.title || 'visitor';
|
const title = req.query.title || 'visitor';
|
||||||
const start = req.query.start ? Number(req.query.start) : 0;
|
const start = req.query.start ? Number(req.query.start) : 0;
|
||||||
|
|
||||||
@ -39,4 +53,5 @@ telemetryRouter.get('/badge.svg', async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
res.header('Content-Type', 'image/svg+xml').send(svg);
|
res.header('Content-Type', 'image/svg+xml').send(svg);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user