refactor: db id type replace uuid with cuid

This commit is contained in:
moonrailgun 2023-10-06 00:06:44 +08:00
parent b18611fa9a
commit 7f40a049c8
11 changed files with 71 additions and 63 deletions

@ -12,7 +12,7 @@
<script>
const el = document.createElement('script');
el.src = location.origin + '/tracker.js';
el.setAttribute('data-website-id', '1003c2f3-5cc0-482d-b081-53d8e4858b5d'); // For test
el.setAttribute('data-website-id', 'clndcbgl90003vyf4uarkfl73'); // For test
document.head.append(el);
</script>
</body>

@ -15,6 +15,7 @@
"dependencies": {
"@ant-design/charts": "^1.4.2",
"@ant-design/icons": "^5.2.5",
"@paralleldrive/cuid2": "^2.2.2",
"@prisma/client": "^5.2.0",
"@tanstack/react-query": "^4.33.0",
"@trpc/client": "^10.38.4",

14
pnpm-lock.yaml generated

@ -7,6 +7,9 @@ dependencies:
'@ant-design/icons':
specifier: ^5.2.5
version: 5.2.5(react-dom@18.2.0)(react@18.2.0)
'@paralleldrive/cuid2':
specifier: ^2.2.2
version: 2.2.2
'@prisma/client':
specifier: ^5.2.0
version: 5.2.0(prisma@5.2.0)
@ -1651,6 +1654,11 @@ packages:
engines: {node: '>=6.0.0'}
dev: false
/@noble/hashes@1.3.2:
resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==}
engines: {node: '>= 16'}
dev: false
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@ -1672,6 +1680,12 @@ packages:
fastq: 1.15.0
dev: true
/@paralleldrive/cuid2@2.2.2:
resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}
dependencies:
'@noble/hashes': 1.3.2
dev: false
/@prisma/client@5.2.0(prisma@5.2.0):
resolution: {integrity: sha512-AiTjJwR4J5Rh6Z/9ZKrBBLel3/5DzUNntMohOy7yObVnVoTNVFi2kvpLZlFuKO50d7yDspOtW6XBpiAd0BVXbQ==}
engines: {node: '>=16.13'}

@ -8,14 +8,14 @@ generator client {
}
model User {
id String @id @unique @default(uuid()) @db.Uuid
id String @id @unique @default(cuid()) @db.VarChar(30)
username String @unique @db.VarChar(255)
password String @db.VarChar(60)
role String @db.VarChar(50)
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @updatedAt @db.Timestamptz(6)
deletedAt DateTime? @db.Timestamptz(6)
currentWorkspaceId String? @db.Uuid
currentWorkspaceId String? @db.VarChar(30)
currentWorkspace Workspace? @relation(fields: [currentWorkspaceId], references: [id])
@ -23,7 +23,7 @@ model User {
}
model Workspace {
id String @id @unique @default(uuid()) @db.Uuid
id String @id @unique @default(cuid()) @db.VarChar(30)
name String @db.VarChar(100)
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @updatedAt @db.Timestamptz(6)
@ -38,8 +38,8 @@ model Workspace {
}
model WorkspacesOnUsers {
userId String @db.Uuid
workspaceId String @db.Uuid
userId String @db.VarChar(30)
workspaceId String @db.VarChar(30)
role String @db.VarChar(100)
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @updatedAt @db.Timestamptz(6)
@ -53,12 +53,12 @@ model WorkspacesOnUsers {
}
model Website {
id String @id @unique @default(uuid()) @db.Uuid
id String @id @unique @default(cuid()) @db.VarChar(30)
name String @db.VarChar(100)
domain String? @db.VarChar(500)
shareId String? @unique @db.VarChar(50)
resetAt DateTime? @db.Timestamptz(6)
workspaceId String @db.Uuid
workspaceId String @db.VarChar(30)
createdAt DateTime? @default(now()) @db.Timestamptz(6)
updatedAt DateTime? @updatedAt @db.Timestamptz(6)
deletedAt DateTime? @db.Timestamptz(6)
@ -76,7 +76,7 @@ model Website {
model WebsiteSession {
id String @id @unique @db.Uuid
websiteId String @db.Uuid
websiteId String @db.VarChar(30)
hostname String? @db.VarChar(100)
browser String? @db.VarChar(20)
os String? @db.VarChar(20)
@ -109,8 +109,8 @@ model WebsiteSession {
}
model WebsiteEvent {
id String @id() @default(uuid()) @db.Uuid
websiteId String @db.Uuid
id String @id() @default(cuid()) @db.VarChar(30)
websiteId String @db.VarChar(30)
sessionId String @db.Uuid
urlPath String @db.VarChar(500)
urlQuery String? @db.VarChar(500)
@ -138,9 +138,9 @@ model WebsiteEvent {
}
model WebsiteEventData {
id String @id() @default(uuid()) @db.Uuid
websiteId String @db.Uuid
websiteEventId String @db.Uuid
id String @id() @default(cuid()) @db.VarChar(30)
websiteId String @db.VarChar(30)
websiteEventId String @db.VarChar(30)
eventKey String @db.VarChar(500)
stringValue String? @db.VarChar(500)
numberValue Decimal? @db.Decimal(19, 4)
@ -159,8 +159,8 @@ model WebsiteEventData {
}
model WebsiteSessionData {
id String @id() @default(uuid()) @db.Uuid
websiteId String @db.Uuid
id String @id() @default(cuid()) @db.VarChar(30)
websiteId String @db.VarChar(30)
sessionId String @db.Uuid
stringValue String? @db.VarChar(500)
numberValue Decimal? @db.Decimal(19, 4)
@ -179,7 +179,7 @@ model WebsiteSessionData {
model TelemetrySession {
id String @id @unique @db.Uuid
workspaceId String @db.Uuid
workspaceId String @db.VarChar(30)
hostname String? @db.VarChar(100)
browser String? @db.VarChar(20)
os String? @db.VarChar(20)
@ -196,9 +196,9 @@ model TelemetrySession {
}
model TelemetryEvent {
id String @id() @default(uuid()) @db.Uuid
id String @id() @default(cuid()) @db.VarChar(30)
sessionId String @db.Uuid
workspaceId String @db.Uuid
workspaceId String @db.VarChar(30)
eventName String? @db.VarChar(100)
urlOrigin String @db.VarChar(500)
urlPath String @db.VarChar(500)
@ -213,8 +213,8 @@ model TelemetryEvent {
}
model Notification {
id String @id() @default(uuid()) @db.Uuid
workspaceId String @db.Uuid
id String @id() @default(cuid()) @db.VarChar(30)
workspaceId String @db.VarChar(30)
name String @db.VarChar(100)
type String @db.VarChar(100)
payload Json @db.Json
@ -228,17 +228,17 @@ model Notification {
}
model Monitor {
id String @id() @default(uuid()) @db.Uuid
workspaceId String @db.Uuid
name String @db.VarChar(100)
type String @db.VarChar(100)
active Boolean @default(true) @db.Boolean
interval Int @default(20) @db.Integer
id String @id() @default(cuid()) @db.VarChar(30)
workspaceId String @db.VarChar(30)
name String @db.VarChar(100)
type String @db.VarChar(100)
active Boolean @default(true) @db.Boolean
interval Int @default(20) @db.Integer
// TODO
// maxRetry Int @default(0) @db.Integer
// retryInterval Int @default(0) @db.Integer
payload Json @db.Json
createdAt DateTime? @default(now()) @db.Timestamptz(6)
payload Json @db.Json
createdAt DateTime? @default(now()) @db.Timestamptz(6)
workspace Workspace @relation(fields: [workspaceId], references: [id])
@ -250,9 +250,9 @@ model Monitor {
}
model MonitorEvent {
id String @id @default(uuid()) @db.Uuid
id String @id @default(cuid()) @db.VarChar(30)
message String @db.VarChar(500)
monitorId String @db.Uuid
monitorId String @db.VarChar(30)
type String @db.VarChar(100) // UP or DOWN
createdAt DateTime? @default(now()) @db.Timestamptz(6)
@ -260,8 +260,8 @@ model MonitorEvent {
}
model MonitorData {
id String @id @default(uuid()) @db.Uuid
monitorId String @db.Uuid
id String @id @default(cuid()) @db.VarChar(30)
monitorId String @db.VarChar(30)
value Int @default(0) @db.Integer // -1 means error
createdAt DateTime? @default(now()) @db.Timestamptz(6)

@ -1,5 +1,5 @@
import { Website, WebsiteSession } from '@prisma/client';
import { flattenJSON, hashUuid, isUuid, parseToken } from '../utils/common';
import { flattenJSON, hashUuid, isCuid, parseToken } from '../utils/common';
import { prisma } from './_client';
import { Request } from 'express';
import { getClientInfo } from '../utils/detect';
@ -66,7 +66,7 @@ export async function findSession(req: Request): Promise<{
throw new Error('Invalid hostname.');
}
if (!isUuid(websiteId)) {
if (!isCuid(websiteId)) {
throw new Error('Invalid website ID.');
}
@ -268,7 +268,7 @@ export async function getWebsiteOnlineUserCount(
const res = await prisma.$queryRaw<
Ret[]
>`SELECT count(distinct "sessionId") x FROM "WebsiteEvent" where "websiteId" = ${websiteId}::uuid AND "createdAt" >= ${startAt}`;
>`SELECT count(distinct "sessionId") x FROM "WebsiteEvent" where "websiteId" = ${websiteId} AND "createdAt" >= ${startAt}`;
return res?.[0].x ?? 0;
}

@ -157,7 +157,7 @@ export async function getWorkspaceWebsitePageview(
count(1) y
from "WebsiteEvent"
${joinSession}
where "WebsiteEvent"."websiteId" = ${params.websiteId}::uuid
where "WebsiteEvent"."websiteId" = ${params.websiteId}
and "WebsiteEvent"."createdAt" between ${
params.startDate
}::timestamptz and ${params.endDate}::timestamptz
@ -182,7 +182,7 @@ export async function getWorkspaceWebsiteSession(
count(distinct "WebsiteEvent"."sessionId") y
from "WebsiteEvent"
${joinSession}
where "WebsiteEvent"."websiteId" = ${params.websiteId}::uuid
where "WebsiteEvent"."websiteId" = ${params.websiteId}
and "WebsiteEvent"."createdAt" between ${
params.startDate
}::timestamptz and ${params.endDate}::timestamptz
@ -216,7 +216,7 @@ export async function getWorkspaceWebsiteStats(
join "Website"
on "WebsiteEvent"."websiteId" = "Website"."id"
${joinSession}
where "Website"."id" = ${params.websiteId}::uuid
where "Website"."id" = ${params.websiteId}
and "WebsiteEvent"."createdAt" between ${
params.startDate
}::timestamptz and ${params.endDate}::timestamptz

@ -29,7 +29,7 @@ websiteRouter.post(
screen: yup.string().max(11),
title: yup.string().max(500),
url: yup.string().max(500),
website: yup.string().uuid().required(),
website: yup.string().required(),
name: yup.string().max(50),
})
.required()

@ -22,11 +22,7 @@ export const workspaceRouter = Router();
workspaceRouter.get(
'/websites',
validate(
query('workspaceId')
.isString()
.withMessage('workspaceId should be string')
.isUUID()
.withMessage('workspaceId should be UUID')
query('workspaceId').isString().withMessage('workspaceId should be string')
),
auth(),
workspacePermission(),
@ -42,7 +38,7 @@ workspaceRouter.get(
workspaceRouter.post(
'/website',
validate(
body('workspaceId').isUUID().withMessage('workspaceId should be UUID'),
body('workspaceId').isString(),
body('name')
.isString()
.withMessage('name should be string')
@ -67,10 +63,7 @@ workspaceRouter.post(
workspaceRouter.get(
'/website/:websiteId',
validate(
query('workspaceId').isUUID().withMessage('workspaceId should be UUID'),
param('websiteId').isUUID().withMessage('workspaceId should be UUID')
),
validate(query('workspaceId').isString(), param('websiteId').isString()),
auth(),
workspacePermission(),
async (req, res) => {
@ -86,7 +79,7 @@ workspaceRouter.get(
workspaceRouter.post(
'/website/:websiteId',
validate(
body('workspaceId').isUUID().withMessage('workspaceId should be UUID'),
body('workspaceId').isString(),
param('websiteId')
.isString()
.isUUID()
@ -122,10 +115,7 @@ workspaceRouter.post(
workspaceRouter.delete(
'/:workspaceId/website/:websiteId',
validate(
param('workspaceId').isUUID().withMessage('workspaceId should be UUID'),
param('websiteId').isUUID().withMessage('workspaceId should be UUID')
),
validate(param('workspaceId').isString(), param('websiteId').isString()),
auth(),
workspacePermission([ROLES.owner]),
async (req, res) => {
@ -141,8 +131,8 @@ workspaceRouter.delete(
workspaceRouter.get(
'/:workspaceId/website/:websiteId/pageviews',
validate(
param('workspaceId').isUUID().withMessage('workspaceId should be UUID'),
param('websiteId').isUUID().withMessage('workspaceId should be UUID'),
param('workspaceId').isString(),
param('websiteId').isString(),
query('startAt').isNumeric().withMessage('startAt should be number'),
query('endAt').isNumeric().withMessage('startAt should be number')
),
@ -201,8 +191,8 @@ workspaceRouter.get(
workspaceRouter.get(
'/:workspaceId/website/:websiteId/stats',
validate(
param('workspaceId').isUUID().withMessage('workspaceId should be UUID'),
param('websiteId').isUUID().withMessage('workspaceId should be UUID'),
param('workspaceId').isString(),
param('websiteId').isString(),
query('startAt').isNumeric().withMessage('startAt should be number'),
query('endAt').isNumeric().withMessage('startAt should be number')
),

@ -56,14 +56,14 @@ export const systemAdminProcedure = t.procedure.use(isSystemAdmin);
export const workspaceProcedure = protectProedure
.input(
z.object({
workspaceId: z.string().uuid(),
workspaceId: z.string().cuid2(),
})
)
.use(createWorkspacePermissionMiddleware());
export const workspaceOwnerProcedure = protectProedure
.input(
z.object({
workspaceId: z.string().uuid(),
workspaceId: z.string().cuid2(),
})
)
.use(createWorkspacePermissionMiddleware([ROLES.owner]));

@ -7,6 +7,9 @@ import minMax from 'dayjs/plugin/minMax';
import jwt from 'jsonwebtoken';
import _ from 'lodash';
import { getWorkspaceWebsiteDateRange } from '../model/workspace';
import { isCuid } from '@paralleldrive/cuid2';
export { isCuid };
dayjs.extend(minMax);

@ -2,7 +2,7 @@ import { Server as SocketIOServer } from 'socket.io';
import { Server as HTTPServer } from 'http';
import { jwtVerify } from '../middleware/auth';
import { socketEventBus } from './shared';
import { isUuid } from '../utils/common';
import { isCuid } from '../utils/common';
export function initSocketio(httpServer: HTTPServer) {
const io = new SocketIOServer(httpServer, {
@ -17,7 +17,7 @@ export function initSocketio(httpServer: HTTPServer) {
io.of((name, auth, next) => {
const workspaceId = name.replace(/^\//, '');
next(null, isUuid(workspaceId)); // or false, when the creation is denied
next(null, isCuid(workspaceId)); // or false, when the creation is denied
})
.use(async (socket, next) => {
// Auth