diff --git a/model/common.go b/model/common.go index 018a8642..c85c19ab 100644 --- a/model/common.go +++ b/model/common.go @@ -140,3 +140,13 @@ func assembleSumSelectStr(selectStr string) string { return sumSelectStr } + +func RecordExists(table interface{}, fieldName string, fieldValue interface{}, excludeID interface{}) bool { + var count int64 + query := DB.Model(table).Where(fmt.Sprintf("%s = ?", fieldName), fieldValue) + if excludeID != nil { + query = query.Not("id", excludeID) + } + query.Count(&count) + return count > 0 +} diff --git a/model/user.go b/model/user.go index 3adb7b83..9190efc5 100644 --- a/model/user.go +++ b/model/user.go @@ -5,6 +5,7 @@ import ( "fmt" "one-api/common" "strings" + "time" "gorm.io/gorm" ) @@ -12,25 +13,26 @@ import ( // User if you add sensitive fields, don't forget to clean them in setupLogin function. // Otherwise, the sensitive information will be saved on local storage in plain text! type User struct { - Id int `json:"id"` - Username string `json:"username" gorm:"unique;index" validate:"max=12"` - Password string `json:"password" gorm:"not null;" validate:"min=8,max=20"` - DisplayName string `json:"display_name" gorm:"index" validate:"max=20"` - Role int `json:"role" gorm:"type:int;default:1"` // admin, common - Status int `json:"status" gorm:"type:int;default:1"` // enabled, disabled - Email string `json:"email" gorm:"index" validate:"max=50"` - GitHubId string `json:"github_id" gorm:"column:github_id;index"` - WeChatId string `json:"wechat_id" gorm:"column:wechat_id;index"` - TelegramId int64 `json:"telegram_id" gorm:"bigint,column:telegram_id;default:0;"` - VerificationCode string `json:"verification_code" gorm:"-:all"` // this field is only for Email verification, don't save it to database! - AccessToken string `json:"access_token" gorm:"type:char(32);column:access_token;uniqueIndex"` // this token is for system management - Quota int `json:"quota" gorm:"type:int;default:0"` - UsedQuota int `json:"used_quota" gorm:"type:int;default:0;column:used_quota"` // used quota - RequestCount int `json:"request_count" gorm:"type:int;default:0;"` // request number - Group string `json:"group" gorm:"type:varchar(32);default:'default'"` - AffCode string `json:"aff_code" gorm:"type:varchar(32);column:aff_code;uniqueIndex"` - InviterId int `json:"inviter_id" gorm:"type:int;column:inviter_id;index"` - CreatedTime int64 `json:"created_time" gorm:"bigint"` + Id int `json:"id"` + Username string `json:"username" gorm:"unique;index" validate:"max=12"` + Password string `json:"password" gorm:"not null;" validate:"min=8,max=20"` + DisplayName string `json:"display_name" gorm:"index" validate:"max=20"` + Role int `json:"role" gorm:"type:int;default:1"` // admin, common + Status int `json:"status" gorm:"type:int;default:1"` // enabled, disabled + Email string `json:"email" gorm:"index" validate:"max=50"` + GitHubId string `json:"github_id" gorm:"column:github_id;index"` + WeChatId string `json:"wechat_id" gorm:"column:wechat_id;index"` + TelegramId int64 `json:"telegram_id" gorm:"bigint,column:telegram_id;default:0;"` + VerificationCode string `json:"verification_code" gorm:"-:all"` // this field is only for Email verification, don't save it to database! + AccessToken string `json:"access_token" gorm:"type:char(32);column:access_token;uniqueIndex"` // this token is for system management + Quota int `json:"quota" gorm:"type:int;default:0"` + UsedQuota int `json:"used_quota" gorm:"type:int;default:0;column:used_quota"` // used quota + RequestCount int `json:"request_count" gorm:"type:int;default:0;"` // request number + Group string `json:"group" gorm:"type:varchar(32);default:'default'"` + AffCode string `json:"aff_code" gorm:"type:varchar(32);column:aff_code;uniqueIndex"` + InviterId int `json:"inviter_id" gorm:"type:int;column:inviter_id;index"` + CreatedTime int64 `json:"created_time" gorm:"bigint"` + DeletedAt *time.Time `gorm:"index"` } type UserUpdates func(*User) @@ -102,6 +104,9 @@ func DeleteUserById(id int) (err error) { } func (user *User) Insert(inviterId int) error { + if RecordExists(&User{}, "username", user.Username, nil) { + return errors.New("用户名已存在!") + } var err error if user.Password != "" { user.Password, err = common.Password2Hash(user.Password) @@ -134,6 +139,9 @@ func (user *User) Insert(inviterId int) error { } func (user *User) Update(updatePassword bool) error { + if RecordExists(&User{}, "username", user.Username, user.Id) { + return errors.New("用户名已存在!") + } var err error if updatePassword { user.Password, err = common.Password2Hash(user.Password) diff --git a/router/api-router.go b/router/api-router.go index d1fef864..c2b2fcc8 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -42,7 +42,7 @@ func SetApiRouter(router *gin.Engine) { selfRoute.GET("/dashboard", controller.GetUserDashboard) selfRoute.GET("/self", controller.GetSelf) selfRoute.PUT("/self", controller.UpdateSelf) - selfRoute.DELETE("/self", controller.DeleteSelf) + // selfRoute.DELETE("/self", controller.DeleteSelf) selfRoute.GET("/token", controller.GenerateAccessToken) selfRoute.GET("/aff", controller.GetAffCode) selfRoute.POST("/topup", controller.TopUp) diff --git a/web/src/views/Profile/index.js b/web/src/views/Profile/index.js index bdf4e080..44b4aaf8 100644 --- a/web/src/views/Profile/index.js +++ b/web/src/views/Profile/index.js @@ -1,21 +1,6 @@ import { useState, useEffect } from 'react'; import UserCard from 'ui-component/cards/UserCard'; -import { - Card, - Button, - InputLabel, - FormControl, - OutlinedInput, - Stack, - Alert, - Dialog, - DialogTitle, - DialogContent, - DialogActions, - Divider, - Chip, - Typography -} from '@mui/material'; +import { Card, Button, InputLabel, FormControl, OutlinedInput, Stack, Alert, Divider, Chip, Typography } from '@mui/material'; import Grid from '@mui/material/Unstable_Grid2'; import SubCard from 'ui-component/cards/SubCard'; import { IconBrandWechat, IconBrandGithub, IconMail, IconBrandTelegram } from '@tabler/icons-react'; @@ -38,7 +23,6 @@ const validationSchema = Yup.object().shape({ export default function Profile() { const [inputs, setInputs] = useState([]); - const [showAccountDeleteModal, setShowAccountDeleteModal] = useState(false); const [turnstileEnabled, setTurnstileEnabled] = useState(false); const [turnstileSiteKey, setTurnstileSiteKey] = useState(''); const [turnstileToken, setTurnstileToken] = useState(''); @@ -284,41 +268,11 @@ export default function Profile() { {inputs.access_token ? '重置访问令牌' : '生成访问令牌'} - - - - - setShowAccountDeleteModal(false)} maxWidth={'md'}> - - 危险操作 - - - 您正在删除自己的帐户,将清空所有数据且不可恢复 - - - - -