feat: add feed endpoint
This commit is contained in:
parent
c6747073b1
commit
f459c6beea
@ -47,7 +47,7 @@ export const OpenAPI: OpenAPIConfig = {
|
||||
PASSWORD: undefined,
|
||||
TOKEN: undefined,
|
||||
USERNAME: undefined,
|
||||
VERSION: '1.9.3',
|
||||
VERSION: '1.11.4',
|
||||
WITH_CREDENTIALS: false,
|
||||
interceptors: {
|
||||
request: new Interceptors(),
|
||||
|
@ -51,21 +51,6 @@ export class UserService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns unknown Successful response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static userRegister(data: $OpenApiTs['/register']['post']['req']): CancelablePromise<$OpenApiTs['/register']['post']['res'][200]> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/register',
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json'
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class WorkspaceService {
|
||||
@ -123,6 +108,23 @@ export class WebsiteService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data The data for the request.
|
||||
* @param data.workspaceId
|
||||
* @returns number Successful response
|
||||
* @returns unknown Error response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static websiteAllOverview(data: $OpenApiTs['/workspace/{workspaceId}/website/allOverview']['get']['req']): CancelablePromise<$OpenApiTs['/workspace/{workspaceId}/website/allOverview']['get']['res'][200] | $OpenApiTs['/workspace/{workspaceId}/website/allOverview']['get']['res'][200]> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
url: '/workspace/{workspaceId}/website/allOverview',
|
||||
path: {
|
||||
workspaceId: data.workspaceId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data The data for the request.
|
||||
* @param data.workspaceId
|
||||
@ -1076,6 +1078,8 @@ export class SurveyService {
|
||||
* @param data.surveyId
|
||||
* @param data.limit
|
||||
* @param data.cursor
|
||||
* @param data.startAt
|
||||
* @param data.endAt
|
||||
* @returns unknown Successful response
|
||||
* @throws ApiError
|
||||
*/
|
||||
@ -1089,7 +1093,9 @@ export class SurveyService {
|
||||
},
|
||||
query: {
|
||||
limit: data.limit,
|
||||
cursor: data.cursor
|
||||
cursor: data.cursor,
|
||||
startAt: data.startAt,
|
||||
endAt: data.endAt
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1142,4 +1148,41 @@ export class BillingService {
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class FeedService {
|
||||
/**
|
||||
* @param data The data for the request.
|
||||
* @param data.workspaceId
|
||||
* @returns unknown Successful response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static feedChannels(data: $OpenApiTs['/workspace/{workspaceId}/feed/channels']['get']['req']): CancelablePromise<$OpenApiTs['/workspace/{workspaceId}/feed/channels']['get']['res'][200]> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
url: '/workspace/{workspaceId}/feed/channels',
|
||||
path: {
|
||||
workspaceId: data.workspaceId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param data The data for the request.
|
||||
* @param data.workspaceId
|
||||
* @param data.channelId
|
||||
* @returns unknown Successful response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static feedEvents(data: $OpenApiTs['/workspace/{workspaceId}/feed/{channelId}/events']['get']['req']): CancelablePromise<$OpenApiTs['/workspace/{workspaceId}/feed/{channelId}/events']['get']['res'][200]> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
url: '/workspace/{workspaceId}/feed/{channelId}/events',
|
||||
path: {
|
||||
workspaceId: data.workspaceId,
|
||||
channelId: data.channelId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -104,49 +104,6 @@ export type $OpenApiTs = {
|
||||
};
|
||||
};
|
||||
};
|
||||
'/register': {
|
||||
post: {
|
||||
req: {
|
||||
requestBody: {
|
||||
username: string;
|
||||
password: string;
|
||||
};
|
||||
};
|
||||
res: {
|
||||
/**
|
||||
* Successful response
|
||||
*/
|
||||
200: {
|
||||
info: {
|
||||
username: string;
|
||||
id: string;
|
||||
role: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string | null;
|
||||
currentWorkspace: {
|
||||
id: string;
|
||||
name: string;
|
||||
dashboardLayout: {
|
||||
layouts: {
|
||||
[key: string]: (unknown[]);
|
||||
};
|
||||
items: unknown[];
|
||||
} | null;
|
||||
};
|
||||
workspaces: Array<{
|
||||
role: string;
|
||||
workspace: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
token: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
'/workspace/{workspaceId}/getServiceCount': {
|
||||
get: {
|
||||
req: {
|
||||
@ -211,6 +168,25 @@ export type $OpenApiTs = {
|
||||
};
|
||||
};
|
||||
};
|
||||
'/workspace/{workspaceId}/website/allOverview': {
|
||||
get: {
|
||||
req: {
|
||||
workspaceId: string;
|
||||
};
|
||||
res: {
|
||||
/**
|
||||
* Error response
|
||||
*/
|
||||
200: {
|
||||
message: string;
|
||||
code: string;
|
||||
issues?: Array<{
|
||||
message: string;
|
||||
}>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
'/workspace/{workspaceId}/website/{websiteId}/info': {
|
||||
get: {
|
||||
req: {
|
||||
@ -345,7 +321,7 @@ export type $OpenApiTs = {
|
||||
region?: string;
|
||||
startAt: number;
|
||||
title?: string;
|
||||
type: 'url' | 'language' | 'referrer' | 'browser' | 'os' | 'device' | 'country' | 'event';
|
||||
type: 'url' | 'language' | 'referrer' | 'title' | 'browser' | 'os' | 'device' | 'country' | 'event';
|
||||
url?: string;
|
||||
websiteId: string;
|
||||
workspaceId: string;
|
||||
@ -1319,7 +1295,9 @@ export type $OpenApiTs = {
|
||||
get: {
|
||||
req: {
|
||||
cursor?: string;
|
||||
endAt?: number;
|
||||
limit?: number;
|
||||
startAt?: number;
|
||||
surveyId: string;
|
||||
workspaceId: string;
|
||||
};
|
||||
@ -1397,4 +1375,52 @@ export type $OpenApiTs = {
|
||||
};
|
||||
};
|
||||
};
|
||||
'/workspace/{workspaceId}/feed/channels': {
|
||||
get: {
|
||||
req: {
|
||||
workspaceId: string;
|
||||
};
|
||||
res: {
|
||||
/**
|
||||
* Successful response
|
||||
*/
|
||||
200: Array<{
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
name: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
_count: {
|
||||
events: number;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
};
|
||||
};
|
||||
'/workspace/{workspaceId}/feed/{channelId}/events': {
|
||||
get: {
|
||||
req: {
|
||||
channelId: string;
|
||||
workspaceId: string;
|
||||
};
|
||||
res: {
|
||||
/**
|
||||
* Successful response
|
||||
*/
|
||||
200: Array<{
|
||||
id: string;
|
||||
channelId: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
eventName: string;
|
||||
eventContent: string;
|
||||
tags: Array<(string)>;
|
||||
source: string;
|
||||
senderId?: string | null;
|
||||
senderName?: string | null;
|
||||
important: boolean;
|
||||
}>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,39 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "FeedChannel" (
|
||||
"id" VARCHAR(30) NOT NULL,
|
||||
"workspaceId" VARCHAR(30) NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMPTZ(6) NOT NULL,
|
||||
|
||||
CONSTRAINT "FeedChannel_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "FeedEvent" (
|
||||
"id" VARCHAR(30) NOT NULL,
|
||||
"channelId" VARCHAR(30) NOT NULL,
|
||||
"createdAt" TIMESTAMPTZ(6) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMPTZ(6) NOT NULL,
|
||||
"eventName" TEXT NOT NULL,
|
||||
"eventContent" TEXT NOT NULL,
|
||||
"tags" TEXT[],
|
||||
"source" TEXT NOT NULL,
|
||||
"senderId" TEXT,
|
||||
"senderName" TEXT,
|
||||
"important" BOOLEAN NOT NULL,
|
||||
|
||||
CONSTRAINT "FeedEvent_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FeedChannel_workspaceId_idx" ON "FeedChannel"("workspaceId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "FeedEvent_channelId_idx" ON "FeedEvent"("channelId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FeedChannel" ADD CONSTRAINT "FeedChannel_workspaceId_fkey" FOREIGN KEY ("workspaceId") REFERENCES "Workspace"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "FeedEvent" ADD CONSTRAINT "FeedEvent_channelId_fkey" FOREIGN KEY ("channelId") REFERENCES "FeedChannel"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -56,6 +56,7 @@ model Workspace {
|
||||
workspaceDailyUsage WorkspaceDailyUsage[]
|
||||
workspaceAuditLog WorkspaceAuditLog[]
|
||||
surveys Survey[]
|
||||
feedChannels FeedChannel[]
|
||||
}
|
||||
|
||||
model WorkspacesOnUsers {
|
||||
@ -438,9 +439,39 @@ model SurveyResult {
|
||||
latitude Float?
|
||||
accuracyRadius Int?
|
||||
|
||||
|
||||
survey Survey @relation(fields: [surveyId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
|
||||
@@index([surveyId])
|
||||
@@index([sessionId])
|
||||
}
|
||||
|
||||
model FeedChannel {
|
||||
id String @id @default(cuid()) @db.VarChar(30)
|
||||
workspaceId String @db.VarChar(30)
|
||||
name String
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(6)
|
||||
|
||||
workspace Workspace @relation(fields: [workspaceId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
events FeedEvent[]
|
||||
|
||||
@@index([workspaceId])
|
||||
}
|
||||
|
||||
model FeedEvent {
|
||||
id String @id @default(cuid()) @db.VarChar(30)
|
||||
channelId String @db.VarChar(30)
|
||||
createdAt DateTime @default(now()) @db.Timestamptz(6)
|
||||
updatedAt DateTime @updatedAt @db.Timestamptz(6)
|
||||
eventName String
|
||||
eventContent String
|
||||
tags String[]
|
||||
source String // custom text or third-party integrations
|
||||
senderId String? // maybe user id
|
||||
senderName String? // use for display who
|
||||
important Boolean
|
||||
|
||||
channel FeedChannel @relation(fields: [channelId], references: [id], onUpdate: Cascade, onDelete: Cascade)
|
||||
|
||||
@@index([channelId])
|
||||
}
|
||||
|
26
src/server/prisma/zod/feedchannel.ts
Normal file
26
src/server/prisma/zod/feedchannel.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import * as z from "zod"
|
||||
import * as imports from "./schemas"
|
||||
import { CompleteWorkspace, RelatedWorkspaceModelSchema, CompleteFeedEvent, RelatedFeedEventModelSchema } from "./index"
|
||||
|
||||
export const FeedChannelModelSchema = z.object({
|
||||
id: z.string(),
|
||||
workspaceId: z.string(),
|
||||
name: z.string(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
})
|
||||
|
||||
export interface CompleteFeedChannel extends z.infer<typeof FeedChannelModelSchema> {
|
||||
workspace: CompleteWorkspace
|
||||
events: CompleteFeedEvent[]
|
||||
}
|
||||
|
||||
/**
|
||||
* RelatedFeedChannelModelSchema contains all relations on your model in addition to the scalars
|
||||
*
|
||||
* NOTE: Lazy required in case of potential circular dependencies within schema
|
||||
*/
|
||||
export const RelatedFeedChannelModelSchema: z.ZodSchema<CompleteFeedChannel> = z.lazy(() => FeedChannelModelSchema.extend({
|
||||
workspace: RelatedWorkspaceModelSchema,
|
||||
events: RelatedFeedEventModelSchema.array(),
|
||||
}))
|
30
src/server/prisma/zod/feedevent.ts
Normal file
30
src/server/prisma/zod/feedevent.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import * as z from "zod"
|
||||
import * as imports from "./schemas"
|
||||
import { CompleteFeedChannel, RelatedFeedChannelModelSchema } from "./index"
|
||||
|
||||
export const FeedEventModelSchema = z.object({
|
||||
id: z.string(),
|
||||
channelId: z.string(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
eventName: z.string(),
|
||||
eventContent: z.string(),
|
||||
tags: z.string().array(),
|
||||
source: z.string(),
|
||||
senderId: z.string().nullish(),
|
||||
senderName: z.string().nullish(),
|
||||
important: z.boolean(),
|
||||
})
|
||||
|
||||
export interface CompleteFeedEvent extends z.infer<typeof FeedEventModelSchema> {
|
||||
channel: CompleteFeedChannel
|
||||
}
|
||||
|
||||
/**
|
||||
* RelatedFeedEventModelSchema contains all relations on your model in addition to the scalars
|
||||
*
|
||||
* NOTE: Lazy required in case of potential circular dependencies within schema
|
||||
*/
|
||||
export const RelatedFeedEventModelSchema: z.ZodSchema<CompleteFeedEvent> = z.lazy(() => FeedEventModelSchema.extend({
|
||||
channel: RelatedFeedChannelModelSchema,
|
||||
}))
|
@ -19,3 +19,5 @@ export * from "./workspacedailyusage"
|
||||
export * from "./workspaceauditlog"
|
||||
export * from "./survey"
|
||||
export * from "./surveyresult"
|
||||
export * from "./feedchannel"
|
||||
export * from "./feedevent"
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as z from "zod"
|
||||
import * as imports from "./schemas"
|
||||
import { CompleteWorkspacesOnUsers, RelatedWorkspacesOnUsersModelSchema, CompleteWebsite, RelatedWebsiteModelSchema, CompleteNotification, RelatedNotificationModelSchema, CompleteMonitor, RelatedMonitorModelSchema, CompleteMonitorStatusPage, RelatedMonitorStatusPageModelSchema, CompleteTelemetry, RelatedTelemetryModelSchema, CompleteUser, RelatedUserModelSchema, CompleteWorkspaceDailyUsage, RelatedWorkspaceDailyUsageModelSchema, CompleteWorkspaceAuditLog, RelatedWorkspaceAuditLogModelSchema, CompleteSurvey, RelatedSurveyModelSchema } from "./index"
|
||||
import { CompleteWorkspacesOnUsers, RelatedWorkspacesOnUsersModelSchema, CompleteWebsite, RelatedWebsiteModelSchema, CompleteNotification, RelatedNotificationModelSchema, CompleteMonitor, RelatedMonitorModelSchema, CompleteMonitorStatusPage, RelatedMonitorStatusPageModelSchema, CompleteTelemetry, RelatedTelemetryModelSchema, CompleteUser, RelatedUserModelSchema, CompleteWorkspaceDailyUsage, RelatedWorkspaceDailyUsageModelSchema, CompleteWorkspaceAuditLog, RelatedWorkspaceAuditLogModelSchema, CompleteSurvey, RelatedSurveyModelSchema, CompleteFeedChannel, RelatedFeedChannelModelSchema } from "./index"
|
||||
|
||||
// Helper schema for JSON fields
|
||||
type Literal = boolean | number | string
|
||||
@ -35,6 +35,7 @@ export interface CompleteWorkspace extends z.infer<typeof WorkspaceModelSchema>
|
||||
workspaceDailyUsage: CompleteWorkspaceDailyUsage[]
|
||||
workspaceAuditLog: CompleteWorkspaceAuditLog[]
|
||||
surveys: CompleteSurvey[]
|
||||
feedChannels: CompleteFeedChannel[]
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,4 +54,5 @@ export const RelatedWorkspaceModelSchema: z.ZodSchema<CompleteWorkspace> = z.laz
|
||||
workspaceDailyUsage: RelatedWorkspaceDailyUsageModelSchema.array(),
|
||||
workspaceAuditLog: RelatedWorkspaceAuditLogModelSchema.array(),
|
||||
surveys: RelatedSurveyModelSchema.array(),
|
||||
feedChannels: RelatedFeedChannelModelSchema.array(),
|
||||
}))
|
||||
|
81
src/server/trpc/routers/feed.ts
Normal file
81
src/server/trpc/routers/feed.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { z } from 'zod';
|
||||
import { OpenApiMetaInfo, router, workspaceProcedure } from '../trpc';
|
||||
import { OPENAPI_TAG } from '../../utils/const';
|
||||
import { OpenApiMeta } from 'trpc-openapi';
|
||||
import { FeedChannelModelSchema, FeedEventModelSchema } from '../../prisma/zod';
|
||||
import { prisma } from '../../model/_client';
|
||||
|
||||
export const feedRouter = router({
|
||||
channels: workspaceProcedure
|
||||
.meta(
|
||||
buildFeedOpenapi({
|
||||
method: 'GET',
|
||||
path: '/channels',
|
||||
})
|
||||
)
|
||||
.input(z.object({}))
|
||||
.output(
|
||||
z.array(
|
||||
FeedChannelModelSchema.merge(
|
||||
z.object({
|
||||
_count: z.object({
|
||||
events: z.number(),
|
||||
}),
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const { workspaceId } = input;
|
||||
|
||||
const channels = await prisma.feedChannel.findMany({
|
||||
where: {
|
||||
workspaceId,
|
||||
},
|
||||
include: {
|
||||
_count: {
|
||||
select: {
|
||||
events: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return channels;
|
||||
}),
|
||||
events: workspaceProcedure
|
||||
.meta(
|
||||
buildFeedOpenapi({
|
||||
method: 'GET',
|
||||
path: '/{channelId}/events',
|
||||
})
|
||||
)
|
||||
.input(
|
||||
z.object({
|
||||
channelId: z.string(),
|
||||
})
|
||||
)
|
||||
.output(z.array(FeedEventModelSchema))
|
||||
.query(async ({ input }) => {
|
||||
const { channelId } = input;
|
||||
|
||||
const events = await prisma.feedEvent.findMany({
|
||||
where: {
|
||||
channelId: channelId,
|
||||
},
|
||||
});
|
||||
|
||||
return events;
|
||||
}),
|
||||
});
|
||||
|
||||
function buildFeedOpenapi(meta: OpenApiMetaInfo): OpenApiMeta {
|
||||
return {
|
||||
openapi: {
|
||||
tags: [OPENAPI_TAG.FEED],
|
||||
protect: true,
|
||||
...meta,
|
||||
path: `/workspace/{workspaceId}/feed${meta.path}`,
|
||||
},
|
||||
};
|
||||
}
|
@ -10,6 +10,7 @@ import { auditLogRouter } from './auditLog';
|
||||
import { billingRouter } from './billing';
|
||||
import { telemetryRouter } from './telemetry';
|
||||
import { surveyRouter } from './survey';
|
||||
import { feedRouter } from './feed';
|
||||
|
||||
export const appRouter = router({
|
||||
global: globalRouter,
|
||||
@ -23,6 +24,7 @@ export const appRouter = router({
|
||||
serverStatus: serverStatusRouter,
|
||||
auditLog: auditLogRouter,
|
||||
billing: billingRouter,
|
||||
feed: feedRouter,
|
||||
});
|
||||
|
||||
export type AppRouter = typeof appRouter;
|
||||
|
@ -111,4 +111,5 @@ export enum OPENAPI_TAG {
|
||||
BILLING = 'Billing',
|
||||
TELEMETRY = 'Telemetry',
|
||||
SURVEY = 'Survey',
|
||||
FEED = 'Feed',
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user