You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

1189 lines
30 KiB

  1. package controller
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "net/url"
  8. "strconv"
  9. "strings"
  10. "sync"
  11. "github.com/QuantumNous/new-api/common"
  12. "github.com/QuantumNous/new-api/dto"
  13. "github.com/QuantumNous/new-api/i18n"
  14. "github.com/QuantumNous/new-api/logger"
  15. "github.com/QuantumNous/new-api/model"
  16. "github.com/QuantumNous/new-api/service"
  17. "github.com/QuantumNous/new-api/service/region_sync"
  18. "github.com/QuantumNous/new-api/setting"
  19. "github.com/QuantumNous/new-api/constant"
  20. "github.com/gin-contrib/sessions"
  21. "github.com/gin-gonic/gin"
  22. )
  23. type LoginRequest struct {
  24. Username string `json:"username"`
  25. Password string `json:"password"`
  26. }
  27. func Login(c *gin.Context) {
  28. if !common.PasswordLoginEnabled {
  29. common.ApiErrorI18n(c, i18n.MsgUserPasswordLoginDisabled)
  30. return
  31. }
  32. var loginRequest LoginRequest
  33. err := json.NewDecoder(c.Request.Body).Decode(&loginRequest)
  34. if err != nil {
  35. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  36. return
  37. }
  38. username := loginRequest.Username
  39. password := loginRequest.Password
  40. if username == "" || password == "" {
  41. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  42. return
  43. }
  44. user := model.User{
  45. Username: username,
  46. Password: password,
  47. }
  48. err = user.ValidateAndFill()
  49. if err != nil {
  50. c.JSON(http.StatusOK, gin.H{
  51. "message": err.Error(),
  52. "success": false,
  53. })
  54. return
  55. }
  56. // 检查是否启用2FA
  57. if model.IsTwoFAEnabled(user.Id) {
  58. // 设置pending session,等待2FA验证
  59. session := sessions.Default(c)
  60. session.Set("pending_username", user.Username)
  61. session.Set("pending_user_id", user.Id)
  62. err := session.Save()
  63. if err != nil {
  64. common.ApiErrorI18n(c, i18n.MsgUserSessionSaveFailed)
  65. return
  66. }
  67. c.JSON(http.StatusOK, gin.H{
  68. "message": i18n.T(c, i18n.MsgUserRequire2FA),
  69. "success": true,
  70. "data": map[string]interface{}{
  71. "require_2fa": true,
  72. },
  73. })
  74. return
  75. }
  76. setupLogin(&user, c)
  77. }
  78. // setup session & cookies and then return user info
  79. func setupLogin(user *model.User, c *gin.Context) {
  80. session := sessions.Default(c)
  81. session.Set("id", user.Id)
  82. session.Set("username", user.Username)
  83. session.Set("role", user.Role)
  84. session.Set("status", user.Status)
  85. session.Set("group", user.Group)
  86. err := session.Save()
  87. if err != nil {
  88. common.ApiErrorI18n(c, i18n.MsgUserSessionSaveFailed)
  89. return
  90. }
  91. c.JSON(http.StatusOK, gin.H{
  92. "message": "",
  93. "success": true,
  94. "data": map[string]any{
  95. "id": user.Id,
  96. "username": user.Username,
  97. "display_name": user.DisplayName,
  98. "role": user.Role,
  99. "status": user.Status,
  100. "group": user.Group,
  101. },
  102. })
  103. }
  104. func Logout(c *gin.Context) {
  105. session := sessions.Default(c)
  106. session.Clear()
  107. err := session.Save()
  108. if err != nil {
  109. c.JSON(http.StatusOK, gin.H{
  110. "message": err.Error(),
  111. "success": false,
  112. })
  113. return
  114. }
  115. c.JSON(http.StatusOK, gin.H{
  116. "message": "",
  117. "success": true,
  118. })
  119. }
  120. func Register(c *gin.Context) {
  121. if !common.RegisterEnabled {
  122. common.ApiErrorI18n(c, i18n.MsgUserRegisterDisabled)
  123. return
  124. }
  125. if !common.PasswordRegisterEnabled {
  126. common.ApiErrorI18n(c, i18n.MsgUserPasswordRegisterDisabled)
  127. return
  128. }
  129. var user model.User
  130. err := json.NewDecoder(c.Request.Body).Decode(&user)
  131. if err != nil {
  132. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  133. return
  134. }
  135. if err := common.Validate.Struct(&user); err != nil {
  136. common.ApiErrorI18n(c, i18n.MsgUserInputInvalid, map[string]any{"Error": err.Error()})
  137. return
  138. }
  139. if common.EmailVerificationEnabled {
  140. if user.Email == "" || user.VerificationCode == "" {
  141. common.ApiErrorI18n(c, i18n.MsgUserEmailVerificationRequired)
  142. return
  143. }
  144. if !common.VerifyCodeWithKey(user.Email, user.VerificationCode, common.EmailVerificationPurpose) {
  145. common.ApiErrorI18n(c, i18n.MsgUserVerificationCodeError)
  146. return
  147. }
  148. }
  149. exist, err := model.CheckUserExistOrDeleted(user.Username, user.Email)
  150. if err != nil {
  151. common.ApiErrorI18n(c, i18n.MsgDatabaseError)
  152. common.SysLog(fmt.Sprintf("CheckUserExistOrDeleted error: %v", err))
  153. return
  154. }
  155. if exist {
  156. common.ApiErrorI18n(c, i18n.MsgUserExists)
  157. return
  158. }
  159. affCode := user.AffCode // this code is the inviter's code, not the user's own code
  160. inviterId, _ := model.GetUserIdByAffCode(affCode)
  161. cleanUser := model.User{
  162. Username: user.Username,
  163. Password: user.Password,
  164. DisplayName: user.Username,
  165. InviterId: inviterId,
  166. Role: common.RoleCommonUser, // 明确设置角色为普通用户
  167. }
  168. if common.EmailVerificationEnabled {
  169. cleanUser.Email = user.Email
  170. }
  171. if err := cleanUser.Insert(inviterId); err != nil {
  172. common.ApiError(c, err)
  173. return
  174. }
  175. // 同步用户到海外节点(异步执行,不阻塞注册流程)
  176. region_sync.PushUserCreateToSlave(&cleanUser)
  177. // 生成默认令牌
  178. if constant.GenerateDefaultToken {
  179. key, err := common.GenerateKey()
  180. if err != nil {
  181. common.ApiErrorI18n(c, i18n.MsgUserDefaultTokenFailed)
  182. common.SysLog("failed to generate token key: " + err.Error())
  183. return
  184. }
  185. // 生成默认令牌
  186. token := model.Token{
  187. UserId: cleanUser.Id, // GORM Create 后已填充 ID
  188. Name: cleanUser.Username + "的初始令牌",
  189. Key: key,
  190. CreatedTime: common.GetTimestamp(),
  191. AccessedTime: common.GetTimestamp(),
  192. ExpiredTime: -1, // 永不过期
  193. RemainQuota: 500000, // 示例额度
  194. UnlimitedQuota: true,
  195. ModelLimitsEnabled: false,
  196. }
  197. if setting.DefaultUseAutoGroup {
  198. token.Group = "auto"
  199. }
  200. if err := token.Insert(); err != nil {
  201. common.ApiErrorI18n(c, i18n.MsgCreateDefaultTokenErr)
  202. return
  203. }
  204. }
  205. c.JSON(http.StatusOK, gin.H{
  206. "success": true,
  207. "message": "",
  208. })
  209. return
  210. }
  211. func GetAllUsers(c *gin.Context) {
  212. pageInfo := common.GetPageQuery(c)
  213. users, total, err := model.GetAllUsers(pageInfo)
  214. if err != nil {
  215. common.ApiError(c, err)
  216. return
  217. }
  218. pageInfo.SetTotal(int(total))
  219. pageInfo.SetItems(users)
  220. common.ApiSuccess(c, pageInfo)
  221. return
  222. }
  223. func SearchUsers(c *gin.Context) {
  224. keyword := c.Query("keyword")
  225. group := c.Query("group")
  226. pageInfo := common.GetPageQuery(c)
  227. users, total, err := model.SearchUsers(keyword, group, pageInfo.GetStartIdx(), pageInfo.GetPageSize())
  228. if err != nil {
  229. common.ApiError(c, err)
  230. return
  231. }
  232. pageInfo.SetTotal(int(total))
  233. pageInfo.SetItems(users)
  234. common.ApiSuccess(c, pageInfo)
  235. return
  236. }
  237. func GetUser(c *gin.Context) {
  238. id, err := strconv.Atoi(c.Param("id"))
  239. if err != nil {
  240. common.ApiError(c, err)
  241. return
  242. }
  243. user, err := model.GetUserById(id, false)
  244. if err != nil {
  245. common.ApiError(c, err)
  246. return
  247. }
  248. myRole := c.GetInt("role")
  249. if myRole <= user.Role && myRole != common.RoleRootUser {
  250. common.ApiErrorI18n(c, i18n.MsgUserNoPermissionSameLevel)
  251. return
  252. }
  253. user.ApplySyncedQuota()
  254. c.JSON(http.StatusOK, gin.H{
  255. "success": true,
  256. "message": "",
  257. "data": user,
  258. })
  259. return
  260. }
  261. func GenerateAccessToken(c *gin.Context) {
  262. id := c.GetInt("id")
  263. user, err := model.GetUserById(id, true)
  264. if err != nil {
  265. common.ApiError(c, err)
  266. return
  267. }
  268. // get rand int 28-32
  269. randI := common.GetRandomInt(4)
  270. key, err := common.GenerateRandomKey(29 + randI)
  271. if err != nil {
  272. common.ApiErrorI18n(c, i18n.MsgGenerateFailed)
  273. common.SysLog("failed to generate key: " + err.Error())
  274. return
  275. }
  276. user.SetAccessToken(key)
  277. if model.DB.Where("access_token = ?", user.AccessToken).First(user).RowsAffected != 0 {
  278. common.ApiErrorI18n(c, i18n.MsgUuidDuplicate)
  279. return
  280. }
  281. if err := user.Update(false); err != nil {
  282. common.ApiError(c, err)
  283. return
  284. }
  285. c.JSON(http.StatusOK, gin.H{
  286. "success": true,
  287. "message": "",
  288. "data": user.AccessToken,
  289. })
  290. return
  291. }
  292. type TransferAffQuotaRequest struct {
  293. Quota int `json:"quota" binding:"required"`
  294. }
  295. func TransferAffQuota(c *gin.Context) {
  296. id := c.GetInt("id")
  297. user, err := model.GetUserById(id, true)
  298. if err != nil {
  299. common.ApiError(c, err)
  300. return
  301. }
  302. tran := TransferAffQuotaRequest{}
  303. if err := c.ShouldBindJSON(&tran); err != nil {
  304. common.ApiError(c, err)
  305. return
  306. }
  307. err = user.TransferAffQuotaToQuota(tran.Quota)
  308. if err != nil {
  309. common.ApiErrorI18n(c, i18n.MsgUserTransferFailed, map[string]any{"Error": err.Error()})
  310. return
  311. }
  312. common.ApiSuccessI18n(c, i18n.MsgUserTransferSuccess, nil)
  313. }
  314. func GetAffCode(c *gin.Context) {
  315. id := c.GetInt("id")
  316. user, err := model.GetUserById(id, true)
  317. if err != nil {
  318. common.ApiError(c, err)
  319. return
  320. }
  321. if user.AffCode == "" {
  322. user.AffCode = common.GetRandomString(4)
  323. if err := user.Update(false); err != nil {
  324. c.JSON(http.StatusOK, gin.H{
  325. "success": false,
  326. "message": err.Error(),
  327. })
  328. return
  329. }
  330. }
  331. c.JSON(http.StatusOK, gin.H{
  332. "success": true,
  333. "message": "",
  334. "data": user.AffCode,
  335. })
  336. return
  337. }
  338. func GetSelf(c *gin.Context) {
  339. id := c.GetInt("id")
  340. userRole := c.GetInt("role")
  341. user, err := model.GetUserById(id, false)
  342. if err != nil {
  343. common.ApiError(c, err)
  344. return
  345. }
  346. // Hide admin remarks: set to empty to trigger omitempty tag, ensuring the remark field is not included in JSON returned to regular users
  347. user.Remark = ""
  348. // 计算用户权限信息
  349. permissions := calculateUserPermissions(userRole)
  350. // 获取用户设置并提取sidebar_modules
  351. userSetting := user.GetSetting()
  352. // 构建响应数据,包含用户信息和权限
  353. // Slave 节点使用 SyncedQuota 作为用户额度
  354. quota := user.Quota
  355. if user.IsSyncedUser() {
  356. quota = user.SyncedQuota
  357. }
  358. responseData := map[string]interface{}{
  359. "id": user.Id,
  360. "username": user.Username,
  361. "display_name": user.DisplayName,
  362. "role": user.Role,
  363. "status": user.Status,
  364. "email": user.Email,
  365. "github_id": user.GitHubId,
  366. "discord_id": user.DiscordId,
  367. "oidc_id": user.OidcId,
  368. "wechat_id": user.WeChatId,
  369. "telegram_id": user.TelegramId,
  370. "group": user.Group,
  371. "quota": quota,
  372. "used_quota": user.UsedQuota,
  373. "request_count": user.RequestCount,
  374. "aff_code": user.AffCode,
  375. "aff_count": user.AffCount,
  376. "aff_quota": user.AffQuota,
  377. "aff_history_quota": user.AffHistoryQuota,
  378. "inviter_id": user.InviterId,
  379. "linux_do_id": user.LinuxDOId,
  380. "setting": user.Setting,
  381. "stripe_customer": user.StripeCustomer,
  382. "sidebar_modules": userSetting.SidebarModules, // 正确提取sidebar_modules字段
  383. "permissions": permissions, // 新增权限字段
  384. }
  385. c.JSON(http.StatusOK, gin.H{
  386. "success": true,
  387. "message": "",
  388. "data": responseData,
  389. })
  390. return
  391. }
  392. // 计算用户权限的辅助函数
  393. func calculateUserPermissions(userRole int) map[string]interface{} {
  394. permissions := map[string]interface{}{}
  395. // 根据用户角色计算权限
  396. if userRole == common.RoleRootUser {
  397. // 超级管理员不需要边栏设置功能
  398. permissions["sidebar_settings"] = false
  399. permissions["sidebar_modules"] = map[string]interface{}{}
  400. } else if userRole == common.RoleAdminUser {
  401. // 管理员可以设置边栏,但不包含系统设置功能
  402. permissions["sidebar_settings"] = true
  403. permissions["sidebar_modules"] = map[string]interface{}{
  404. "admin": map[string]interface{}{
  405. "setting": false, // 管理员不能访问系统设置
  406. },
  407. }
  408. } else {
  409. // 普通用户只能设置个人功能,不包含管理员区域
  410. permissions["sidebar_settings"] = true
  411. permissions["sidebar_modules"] = map[string]interface{}{
  412. "admin": false, // 普通用户不能访问管理员区域
  413. }
  414. }
  415. return permissions
  416. }
  417. // 根据用户角色生成默认的边栏配置
  418. func generateDefaultSidebarConfig(userRole int) string {
  419. defaultConfig := map[string]interface{}{}
  420. // 聊天区域 - 所有用户都可以访问
  421. defaultConfig["chat"] = map[string]interface{}{
  422. "enabled": true,
  423. "playground": true,
  424. "chat": true,
  425. }
  426. // 控制台区域 - 所有用户都可以访问
  427. defaultConfig["console"] = map[string]interface{}{
  428. "enabled": true,
  429. "detail": true,
  430. "token": true,
  431. "log": true,
  432. "midjourney": true,
  433. "task": true,
  434. }
  435. // 个人中心区域 - 所有用户都可以访问
  436. defaultConfig["personal"] = map[string]interface{}{
  437. "enabled": true,
  438. "topup": true,
  439. "personal": true,
  440. }
  441. // 管理员区域 - 根据角色决定
  442. if userRole == common.RoleAdminUser {
  443. // 管理员可以访问管理员区域,但不能访问系统设置
  444. defaultConfig["admin"] = map[string]interface{}{
  445. "enabled": true,
  446. "channel": true,
  447. "models": true,
  448. "redemption": true,
  449. "user": true,
  450. "setting": false, // 管理员不能访问系统设置
  451. }
  452. } else if userRole == common.RoleRootUser {
  453. // 超级管理员可以访问所有功能
  454. defaultConfig["admin"] = map[string]interface{}{
  455. "enabled": true,
  456. "channel": true,
  457. "models": true,
  458. "redemption": true,
  459. "user": true,
  460. "setting": true,
  461. }
  462. }
  463. // 普通用户不包含admin区域
  464. // 转换为JSON字符串
  465. configBytes, err := json.Marshal(defaultConfig)
  466. if err != nil {
  467. common.SysLog("生成默认边栏配置失败: " + err.Error())
  468. return ""
  469. }
  470. return string(configBytes)
  471. }
  472. func GetUserModels(c *gin.Context) {
  473. id, err := strconv.Atoi(c.Param("id"))
  474. if err != nil {
  475. id = c.GetInt("id")
  476. }
  477. user, err := model.GetUserCache(id)
  478. if err != nil {
  479. common.ApiError(c, err)
  480. return
  481. }
  482. groups := service.GetUserUsableGroups(user.Group)
  483. var models []string
  484. seen := make(map[string]struct{})
  485. for group := range groups {
  486. for _, g := range model.GetGroupEnabledModels(group) {
  487. if _, ok := seen[g]; !ok {
  488. seen[g] = struct{}{}
  489. models = append(models, g)
  490. }
  491. }
  492. }
  493. models = common.StringsSubtract(models, model.GetDisabledModelNames(models))
  494. c.JSON(http.StatusOK, gin.H{
  495. "success": true,
  496. "message": "",
  497. "data": models,
  498. })
  499. return
  500. }
  501. func UpdateUser(c *gin.Context) {
  502. var updatedUser model.User
  503. err := json.NewDecoder(c.Request.Body).Decode(&updatedUser)
  504. if err != nil || updatedUser.Id == 0 {
  505. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  506. return
  507. }
  508. if updatedUser.Password == "" {
  509. updatedUser.Password = "$I_LOVE_U" // make Validator happy :)
  510. }
  511. if err := common.Validate.Struct(&updatedUser); err != nil {
  512. common.ApiErrorI18n(c, i18n.MsgUserInputInvalid, map[string]any{"Error": err.Error()})
  513. return
  514. }
  515. originUser, err := model.GetUserById(updatedUser.Id, false)
  516. if err != nil {
  517. common.ApiError(c, err)
  518. return
  519. }
  520. myRole := c.GetInt("role")
  521. if myRole <= originUser.Role && myRole != common.RoleRootUser {
  522. common.ApiErrorI18n(c, i18n.MsgUserNoPermissionHigherLevel)
  523. return
  524. }
  525. if myRole <= updatedUser.Role && myRole != common.RoleRootUser {
  526. common.ApiErrorI18n(c, i18n.MsgUserCannotCreateHigherLevel)
  527. return
  528. }
  529. if updatedUser.Password == "$I_LOVE_U" {
  530. updatedUser.Password = "" // rollback to what it should be
  531. }
  532. updatePassword := updatedUser.Password != ""
  533. if err := updatedUser.Edit(updatePassword); err != nil {
  534. common.ApiError(c, err)
  535. return
  536. }
  537. if originUser.Quota != updatedUser.Quota {
  538. model.RecordLog(originUser.Id, model.LogTypeManage, fmt.Sprintf("管理员将用户额度从 %s修改为 %s", logger.LogQuota(originUser.Quota), logger.LogQuota(updatedUser.Quota)))
  539. }
  540. c.JSON(http.StatusOK, gin.H{
  541. "success": true,
  542. "message": "",
  543. })
  544. return
  545. }
  546. func AdminClearUserBinding(c *gin.Context) {
  547. id, err := strconv.Atoi(c.Param("id"))
  548. if err != nil {
  549. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  550. return
  551. }
  552. bindingType := strings.ToLower(strings.TrimSpace(c.Param("binding_type")))
  553. if bindingType == "" {
  554. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  555. return
  556. }
  557. user, err := model.GetUserById(id, false)
  558. if err != nil {
  559. common.ApiError(c, err)
  560. return
  561. }
  562. myRole := c.GetInt("role")
  563. if myRole <= user.Role && myRole != common.RoleRootUser {
  564. common.ApiErrorI18n(c, i18n.MsgUserNoPermissionSameLevel)
  565. return
  566. }
  567. if err := user.ClearBinding(bindingType); err != nil {
  568. common.ApiError(c, err)
  569. return
  570. }
  571. model.RecordLog(user.Id, model.LogTypeManage, fmt.Sprintf("admin cleared %s binding for user %s", bindingType, user.Username))
  572. c.JSON(http.StatusOK, gin.H{
  573. "success": true,
  574. "message": "success",
  575. })
  576. }
  577. func UpdateSelf(c *gin.Context) {
  578. var requestData map[string]interface{}
  579. err := json.NewDecoder(c.Request.Body).Decode(&requestData)
  580. if err != nil {
  581. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  582. return
  583. }
  584. // 检查是否是用户设置更新请求 (sidebar_modules 或 language)
  585. if sidebarModules, sidebarExists := requestData["sidebar_modules"]; sidebarExists {
  586. userId := c.GetInt("id")
  587. user, err := model.GetUserById(userId, false)
  588. if err != nil {
  589. common.ApiError(c, err)
  590. return
  591. }
  592. // 获取当前用户设置
  593. currentSetting := user.GetSetting()
  594. // 更新sidebar_modules字段
  595. if sidebarModulesStr, ok := sidebarModules.(string); ok {
  596. currentSetting.SidebarModules = sidebarModulesStr
  597. }
  598. // 保存更新后的设置
  599. user.SetSetting(currentSetting)
  600. if err := user.Update(false); err != nil {
  601. common.ApiErrorI18n(c, i18n.MsgUpdateFailed)
  602. return
  603. }
  604. common.ApiSuccessI18n(c, i18n.MsgUpdateSuccess, nil)
  605. return
  606. }
  607. // 检查是否是语言偏好更新请求
  608. if language, langExists := requestData["language"]; langExists {
  609. userId := c.GetInt("id")
  610. user, err := model.GetUserById(userId, false)
  611. if err != nil {
  612. common.ApiError(c, err)
  613. return
  614. }
  615. // 获取当前用户设置
  616. currentSetting := user.GetSetting()
  617. // 更新language字段
  618. if langStr, ok := language.(string); ok {
  619. currentSetting.Language = langStr
  620. }
  621. // 保存更新后的设置
  622. user.SetSetting(currentSetting)
  623. if err := user.Update(false); err != nil {
  624. common.ApiErrorI18n(c, i18n.MsgUpdateFailed)
  625. return
  626. }
  627. common.ApiSuccessI18n(c, i18n.MsgUpdateSuccess, nil)
  628. return
  629. }
  630. // 原有的用户信息更新逻辑
  631. var user model.User
  632. requestDataBytes, err := json.Marshal(requestData)
  633. if err != nil {
  634. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  635. return
  636. }
  637. err = json.Unmarshal(requestDataBytes, &user)
  638. if err != nil {
  639. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  640. return
  641. }
  642. if user.Password == "" {
  643. user.Password = "$I_LOVE_U" // make Validator happy :)
  644. }
  645. if err := common.Validate.Struct(&user); err != nil {
  646. common.ApiErrorI18n(c, i18n.MsgInvalidInput)
  647. return
  648. }
  649. cleanUser := model.User{
  650. Id: c.GetInt("id"),
  651. Username: user.Username,
  652. Password: user.Password,
  653. DisplayName: user.DisplayName,
  654. }
  655. if user.Password == "$I_LOVE_U" {
  656. user.Password = "" // rollback to what it should be
  657. cleanUser.Password = ""
  658. }
  659. updatePassword, err := checkUpdatePassword(user.OriginalPassword, user.Password, cleanUser.Id)
  660. if err != nil {
  661. common.ApiError(c, err)
  662. return
  663. }
  664. if err := cleanUser.Update(updatePassword); err != nil {
  665. common.ApiError(c, err)
  666. return
  667. }
  668. c.JSON(http.StatusOK, gin.H{
  669. "success": true,
  670. "message": "",
  671. })
  672. return
  673. }
  674. func checkUpdatePassword(originalPassword string, newPassword string, userId int) (updatePassword bool, err error) {
  675. var currentUser *model.User
  676. currentUser, err = model.GetUserById(userId, true)
  677. if err != nil {
  678. return
  679. }
  680. // 密码不为空,需要验证原密码
  681. // 支持第一次账号绑定时原密码为空的情况
  682. if !common.ValidatePasswordAndHash(originalPassword, currentUser.Password) && currentUser.Password != "" {
  683. err = fmt.Errorf("原密码错误")
  684. return
  685. }
  686. if newPassword == "" {
  687. return
  688. }
  689. updatePassword = true
  690. return
  691. }
  692. func DeleteUser(c *gin.Context) {
  693. id, err := strconv.Atoi(c.Param("id"))
  694. if err != nil {
  695. common.ApiError(c, err)
  696. return
  697. }
  698. originUser, err := model.GetUserById(id, false)
  699. if err != nil {
  700. common.ApiError(c, err)
  701. return
  702. }
  703. myRole := c.GetInt("role")
  704. if myRole <= originUser.Role {
  705. common.ApiErrorI18n(c, i18n.MsgUserNoPermissionHigherLevel)
  706. return
  707. }
  708. err = model.HardDeleteUserById(id)
  709. if err != nil {
  710. c.JSON(http.StatusOK, gin.H{
  711. "success": true,
  712. "message": "",
  713. })
  714. return
  715. }
  716. }
  717. func DeleteSelf(c *gin.Context) {
  718. id := c.GetInt("id")
  719. user, _ := model.GetUserById(id, false)
  720. if user.Role == common.RoleRootUser {
  721. common.ApiErrorI18n(c, i18n.MsgUserCannotDeleteRootUser)
  722. return
  723. }
  724. err := model.DeleteUserById(id)
  725. if err != nil {
  726. common.ApiError(c, err)
  727. return
  728. }
  729. c.JSON(http.StatusOK, gin.H{
  730. "success": true,
  731. "message": "",
  732. })
  733. return
  734. }
  735. func CreateUser(c *gin.Context) {
  736. var user model.User
  737. err := json.NewDecoder(c.Request.Body).Decode(&user)
  738. user.Username = strings.TrimSpace(user.Username)
  739. if err != nil || user.Username == "" || user.Password == "" {
  740. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  741. return
  742. }
  743. if err := common.Validate.Struct(&user); err != nil {
  744. common.ApiErrorI18n(c, i18n.MsgUserInputInvalid, map[string]any{"Error": err.Error()})
  745. return
  746. }
  747. if user.DisplayName == "" {
  748. user.DisplayName = user.Username
  749. }
  750. myRole := c.GetInt("role")
  751. if user.Role >= myRole {
  752. common.ApiErrorI18n(c, i18n.MsgUserCannotCreateHigherLevel)
  753. return
  754. }
  755. // Even for admin users, we cannot fully trust them!
  756. cleanUser := model.User{
  757. Username: user.Username,
  758. Password: user.Password,
  759. DisplayName: user.DisplayName,
  760. Role: user.Role, // 保持管理员设置的角色
  761. }
  762. if err := cleanUser.Insert(0); err != nil {
  763. common.ApiError(c, err)
  764. return
  765. }
  766. c.JSON(http.StatusOK, gin.H{
  767. "success": true,
  768. "message": "",
  769. })
  770. return
  771. }
  772. type ManageRequest struct {
  773. Id int `json:"id"`
  774. Action string `json:"action"`
  775. }
  776. // ManageUser Only admin user can do this
  777. func ManageUser(c *gin.Context) {
  778. var req ManageRequest
  779. err := json.NewDecoder(c.Request.Body).Decode(&req)
  780. if err != nil {
  781. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  782. return
  783. }
  784. user := model.User{
  785. Id: req.Id,
  786. }
  787. // Fill attributes
  788. model.DB.Unscoped().Where(&user).First(&user)
  789. if user.Id == 0 {
  790. common.ApiErrorI18n(c, i18n.MsgUserNotExists)
  791. return
  792. }
  793. myRole := c.GetInt("role")
  794. if myRole <= user.Role && myRole != common.RoleRootUser {
  795. common.ApiErrorI18n(c, i18n.MsgUserNoPermissionHigherLevel)
  796. return
  797. }
  798. switch req.Action {
  799. case "disable":
  800. user.Status = common.UserStatusDisabled
  801. if user.Role == common.RoleRootUser {
  802. common.ApiErrorI18n(c, i18n.MsgUserCannotDisableRootUser)
  803. return
  804. }
  805. case "enable":
  806. user.Status = common.UserStatusEnabled
  807. case "delete":
  808. if user.Role == common.RoleRootUser {
  809. common.ApiErrorI18n(c, i18n.MsgUserCannotDeleteRootUser)
  810. return
  811. }
  812. if err := user.Delete(); err != nil {
  813. c.JSON(http.StatusOK, gin.H{
  814. "success": false,
  815. "message": err.Error(),
  816. })
  817. return
  818. }
  819. case "promote":
  820. if myRole != common.RoleRootUser {
  821. common.ApiErrorI18n(c, i18n.MsgUserAdminCannotPromote)
  822. return
  823. }
  824. if user.Role >= common.RoleAdminUser {
  825. common.ApiErrorI18n(c, i18n.MsgUserAlreadyAdmin)
  826. return
  827. }
  828. user.Role = common.RoleAdminUser
  829. case "demote":
  830. if user.Role == common.RoleRootUser {
  831. common.ApiErrorI18n(c, i18n.MsgUserCannotDemoteRootUser)
  832. return
  833. }
  834. if user.Role == common.RoleCommonUser {
  835. common.ApiErrorI18n(c, i18n.MsgUserAlreadyCommon)
  836. return
  837. }
  838. user.Role = common.RoleCommonUser
  839. }
  840. if err := user.Update(false); err != nil {
  841. common.ApiError(c, err)
  842. return
  843. }
  844. clearUser := model.User{
  845. Role: user.Role,
  846. Status: user.Status,
  847. }
  848. c.JSON(http.StatusOK, gin.H{
  849. "success": true,
  850. "message": "",
  851. "data": clearUser,
  852. })
  853. return
  854. }
  855. func EmailBind(c *gin.Context) {
  856. email := c.Query("email")
  857. code := c.Query("code")
  858. if !common.VerifyCodeWithKey(email, code, common.EmailVerificationPurpose) {
  859. common.ApiErrorI18n(c, i18n.MsgUserVerificationCodeError)
  860. return
  861. }
  862. session := sessions.Default(c)
  863. id := session.Get("id")
  864. user := model.User{
  865. Id: id.(int),
  866. }
  867. err := user.FillUserById()
  868. if err != nil {
  869. common.ApiError(c, err)
  870. return
  871. }
  872. user.Email = email
  873. // no need to check if this email already taken, because we have used verification code to check it
  874. err = user.Update(false)
  875. if err != nil {
  876. common.ApiError(c, err)
  877. return
  878. }
  879. c.JSON(http.StatusOK, gin.H{
  880. "success": true,
  881. "message": "",
  882. })
  883. return
  884. }
  885. type topUpRequest struct {
  886. Key string `json:"key"`
  887. }
  888. var topUpLocks sync.Map
  889. var topUpCreateLock sync.Mutex
  890. type topUpTryLock struct {
  891. ch chan struct{}
  892. }
  893. func newTopUpTryLock() *topUpTryLock {
  894. return &topUpTryLock{ch: make(chan struct{}, 1)}
  895. }
  896. func (l *topUpTryLock) TryLock() bool {
  897. select {
  898. case l.ch <- struct{}{}:
  899. return true
  900. default:
  901. return false
  902. }
  903. }
  904. func (l *topUpTryLock) Unlock() {
  905. select {
  906. case <-l.ch:
  907. default:
  908. }
  909. }
  910. func getTopUpLock(userID int) *topUpTryLock {
  911. if v, ok := topUpLocks.Load(userID); ok {
  912. return v.(*topUpTryLock)
  913. }
  914. topUpCreateLock.Lock()
  915. defer topUpCreateLock.Unlock()
  916. if v, ok := topUpLocks.Load(userID); ok {
  917. return v.(*topUpTryLock)
  918. }
  919. l := newTopUpTryLock()
  920. topUpLocks.Store(userID, l)
  921. return l
  922. }
  923. func TopUp(c *gin.Context) {
  924. id := c.GetInt("id")
  925. lock := getTopUpLock(id)
  926. if !lock.TryLock() {
  927. common.ApiErrorI18n(c, i18n.MsgUserTopUpProcessing)
  928. return
  929. }
  930. defer lock.Unlock()
  931. req := topUpRequest{}
  932. err := c.ShouldBindJSON(&req)
  933. if err != nil {
  934. common.ApiError(c, err)
  935. return
  936. }
  937. quota, err := model.Redeem(req.Key, id)
  938. if err != nil {
  939. if errors.Is(err, model.ErrRedeemFailed) {
  940. common.ApiErrorI18n(c, i18n.MsgRedeemFailed)
  941. return
  942. }
  943. common.ApiError(c, err)
  944. return
  945. }
  946. c.JSON(http.StatusOK, gin.H{
  947. "success": true,
  948. "message": "",
  949. "data": quota,
  950. })
  951. }
  952. type UpdateUserSettingRequest struct {
  953. QuotaWarningType string `json:"notify_type"`
  954. QuotaWarningThreshold float64 `json:"quota_warning_threshold"`
  955. WebhookUrl string `json:"webhook_url,omitempty"`
  956. WebhookSecret string `json:"webhook_secret,omitempty"`
  957. NotificationEmail string `json:"notification_email,omitempty"`
  958. BarkUrl string `json:"bark_url,omitempty"`
  959. GotifyUrl string `json:"gotify_url,omitempty"`
  960. GotifyToken string `json:"gotify_token,omitempty"`
  961. GotifyPriority int `json:"gotify_priority,omitempty"`
  962. AcceptUnsetModelRatioModel bool `json:"accept_unset_model_ratio_model"`
  963. RecordIpLog bool `json:"record_ip_log"`
  964. }
  965. func UpdateUserSetting(c *gin.Context) {
  966. var req UpdateUserSettingRequest
  967. if err := c.ShouldBindJSON(&req); err != nil {
  968. common.ApiErrorI18n(c, i18n.MsgInvalidParams)
  969. return
  970. }
  971. // 验证预警类型
  972. if req.QuotaWarningType != dto.NotifyTypeEmail && req.QuotaWarningType != dto.NotifyTypeWebhook && req.QuotaWarningType != dto.NotifyTypeBark && req.QuotaWarningType != dto.NotifyTypeGotify {
  973. common.ApiErrorI18n(c, i18n.MsgSettingInvalidType)
  974. return
  975. }
  976. // 验证预警阈值
  977. if req.QuotaWarningThreshold <= 0 {
  978. common.ApiErrorI18n(c, i18n.MsgQuotaThresholdGtZero)
  979. return
  980. }
  981. // 如果是webhook类型,验证webhook地址
  982. if req.QuotaWarningType == dto.NotifyTypeWebhook {
  983. if req.WebhookUrl == "" {
  984. common.ApiErrorI18n(c, i18n.MsgSettingWebhookEmpty)
  985. return
  986. }
  987. // 验证URL格式
  988. if _, err := url.ParseRequestURI(req.WebhookUrl); err != nil {
  989. common.ApiErrorI18n(c, i18n.MsgSettingWebhookInvalid)
  990. return
  991. }
  992. }
  993. // 如果是邮件类型,验证邮箱地址
  994. if req.QuotaWarningType == dto.NotifyTypeEmail && req.NotificationEmail != "" {
  995. // 验证邮箱格式
  996. if !strings.Contains(req.NotificationEmail, "@") {
  997. common.ApiErrorI18n(c, i18n.MsgSettingEmailInvalid)
  998. return
  999. }
  1000. }
  1001. // 如果是Bark类型,验证Bark URL
  1002. if req.QuotaWarningType == dto.NotifyTypeBark {
  1003. if req.BarkUrl == "" {
  1004. common.ApiErrorI18n(c, i18n.MsgSettingBarkUrlEmpty)
  1005. return
  1006. }
  1007. // 验证URL格式
  1008. if _, err := url.ParseRequestURI(req.BarkUrl); err != nil {
  1009. common.ApiErrorI18n(c, i18n.MsgSettingBarkUrlInvalid)
  1010. return
  1011. }
  1012. // 检查是否是HTTP或HTTPS
  1013. if !strings.HasPrefix(req.BarkUrl, "https://") && !strings.HasPrefix(req.BarkUrl, "http://") {
  1014. common.ApiErrorI18n(c, i18n.MsgSettingUrlMustHttp)
  1015. return
  1016. }
  1017. }
  1018. // 如果是Gotify类型,验证Gotify URL和Token
  1019. if req.QuotaWarningType == dto.NotifyTypeGotify {
  1020. if req.GotifyUrl == "" {
  1021. common.ApiErrorI18n(c, i18n.MsgSettingGotifyUrlEmpty)
  1022. return
  1023. }
  1024. if req.GotifyToken == "" {
  1025. common.ApiErrorI18n(c, i18n.MsgSettingGotifyTokenEmpty)
  1026. return
  1027. }
  1028. // 验证URL格式
  1029. if _, err := url.ParseRequestURI(req.GotifyUrl); err != nil {
  1030. common.ApiErrorI18n(c, i18n.MsgSettingGotifyUrlInvalid)
  1031. return
  1032. }
  1033. // 检查是否是HTTP或HTTPS
  1034. if !strings.HasPrefix(req.GotifyUrl, "https://") && !strings.HasPrefix(req.GotifyUrl, "http://") {
  1035. common.ApiErrorI18n(c, i18n.MsgSettingUrlMustHttp)
  1036. return
  1037. }
  1038. }
  1039. userId := c.GetInt("id")
  1040. user, err := model.GetUserById(userId, true)
  1041. if err != nil {
  1042. common.ApiError(c, err)
  1043. return
  1044. }
  1045. // 构建设置
  1046. settings := dto.UserSetting{
  1047. NotifyType: req.QuotaWarningType,
  1048. QuotaWarningThreshold: req.QuotaWarningThreshold,
  1049. AcceptUnsetRatioModel: req.AcceptUnsetModelRatioModel,
  1050. RecordIpLog: req.RecordIpLog,
  1051. }
  1052. // 如果是webhook类型,添加webhook相关设置
  1053. if req.QuotaWarningType == dto.NotifyTypeWebhook {
  1054. settings.WebhookUrl = req.WebhookUrl
  1055. if req.WebhookSecret != "" {
  1056. settings.WebhookSecret = req.WebhookSecret
  1057. }
  1058. }
  1059. // 如果提供了通知邮箱,添加到设置中
  1060. if req.QuotaWarningType == dto.NotifyTypeEmail && req.NotificationEmail != "" {
  1061. settings.NotificationEmail = req.NotificationEmail
  1062. }
  1063. // 如果是Bark类型,添加Bark URL到设置中
  1064. if req.QuotaWarningType == dto.NotifyTypeBark {
  1065. settings.BarkUrl = req.BarkUrl
  1066. }
  1067. // 如果是Gotify类型,添加Gotify配置到设置中
  1068. if req.QuotaWarningType == dto.NotifyTypeGotify {
  1069. settings.GotifyUrl = req.GotifyUrl
  1070. settings.GotifyToken = req.GotifyToken
  1071. // Gotify优先级范围0-10,超出范围则使用默认值5
  1072. if req.GotifyPriority < 0 || req.GotifyPriority > 10 {
  1073. settings.GotifyPriority = 5
  1074. } else {
  1075. settings.GotifyPriority = req.GotifyPriority
  1076. }
  1077. }
  1078. // 更新用户设置
  1079. user.SetSetting(settings)
  1080. if err := user.Update(false); err != nil {
  1081. common.ApiErrorI18n(c, i18n.MsgUpdateFailed)
  1082. return
  1083. }
  1084. common.ApiSuccessI18n(c, i18n.MsgSettingSaved, nil)
  1085. }