feat: add notification api

This commit is contained in:
moonrailgun 2023-09-26 14:45:28 +08:00
parent 72e3753503
commit b6a26d8777
7 changed files with 106 additions and 17 deletions

View File

@ -30,6 +30,7 @@ model Workspace {
users WorkspacesOnUsers[] users WorkspacesOnUsers[]
websites Website[] websites Website[]
notifications Notification[]
// for user currentWorkspace // for user currentWorkspace
selectedUsers User[] selectedUsers User[]
@ -205,3 +206,16 @@ model TelemetryEvent {
@@index([workspaceId]) @@index([workspaceId])
@@index([workspaceId, createdAt]) @@index([workspaceId, createdAt])
} }
model Notification {
id String @id() @default(uuid()) @db.Uuid
workspaceId String @db.Uuid
name String @db.VarChar(100)
type String @db.VarChar(100)
payload Json @db.Json
createdAt DateTime? @default(now()) @db.Timestamptz(6)
workspace Workspace @relation(fields: [workspaceId], references: [id])
@@index([workspaceId])
}

View File

@ -1,7 +1,8 @@
import { Handler } from 'express'; import { Handler } from 'express';
import { getWorkspaceUser } from '../model/workspace'; import { getWorkspaceUser } from '../model/workspace';
import { ROLES } from '../utils/const';
export function workspacePermission(roles: string[] = []): Handler { export function workspacePermission(roles: ROLES[] = []): Handler {
return async (req, res, next) => { return async (req, res, next) => {
const workspaceId = const workspaceId =
req.body.workspaceId ?? req.query.workspaceId ?? req.params.workspaceId; req.body.workspaceId ?? req.query.workspaceId ?? req.params.workspaceId;
@ -23,7 +24,7 @@ export function workspacePermission(roles: string[] = []): Handler {
} }
if (Array.isArray(roles) && roles.length > 0) { if (Array.isArray(roles) && roles.length > 0) {
if (!roles.includes(info.role)) { if (!roles.includes(info.role as ROLES)) {
throw new Error( throw new Error(
`Workspace roles not has this permission, need ${roles}` `Workspace roles not has this permission, need ${roles}`
); );

View File

@ -0,0 +1,27 @@
import { prisma } from './_client';
export function getWorkspaceNotifications(workspaceId: string) {
return prisma.notification.findMany({
where: {
workspaceId,
},
});
}
export async function createWorkspaceNotification(
workspaceId: string,
name: string,
type: string,
payload: Record<string, any>
) {
const notification = await prisma.notification.create({
data: {
workspaceId,
name,
type,
payload,
},
});
return notification;
}

View File

@ -1,6 +1,6 @@
import { prisma } from './_client'; import { prisma } from './_client';
import bcryptjs from 'bcryptjs'; import bcryptjs from 'bcryptjs';
import { ROLES } from '../utils/const'; import { ROLES, SYSTEM_ROLES } from '../utils/const';
import { jwtVerify } from '../middleware/auth'; import { jwtVerify } from '../middleware/auth';
async function hashPassword(password: string) { async function hashPassword(password: string) {
@ -59,7 +59,7 @@ export async function createAdminUser(username: string, password: string) {
data: { data: {
username, username,
password: await hashPassword(password), password: await hashPassword(password),
role: ROLES.admin, role: SYSTEM_ROLES.admin,
workspaces: { workspaces: {
create: [ create: [
{ {
@ -106,7 +106,7 @@ export async function createUser(username: string, password: string) {
data: { data: {
username, username,
password: await hashPassword(password), password: await hashPassword(password),
role: ROLES.user, role: SYSTEM_ROLES.user,
workspaces: { workspaces: {
create: [ create: [
{ {

View File

@ -195,7 +195,7 @@ export async function getWorkspaceWebsiteSession(
export async function getWorkspaceWebsiteStats( export async function getWorkspaceWebsiteStats(
websiteId: string, websiteId: string,
filters: QueryFilters filters: QueryFilters
): any { ): Promise<any> {
const { filterQuery, joinSession, params } = await parseFilters(websiteId, { const { filterQuery, joinSession, params } = await parseFilters(websiteId, {
...filters, ...filters,
}); });

View File

@ -0,0 +1,47 @@
import { Router } from 'express';
import { auth } from '../middleware/auth';
import { body, param, validate } from '../middleware/validate';
import { workspacePermission } from '../middleware/workspace';
import {
createWorkspaceNotification,
getWorkspaceNotifications,
} from '../model/notification';
import { ROLES } from '../utils/const';
export const notificationRouter = Router();
notificationRouter.get(
'/list',
validate(param('workspaceId').isUUID()),
auth(),
workspacePermission(),
async (req, res) => {
const list = await getWorkspaceNotifications(req.params.workspaceId);
res.json({ list });
}
);
notificationRouter.post(
'/create',
validate(
param('workspaceId').isUUID(),
body('name').isString(),
body('type').isString(),
body('payload').isObject()
),
auth(),
workspacePermission([ROLES.owner]),
async (req, res) => {
const workspaceId = req.params.workspaceId;
const { name, type, payload } = req.body;
const notification = await createWorkspaceNotification(
workspaceId,
name,
type,
payload
);
res.json({ notification });
}
);

View File

@ -1,12 +1,12 @@
export const ROLES = { export enum SYSTEM_ROLES {
// System Role admin = 'admin',
admin: 'admin', user = 'user',
user: 'user', }
// Workspace Role export enum ROLES {
owner: 'owner', owner = 'owner',
readOnly: 'readOnly', readOnly = 'readOnly',
} as const; }
export const HOSTNAME_REGEX = export const HOSTNAME_REGEX =
/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/; /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])$/;