mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-09-27 05:36:40 +08:00
695 lines
15 KiB
Go
695 lines
15 KiB
Go
package controller
|
||
|
||
import (
|
||
"encoding/json"
|
||
"github.com/gin-contrib/sessions"
|
||
"github.com/gin-gonic/gin"
|
||
"net/http"
|
||
"one-api/common"
|
||
"one-api/model"
|
||
"strconv"
|
||
)
|
||
|
||
type LoginRequest struct {
|
||
Username string `json:"username"`
|
||
Password string `json:"password"`
|
||
}
|
||
|
||
func Login(c *gin.Context) {
|
||
if !common.PasswordLoginEnabled {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": "Admin turned off password login",
|
||
"success": false,
|
||
})
|
||
return
|
||
}
|
||
var loginRequest LoginRequest
|
||
err := json.NewDecoder(c.Request.Body).Decode(&loginRequest)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": "invalid parameter",
|
||
"success": false,
|
||
})
|
||
return
|
||
}
|
||
username := loginRequest.Username
|
||
password := loginRequest.Password
|
||
if username == "" || password == "" {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": "invalid parameter",
|
||
"success": false,
|
||
})
|
||
return
|
||
}
|
||
user := model.User{
|
||
Username: username,
|
||
Password: password,
|
||
}
|
||
err = user.ValidateAndFill()
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": err.Error(),
|
||
"success": false,
|
||
})
|
||
return
|
||
}
|
||
setupLogin(&user, c)
|
||
}
|
||
|
||
// setup session & cookies and then return user info
|
||
func setupLogin(user *model.User, c *gin.Context) {
|
||
session := sessions.Default(c)
|
||
session.Set("id", user.Id)
|
||
session.Set("username", user.Username)
|
||
session.Set("role", user.Role)
|
||
session.Set("status", user.Status)
|
||
err := session.Save()
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": "Unable to save session information, please try again",
|
||
"success": false,
|
||
})
|
||
return
|
||
}
|
||
cleanUser := model.User{
|
||
Id: user.Id,
|
||
Username: user.Username,
|
||
DisplayName: user.DisplayName,
|
||
Role: user.Role,
|
||
Status: user.Status,
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": "",
|
||
"success": true,
|
||
"data": cleanUser,
|
||
})
|
||
}
|
||
|
||
func Logout(c *gin.Context) {
|
||
session := sessions.Default(c)
|
||
session.Clear()
|
||
err := session.Save()
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": err.Error(),
|
||
"success": false,
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": "",
|
||
"success": true,
|
||
})
|
||
}
|
||
|
||
func Register(c *gin.Context) {
|
||
if !common.RegisterEnabled {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": "Admin turned off new user registration",
|
||
"success": false,
|
||
})
|
||
return
|
||
}
|
||
if !common.PasswordRegisterEnabled {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"message": "The administrator has closed the registration by password, please use the form of third-party account verification to register",
|
||
"success": false,
|
||
})
|
||
return
|
||
}
|
||
var user model.User
|
||
err := json.NewDecoder(c.Request.Body).Decode(&user)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "invalid parameter",
|
||
})
|
||
return
|
||
}
|
||
if err := common.Validate.Struct(&user); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Illegal input " + err.Error(),
|
||
})
|
||
return
|
||
}
|
||
if common.EmailVerificationEnabled {
|
||
if user.Email == "" || user.VerificationCode == "" {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "The administrator has enabled email verification, please enter the email address and verification code",
|
||
})
|
||
return
|
||
}
|
||
if !common.VerifyCodeWithKey(user.Email, user.VerificationCode, common.EmailVerificationPurpose) {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "The verification code is wrong or has expired",
|
||
})
|
||
return
|
||
}
|
||
}
|
||
cleanUser := model.User{
|
||
Username: user.Username,
|
||
Password: user.Password,
|
||
DisplayName: user.Username,
|
||
}
|
||
if common.EmailVerificationEnabled {
|
||
cleanUser.Email = user.Email
|
||
}
|
||
if err := cleanUser.Insert(); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
})
|
||
return
|
||
}
|
||
|
||
func GetAllUsers(c *gin.Context) {
|
||
p, _ := strconv.Atoi(c.Query("p"))
|
||
if p < 0 {
|
||
p = 0
|
||
}
|
||
users, err := model.GetAllUsers(p*common.ItemsPerPage, common.ItemsPerPage)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
"data": users,
|
||
})
|
||
return
|
||
}
|
||
|
||
func SearchUsers(c *gin.Context) {
|
||
keyword := c.Query("keyword")
|
||
users, err := model.SearchUsers(keyword)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
"data": users,
|
||
})
|
||
return
|
||
}
|
||
|
||
func GetUser(c *gin.Context) {
|
||
id, err := strconv.Atoi(c.Param("id"))
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
user, err := model.GetUserById(id, false)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
myRole := c.GetInt("role")
|
||
if myRole <= user.Role {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Do not have the right to obtain the information of users of the same level or higher level",
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
"data": user,
|
||
})
|
||
return
|
||
}
|
||
|
||
func GenerateAccessToken(c *gin.Context) {
|
||
id := c.GetInt("id")
|
||
user, err := model.GetUserById(id, true)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
user.AccessToken = common.GetUUID()
|
||
|
||
if model.DB.Where("token = ?", user.AccessToken).First(user).RowsAffected != 0 {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Please try again, the UUID generated by the system is duplicated!",
|
||
})
|
||
return
|
||
}
|
||
|
||
if err := user.Update(false); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
"data": user.AccessToken,
|
||
})
|
||
return
|
||
}
|
||
|
||
func GetSelf(c *gin.Context) {
|
||
id := c.GetInt("id")
|
||
user, err := model.GetUserById(id, false)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
"data": user,
|
||
})
|
||
return
|
||
}
|
||
|
||
func UpdateUser(c *gin.Context) {
|
||
var updatedUser model.User
|
||
err := json.NewDecoder(c.Request.Body).Decode(&updatedUser)
|
||
if err != nil || updatedUser.Id == 0 {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "invalid parameter",
|
||
})
|
||
return
|
||
}
|
||
if updatedUser.Password == "" {
|
||
updatedUser.Password = "$I_LOVE_U" // make Validator happy :)
|
||
}
|
||
if err := common.Validate.Struct(&updatedUser); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Illegal input " + err.Error(),
|
||
})
|
||
return
|
||
}
|
||
originUser, err := model.GetUserById(updatedUser.Id, false)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
myRole := c.GetInt("role")
|
||
if myRole <= originUser.Role {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Not authorized to update user information at the same level or higher",
|
||
})
|
||
return
|
||
}
|
||
if myRole <= updatedUser.Role {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Do not have the right to elevate the authority level of other users to be greater than or equal to their own authority level",
|
||
})
|
||
return
|
||
}
|
||
if updatedUser.Password == "$I_LOVE_U" {
|
||
updatedUser.Password = "" // rollback to what it should be
|
||
}
|
||
updatePassword := updatedUser.Password != ""
|
||
if err := updatedUser.Update(updatePassword); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
})
|
||
return
|
||
}
|
||
|
||
func UpdateSelf(c *gin.Context) {
|
||
var user model.User
|
||
err := json.NewDecoder(c.Request.Body).Decode(&user)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "invalid parameter",
|
||
})
|
||
return
|
||
}
|
||
if user.Password == "" {
|
||
user.Password = "$I_LOVE_U" // make Validator happy :)
|
||
}
|
||
if err := common.Validate.Struct(&user); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Illegal input " + err.Error(),
|
||
})
|
||
return
|
||
}
|
||
|
||
cleanUser := model.User{
|
||
Id: c.GetInt("id"),
|
||
Username: user.Username,
|
||
Password: user.Password,
|
||
DisplayName: user.DisplayName,
|
||
}
|
||
if user.Password == "$I_LOVE_U" {
|
||
user.Password = "" // rollback to what it should be
|
||
cleanUser.Password = ""
|
||
}
|
||
updatePassword := user.Password != ""
|
||
if err := cleanUser.Update(updatePassword); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
})
|
||
return
|
||
}
|
||
|
||
func DeleteUser(c *gin.Context) {
|
||
id, err := strconv.Atoi(c.Param("id"))
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
originUser, err := model.GetUserById(id, false)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
myRole := c.GetInt("role")
|
||
if myRole <= originUser.Role {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Not authorized to delete users with the same or higher privilege level",
|
||
})
|
||
return
|
||
}
|
||
err = model.DeleteUserById(id)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
})
|
||
return
|
||
}
|
||
}
|
||
|
||
func DeleteSelf(c *gin.Context) {
|
||
id := c.GetInt("id")
|
||
err := model.DeleteUserById(id)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
})
|
||
return
|
||
}
|
||
|
||
func CreateUser(c *gin.Context) {
|
||
var user model.User
|
||
err := json.NewDecoder(c.Request.Body).Decode(&user)
|
||
if err != nil || user.Username == "" || user.Password == "" {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "invalid parameter",
|
||
})
|
||
return
|
||
}
|
||
if err := common.Validate.Struct(&user); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Illegal input " + err.Error(),
|
||
})
|
||
return
|
||
}
|
||
if user.DisplayName == "" {
|
||
user.DisplayName = user.Username
|
||
}
|
||
myRole := c.GetInt("role")
|
||
if user.Role >= myRole {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Unable to create users with permissions greater than or equal to their own",
|
||
})
|
||
return
|
||
}
|
||
// Even for admin users, we cannot fully trust them!
|
||
cleanUser := model.User{
|
||
Username: user.Username,
|
||
Password: user.Password,
|
||
DisplayName: user.DisplayName,
|
||
}
|
||
if err := cleanUser.Insert(); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
})
|
||
return
|
||
}
|
||
|
||
type ManageRequest struct {
|
||
Username string `json:"username"`
|
||
Action string `json:"action"`
|
||
}
|
||
|
||
// ManageUser Only admin user can do this
|
||
func ManageUser(c *gin.Context) {
|
||
var req ManageRequest
|
||
err := json.NewDecoder(c.Request.Body).Decode(&req)
|
||
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "invalid parameter",
|
||
})
|
||
return
|
||
}
|
||
user := model.User{
|
||
Username: req.Username,
|
||
}
|
||
// Fill attributes
|
||
model.DB.Where(&user).First(&user)
|
||
if user.Id == 0 {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "User does not exist",
|
||
})
|
||
return
|
||
}
|
||
myRole := c.GetInt("role")
|
||
if myRole <= user.Role && myRole != common.RoleRootUser {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Not authorized to update user information at the same level or higher",
|
||
})
|
||
return
|
||
}
|
||
switch req.Action {
|
||
case "disable":
|
||
user.Status = common.UserStatusDisabled
|
||
if user.Role == common.RoleRootUser {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Unable to disable super admin user",
|
||
})
|
||
return
|
||
}
|
||
case "enable":
|
||
user.Status = common.UserStatusEnabled
|
||
case "delete":
|
||
if user.Role == common.RoleRootUser {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Unable to delete super admin user",
|
||
})
|
||
return
|
||
}
|
||
if err := user.Delete(); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
case "promote":
|
||
if myRole != common.RoleRootUser {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Regular admin users cannot promote other users to be admins",
|
||
})
|
||
return
|
||
}
|
||
if user.Role >= common.RoleAdminUser {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "This user is already an administrator",
|
||
})
|
||
return
|
||
}
|
||
user.Role = common.RoleAdminUser
|
||
case "demote":
|
||
if user.Role == common.RoleRootUser {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Unable to demote super administrator users",
|
||
})
|
||
return
|
||
}
|
||
if user.Role == common.RoleCommonUser {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "This user is already a regular user",
|
||
})
|
||
return
|
||
}
|
||
user.Role = common.RoleCommonUser
|
||
}
|
||
|
||
if err := user.Update(false); err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
clearUser := model.User{
|
||
Role: user.Role,
|
||
Status: user.Status,
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
"data": clearUser,
|
||
})
|
||
return
|
||
}
|
||
|
||
func EmailBind(c *gin.Context) {
|
||
email := c.Query("email")
|
||
code := c.Query("code")
|
||
if !common.VerifyCodeWithKey(email, code, common.EmailVerificationPurpose) {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": "Verification code is incorrect or has expired",
|
||
})
|
||
return
|
||
}
|
||
id := c.GetInt("id")
|
||
user := model.User{
|
||
Id: id,
|
||
}
|
||
err := user.FillUserById()
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
user.Email = email
|
||
// no need to check if this email already taken, because we have used verification code to check it
|
||
err = user.Update(false)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
})
|
||
return
|
||
}
|
||
|
||
type topUpRequest struct {
|
||
Key string `json:"key"`
|
||
}
|
||
|
||
func TopUp(c *gin.Context) {
|
||
req := topUpRequest{}
|
||
err := c.ShouldBindJSON(&req)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
id := c.GetInt("id")
|
||
quota, err := model.Redeem(req.Key, id)
|
||
if err != nil {
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": false,
|
||
"message": err.Error(),
|
||
})
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, gin.H{
|
||
"success": true,
|
||
"message": "",
|
||
"data": quota,
|
||
})
|
||
return
|
||
}
|