feat: add delete button

This commit is contained in:
moonrailgun 2023-09-06 14:14:12 +08:00
parent bc06258a1d
commit 066c9e8895
7 changed files with 132 additions and 46 deletions

View File

@ -53,6 +53,15 @@ export async function updateWorkspaceWebsiteInfo(
queryClient.resetQueries(['websites', workspaceId]);
}
export async function deleteWorkspaceWebsite(
workspaceId: string,
websiteId: string
) {
await request.delete(`/api/workspace/${workspaceId}/website/${websiteId}`);
queryClient.resetQueries(['websites', workspaceId]);
}
export function useWorspaceWebsites(workspaceId: string) {
const { data: websites = [], isLoading } = useQuery(
['websites', workspaceId],

View File

@ -9,10 +9,7 @@ function createRequest() {
const ins = axios.create();
ins.interceptors.request.use(async (val) => {
if (
['post', 'get'].includes(String(val.method).toLowerCase()) &&
!val.headers.Authorization
) {
if (!val.headers.Authorization) {
val.headers.Authorization = `Bearer ${getJWT()}`;
}

View File

@ -1,7 +1,8 @@
import { Button, Form, Input, message } from 'antd';
import { Button, Form, Input, message, Popconfirm, Tabs } from 'antd';
import React from 'react';
import { useParams } from 'react-router';
import { useNavigate, useParams } from 'react-router';
import {
deleteWorkspaceWebsite,
updateWorkspaceWebsiteInfo,
useWorkspaceWebsiteInfo,
} from '../api/model/website';
@ -20,6 +21,7 @@ export const WebsiteInfo: React.FC = React.memo(() => {
currentWorkspaceId!,
websiteId!
);
const navigate = useNavigate();
const [, handleSave] = useRequest(
async (values: { name: string; domain: string }) => {
@ -32,6 +34,14 @@ export const WebsiteInfo: React.FC = React.memo(() => {
}
);
const [, handleDeleteWebsite] = useRequest(async () => {
await deleteWorkspaceWebsite(currentWorkspaceId!, websiteId!);
message.success('Delete Success');
navigate('/settings/websites');
});
if (!currentWorkspaceId) {
return <NoWorkspaceTip />;
}
@ -55,31 +65,50 @@ export const WebsiteInfo: React.FC = React.memo(() => {
</div>
<div>
<Form
layout="vertical"
initialValues={{
id: website.id,
name: website.name,
domain: website.domain,
}}
onFinish={handleSave}
>
<Form.Item label="Website ID" name="id">
<Input size="large" disabled={true} />
</Form.Item>
<Form.Item label="Name" name="name" rules={[{ required: true }]}>
<Input size="large" />
</Form.Item>
<Form.Item label="Domain" name="domain" rules={[{ required: true }]}>
<Input size="large" />
</Form.Item>
<Tabs>
<Tabs.TabPane key={'detail'} tab={'Detail'}>
<Form
layout="vertical"
initialValues={{
id: website.id,
name: website.name,
domain: website.domain,
}}
onFinish={handleSave}
>
<Form.Item label="Website ID" name="id">
<Input size="large" disabled={true} />
</Form.Item>
<Form.Item label="Name" name="name" rules={[{ required: true }]}>
<Input size="large" />
</Form.Item>
<Form.Item
label="Domain"
name="domain"
rules={[{ required: true }]}
>
<Input size="large" />
</Form.Item>
<Form.Item>
<Button size="large" htmlType="submit">
Save
</Button>
</Form.Item>
</Form>
<Form.Item>
<Button size="large" htmlType="submit">
Save
</Button>
</Form.Item>
</Form>
</Tabs.TabPane>
<Tabs.TabPane key={'data'} tab={'Data'}>
<Popconfirm
title="Delete Website"
onConfirm={() => handleDeleteWebsite()}
>
<Button type="primary" danger={true}>
Delete Website
</Button>
</Popconfirm>
</Tabs.TabPane>
</Tabs>
</div>
</div>
);

View File

@ -34,7 +34,6 @@ export const Settings: React.FC = React.memo(() => {
mode="vertical"
items={items}
/>
{pathname}
</div>
<div className="w-full md:w-5/6 py-2 px-4">
<Routes>

View File

@ -1,7 +1,7 @@
import { Handler } from 'express';
import { checkIsWorkspaceUser } from '../model/workspace';
import { getWorkspaceUser } from '../model/workspace';
export function workspacePermission(): Handler {
export function workspacePermission(roles: string[] = []): Handler {
return async (req, res, next) => {
const workspaceId =
req.body.workspaceId ?? req.query.workspaceId ?? req.params.workspaceId;
@ -16,12 +16,20 @@ export function workspacePermission(): Handler {
throw new Error('This middleware should be use after auth()');
}
const isWorkspaceUser = await checkIsWorkspaceUser(workspaceId, userId);
const info = await getWorkspaceUser(workspaceId, userId);
if (!isWorkspaceUser) {
if (!info) {
throw new Error('Is not workspace user');
}
if (Array.isArray(roles) && roles.length > 0) {
if (!roles.includes(info.role)) {
throw new Error(
`Workspace roles not has this permission, need ${roles}`
);
}
}
next();
};
}

View File

@ -1,21 +1,23 @@
import { prisma } from './_client';
export async function getWorkspaceUser(workspaceId: string, userId: string) {
const info = await prisma.workspacesOnUsers.findFirst({
where: {
workspaceId,
userId,
},
});
return info;
}
export async function checkIsWorkspaceUser(
workspaceId: string,
userId: string
) {
const workspace = await prisma.workspace.findUnique({
where: {
id: workspaceId,
users: {
some: {
userId,
},
},
},
});
const info = await getWorkspaceUser(workspaceId, userId);
if (workspace) {
if (info) {
return true;
} else {
return false;
@ -84,3 +86,17 @@ export async function addWorkspaceWebsite(
return website;
}
export async function deleteWorkspaceWebsite(
workspaceId: string,
websiteId: string
) {
const website = await prisma.website.delete({
where: {
id: websiteId,
workspaceId,
},
});
return website;
}

View File

@ -4,10 +4,12 @@ import { body, param, query, validate } from '../middleware/validate';
import { workspacePermission } from '../middleware/workspace';
import {
addWorkspaceWebsite,
deleteWorkspaceWebsite,
getWorkspaceWebsiteInfo,
getWorkspaceWebsites,
updateWorkspaceWebsiteInfo,
} from '../model/workspace';
import { ROLES } from '../utils/const';
export const workspaceRouter = Router();
@ -128,3 +130,29 @@ workspaceRouter.post(
res.json({ website });
}
);
workspaceRouter.delete(
'/:workspaceId/website/:websiteId',
validate(
param('workspaceId')
.isString()
.withMessage('workspaceId should be string')
.isUUID()
.withMessage('workspaceId should be UUID'),
param('websiteId')
.isString()
.withMessage('workspaceId should be string')
.isUUID()
.withMessage('workspaceId should be UUID')
),
auth(),
workspacePermission([ROLES.owner]),
async (req, res) => {
const workspaceId = req.params.workspaceId;
const websiteId = req.params.websiteId;
const website = await deleteWorkspaceWebsite(workspaceId, websiteId);
res.json({ website });
}
);