feat: add delete button
This commit is contained in:
parent
bc06258a1d
commit
066c9e8895
@ -53,6 +53,15 @@ export async function updateWorkspaceWebsiteInfo(
|
|||||||
queryClient.resetQueries(['websites', workspaceId]);
|
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) {
|
export function useWorspaceWebsites(workspaceId: string) {
|
||||||
const { data: websites = [], isLoading } = useQuery(
|
const { data: websites = [], isLoading } = useQuery(
|
||||||
['websites', workspaceId],
|
['websites', workspaceId],
|
||||||
|
@ -9,10 +9,7 @@ function createRequest() {
|
|||||||
const ins = axios.create();
|
const ins = axios.create();
|
||||||
|
|
||||||
ins.interceptors.request.use(async (val) => {
|
ins.interceptors.request.use(async (val) => {
|
||||||
if (
|
if (!val.headers.Authorization) {
|
||||||
['post', 'get'].includes(String(val.method).toLowerCase()) &&
|
|
||||||
!val.headers.Authorization
|
|
||||||
) {
|
|
||||||
val.headers.Authorization = `Bearer ${getJWT()}`;
|
val.headers.Authorization = `Bearer ${getJWT()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 React from 'react';
|
||||||
import { useParams } from 'react-router';
|
import { useNavigate, useParams } from 'react-router';
|
||||||
import {
|
import {
|
||||||
|
deleteWorkspaceWebsite,
|
||||||
updateWorkspaceWebsiteInfo,
|
updateWorkspaceWebsiteInfo,
|
||||||
useWorkspaceWebsiteInfo,
|
useWorkspaceWebsiteInfo,
|
||||||
} from '../api/model/website';
|
} from '../api/model/website';
|
||||||
@ -20,6 +21,7 @@ export const WebsiteInfo: React.FC = React.memo(() => {
|
|||||||
currentWorkspaceId!,
|
currentWorkspaceId!,
|
||||||
websiteId!
|
websiteId!
|
||||||
);
|
);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [, handleSave] = useRequest(
|
const [, handleSave] = useRequest(
|
||||||
async (values: { name: string; domain: string }) => {
|
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) {
|
if (!currentWorkspaceId) {
|
||||||
return <NoWorkspaceTip />;
|
return <NoWorkspaceTip />;
|
||||||
}
|
}
|
||||||
@ -55,6 +65,8 @@ export const WebsiteInfo: React.FC = React.memo(() => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
<Tabs>
|
||||||
|
<Tabs.TabPane key={'detail'} tab={'Detail'}>
|
||||||
<Form
|
<Form
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
initialValues={{
|
initialValues={{
|
||||||
@ -70,7 +82,11 @@ export const WebsiteInfo: React.FC = React.memo(() => {
|
|||||||
<Form.Item label="Name" name="name" rules={[{ required: true }]}>
|
<Form.Item label="Name" name="name" rules={[{ required: true }]}>
|
||||||
<Input size="large" />
|
<Input size="large" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label="Domain" name="domain" rules={[{ required: true }]}>
|
<Form.Item
|
||||||
|
label="Domain"
|
||||||
|
name="domain"
|
||||||
|
rules={[{ required: true }]}
|
||||||
|
>
|
||||||
<Input size="large" />
|
<Input size="large" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
@ -80,6 +96,19 @@ export const WebsiteInfo: React.FC = React.memo(() => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -34,7 +34,6 @@ export const Settings: React.FC = React.memo(() => {
|
|||||||
mode="vertical"
|
mode="vertical"
|
||||||
items={items}
|
items={items}
|
||||||
/>
|
/>
|
||||||
{pathname}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full md:w-5/6 py-2 px-4">
|
<div className="w-full md:w-5/6 py-2 px-4">
|
||||||
<Routes>
|
<Routes>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Handler } from 'express';
|
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) => {
|
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;
|
||||||
@ -16,12 +16,20 @@ export function workspacePermission(): Handler {
|
|||||||
throw new Error('This middleware should be use after auth()');
|
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');
|
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();
|
next();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,23 @@
|
|||||||
import { prisma } from './_client';
|
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(
|
export async function checkIsWorkspaceUser(
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
userId: string
|
userId: string
|
||||||
) {
|
) {
|
||||||
const workspace = await prisma.workspace.findUnique({
|
const info = await getWorkspaceUser(workspaceId, userId);
|
||||||
where: {
|
|
||||||
id: workspaceId,
|
|
||||||
users: {
|
|
||||||
some: {
|
|
||||||
userId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (workspace) {
|
if (info) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -84,3 +86,17 @@ export async function addWorkspaceWebsite(
|
|||||||
|
|
||||||
return website;
|
return website;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteWorkspaceWebsite(
|
||||||
|
workspaceId: string,
|
||||||
|
websiteId: string
|
||||||
|
) {
|
||||||
|
const website = await prisma.website.delete({
|
||||||
|
where: {
|
||||||
|
id: websiteId,
|
||||||
|
workspaceId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return website;
|
||||||
|
}
|
||||||
|
@ -4,10 +4,12 @@ import { body, param, query, validate } from '../middleware/validate';
|
|||||||
import { workspacePermission } from '../middleware/workspace';
|
import { workspacePermission } from '../middleware/workspace';
|
||||||
import {
|
import {
|
||||||
addWorkspaceWebsite,
|
addWorkspaceWebsite,
|
||||||
|
deleteWorkspaceWebsite,
|
||||||
getWorkspaceWebsiteInfo,
|
getWorkspaceWebsiteInfo,
|
||||||
getWorkspaceWebsites,
|
getWorkspaceWebsites,
|
||||||
updateWorkspaceWebsiteInfo,
|
updateWorkspaceWebsiteInfo,
|
||||||
} from '../model/workspace';
|
} from '../model/workspace';
|
||||||
|
import { ROLES } from '../utils/const';
|
||||||
|
|
||||||
export const workspaceRouter = Router();
|
export const workspaceRouter = Router();
|
||||||
|
|
||||||
@ -128,3 +130,29 @@ workspaceRouter.post(
|
|||||||
res.json({ website });
|
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 });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user