Skip to content

Commit 2fcd685

Browse files
feat: able to delete account by self (QuantumNous#294)
* feat: support account deletion * chore: update style --------- Co-authored-by: JustSong <songquanpeng@foxmail.com>
1 parent 9b4d196 commit 2fcd685

3 files changed

Lines changed: 86 additions & 5 deletions

File tree

controller/user.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ package controller
33
import (
44
"encoding/json"
55
"fmt"
6-
"github.com/gin-contrib/sessions"
7-
"github.com/gin-gonic/gin"
86
"net/http"
97
"one-api/common"
108
"one-api/model"
119
"strconv"
10+
11+
"github.com/gin-contrib/sessions"
12+
"github.com/gin-gonic/gin"
1213
)
1314

1415
type LoginRequest struct {
@@ -477,6 +478,16 @@ func DeleteUser(c *gin.Context) {
477478

478479
func DeleteSelf(c *gin.Context) {
479480
id := c.GetInt("id")
481+
user, _ := model.GetUserById(id, false)
482+
483+
if user.Role == common.RoleRootUser {
484+
c.JSON(http.StatusOK, gin.H{
485+
"success": false,
486+
"message": "不能删除超级管理员账户",
487+
})
488+
return
489+
}
490+
480491
err := model.DeleteUserById(id)
481492
if err != nil {
482493
c.JSON(http.StatusOK, gin.H{

router/api-router.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func SetApiRouter(router *gin.Engine) {
3636
{
3737
selfRoute.GET("/self", controller.GetSelf)
3838
selfRoute.PUT("/self", controller.UpdateSelf)
39-
selfRoute.DELETE("/self", controller.DeleteSelf)
39+
selfRoute.DELETE("/self", middleware.TurnstileCheck(), controller.DeleteSelf)
4040
selfRoute.GET("/token", controller.GenerateAccessToken)
4141
selfRoute.GET("/aff", controller.GetAffCode)
4242
selfRoute.POST("/topup", controller.TopUp)

web/src/components/PersonalSetting.js

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React, { useContext, useEffect, useState } from 'react';
22
import { Button, Divider, Form, Header, Image, Message, Modal } from 'semantic-ui-react';
3-
import { Link } from 'react-router-dom';
3+
import { Link, useNavigate } from 'react-router-dom';
44
import { API, copy, showError, showInfo, showNotice, showSuccess } from '../helpers';
55
import Turnstile from 'react-turnstile';
6+
import { UserContext } from '../context/User';
67

78
const PersonalSetting = () => {
9+
const [userState, userDispatch] = useContext(UserContext);
10+
let navigate = useNavigate();
11+
812
const [inputs, setInputs] = useState({
913
wechat_verification_code: '',
1014
email_verification_code: '',
1115
email: '',
16+
self_account_deletion_confirmation: ''
1217
});
1318
const [status, setStatus] = useState({});
1419
const [showWeChatBindModal, setShowWeChatBindModal] = useState(false);
1520
const [showEmailBindModal, setShowEmailBindModal] = useState(false);
21+
const [showAccountDeleteModal, setShowAccountDeleteModal] = useState(false);
1622
const [turnstileEnabled, setTurnstileEnabled] = useState(false);
1723
const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
1824
const [turnstileToken, setTurnstileToken] = useState('');
@@ -72,6 +78,26 @@ const PersonalSetting = () => {
7278
}
7379
};
7480

81+
const deleteAccount = async () => {
82+
if (inputs.self_account_deletion_confirmation !== userState.user.username) {
83+
showError('请输入你的账户名以确认删除!');
84+
return;
85+
}
86+
87+
const res = await API.delete('/api/user/self');
88+
const { success, message } = res.data;
89+
90+
if (success) {
91+
showSuccess('账户已删除!');
92+
await API.get('/api/user/logout');
93+
userDispatch({ type: 'logout' });
94+
localStorage.removeItem('user');
95+
navigate('/login');
96+
} else {
97+
showError(message);
98+
}
99+
};
100+
75101
const bindWeChat = async () => {
76102
if (inputs.wechat_verification_code === '') return;
77103
const res = await API.get(
@@ -139,6 +165,9 @@ const PersonalSetting = () => {
139165
</Button>
140166
<Button onClick={generateAccessToken}>生成系统访问令牌</Button>
141167
<Button onClick={getAffLink}>复制邀请链接</Button>
168+
<Button onClick={() => {
169+
setShowAccountDeleteModal(true);
170+
}}>删除个人账户</Button>
142171
<Divider />
143172
<Header as='h3'>账号绑定</Header>
144173
{
@@ -246,6 +275,47 @@ const PersonalSetting = () => {
246275
</Modal.Description>
247276
</Modal.Content>
248277
</Modal>
278+
<Modal
279+
onClose={() => setShowAccountDeleteModal(false)}
280+
onOpen={() => setShowAccountDeleteModal(true)}
281+
open={showAccountDeleteModal}
282+
size={'tiny'}
283+
style={{ maxWidth: '450px' }}
284+
>
285+
<Modal.Header>确认删除自己的帐户</Modal.Header>
286+
<Modal.Content>
287+
<Modal.Description>
288+
<Form size='large'>
289+
<Form.Input
290+
fluid
291+
placeholder={`输入你的账户名 ${userState.user.username} 以确认删除`}
292+
name='self_account_deletion_confirmation'
293+
value={inputs.self_account_deletion_confirmation}
294+
onChange={handleInputChange}
295+
/>
296+
{turnstileEnabled ? (
297+
<Turnstile
298+
sitekey={turnstileSiteKey}
299+
onVerify={(token) => {
300+
setTurnstileToken(token);
301+
}}
302+
/>
303+
) : (
304+
<></>
305+
)}
306+
<Button
307+
color='red'
308+
fluid
309+
size='large'
310+
onClick={deleteAccount}
311+
loading={loading}
312+
>
313+
删除
314+
</Button>
315+
</Form>
316+
</Modal.Description>
317+
</Modal.Content>
318+
</Modal>
249319
</div>
250320
);
251321
};

0 commit comments

Comments
 (0)