user.go 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028
  1. package controller
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "net/http"
  6. "net/url"
  7. "one-api/common"
  8. "one-api/dto"
  9. "one-api/logger"
  10. "one-api/model"
  11. "one-api/setting"
  12. "strconv"
  13. "strings"
  14. "sync"
  15. "one-api/constant"
  16. "github.com/gin-contrib/sessions"
  17. "github.com/gin-gonic/gin"
  18. )
  19. type LoginRequest struct {
  20. Username string `json:"username"`
  21. Password string `json:"password"`
  22. }
  23. func Login(c *gin.Context) {
  24. if !common.PasswordLoginEnabled {
  25. c.JSON(http.StatusOK, gin.H{
  26. "message": "管理员关闭了密码登录",
  27. "success": false,
  28. })
  29. return
  30. }
  31. var loginRequest LoginRequest
  32. err := json.NewDecoder(c.Request.Body).Decode(&loginRequest)
  33. if err != nil {
  34. c.JSON(http.StatusOK, gin.H{
  35. "message": "无效的参数",
  36. "success": false,
  37. })
  38. return
  39. }
  40. username := loginRequest.Username
  41. password := loginRequest.Password
  42. if username == "" || password == "" {
  43. c.JSON(http.StatusOK, gin.H{
  44. "message": "无效的参数",
  45. "success": false,
  46. })
  47. return
  48. }
  49. user := model.User{
  50. Username: username,
  51. Password: password,
  52. }
  53. err = user.ValidateAndFill()
  54. if err != nil {
  55. c.JSON(http.StatusOK, gin.H{
  56. "message": err.Error(),
  57. "success": false,
  58. })
  59. return
  60. }
  61. // 检查是否启用2FA
  62. if model.IsTwoFAEnabled(user.Id) {
  63. // 设置pending session,等待2FA验证
  64. session := sessions.Default(c)
  65. session.Set("pending_username", user.Username)
  66. session.Set("pending_user_id", user.Id)
  67. err := session.Save()
  68. if err != nil {
  69. c.JSON(http.StatusOK, gin.H{
  70. "message": "无法保存会话信息,请重试",
  71. "success": false,
  72. })
  73. return
  74. }
  75. c.JSON(http.StatusOK, gin.H{
  76. "message": "请输入两步验证码",
  77. "success": true,
  78. "data": map[string]interface{}{
  79. "require_2fa": true,
  80. },
  81. })
  82. return
  83. }
  84. setupLogin(&user, c)
  85. }
  86. // setup session & cookies and then return user info
  87. func setupLogin(user *model.User, c *gin.Context) {
  88. session := sessions.Default(c)
  89. session.Set("id", user.Id)
  90. session.Set("username", user.Username)
  91. session.Set("role", user.Role)
  92. session.Set("status", user.Status)
  93. session.Set("group", user.Group)
  94. err := session.Save()
  95. if err != nil {
  96. c.JSON(http.StatusOK, gin.H{
  97. "message": "无法保存会话信息,请重试",
  98. "success": false,
  99. })
  100. return
  101. }
  102. cleanUser := model.User{
  103. Id: user.Id,
  104. Username: user.Username,
  105. DisplayName: user.DisplayName,
  106. Role: user.Role,
  107. Status: user.Status,
  108. Group: user.Group,
  109. }
  110. c.JSON(http.StatusOK, gin.H{
  111. "message": "",
  112. "success": true,
  113. "data": cleanUser,
  114. })
  115. }
  116. func Logout(c *gin.Context) {
  117. session := sessions.Default(c)
  118. session.Clear()
  119. err := session.Save()
  120. if err != nil {
  121. c.JSON(http.StatusOK, gin.H{
  122. "message": err.Error(),
  123. "success": false,
  124. })
  125. return
  126. }
  127. c.JSON(http.StatusOK, gin.H{
  128. "message": "",
  129. "success": true,
  130. })
  131. }
  132. func Register(c *gin.Context) {
  133. if !common.RegisterEnabled {
  134. c.JSON(http.StatusOK, gin.H{
  135. "message": "管理员关闭了新用户注册",
  136. "success": false,
  137. })
  138. return
  139. }
  140. if !common.PasswordRegisterEnabled {
  141. c.JSON(http.StatusOK, gin.H{
  142. "message": "管理员关闭了通过密码进行注册,请使用第三方账户验证的形式进行注册",
  143. "success": false,
  144. })
  145. return
  146. }
  147. var user model.User
  148. err := json.NewDecoder(c.Request.Body).Decode(&user)
  149. if err != nil {
  150. c.JSON(http.StatusOK, gin.H{
  151. "success": false,
  152. "message": "无效的参数",
  153. })
  154. return
  155. }
  156. if err := common.Validate.Struct(&user); err != nil {
  157. c.JSON(http.StatusOK, gin.H{
  158. "success": false,
  159. "message": "输入不合法 " + err.Error(),
  160. })
  161. return
  162. }
  163. if common.EmailVerificationEnabled {
  164. if user.Email == "" || user.VerificationCode == "" {
  165. c.JSON(http.StatusOK, gin.H{
  166. "success": false,
  167. "message": "管理员开启了邮箱验证,请输入邮箱地址和验证码",
  168. })
  169. return
  170. }
  171. if !common.VerifyCodeWithKey(user.Email, user.VerificationCode, common.EmailVerificationPurpose) {
  172. c.JSON(http.StatusOK, gin.H{
  173. "success": false,
  174. "message": "验证码错误或已过期",
  175. })
  176. return
  177. }
  178. }
  179. exist, err := model.CheckUserExistOrDeleted(user.Username, user.Email)
  180. if err != nil {
  181. c.JSON(http.StatusOK, gin.H{
  182. "success": false,
  183. "message": "数据库错误,请稍后重试",
  184. })
  185. common.SysLog(fmt.Sprintf("CheckUserExistOrDeleted error: %v", err))
  186. return
  187. }
  188. if exist {
  189. c.JSON(http.StatusOK, gin.H{
  190. "success": false,
  191. "message": "用户名已存在,或已注销",
  192. })
  193. return
  194. }
  195. affCode := user.AffCode // this code is the inviter's code, not the user's own code
  196. inviterId, _ := model.GetUserIdByAffCode(affCode)
  197. cleanUser := model.User{
  198. Username: user.Username,
  199. Password: user.Password,
  200. DisplayName: user.Username,
  201. InviterId: inviterId,
  202. }
  203. if common.EmailVerificationEnabled {
  204. cleanUser.Email = user.Email
  205. }
  206. if err := cleanUser.Insert(inviterId); err != nil {
  207. common.ApiError(c, err)
  208. return
  209. }
  210. // 获取插入后的用户ID
  211. var insertedUser model.User
  212. if err := model.DB.Where("username = ?", cleanUser.Username).First(&insertedUser).Error; err != nil {
  213. c.JSON(http.StatusOK, gin.H{
  214. "success": false,
  215. "message": "用户注册失败或用户ID获取失败",
  216. })
  217. return
  218. }
  219. // 生成默认令牌
  220. if constant.GenerateDefaultToken {
  221. key, err := common.GenerateKey()
  222. if err != nil {
  223. c.JSON(http.StatusOK, gin.H{
  224. "success": false,
  225. "message": "生成默认令牌失败",
  226. })
  227. common.SysLog("failed to generate token key: " + err.Error())
  228. return
  229. }
  230. // 生成默认令牌
  231. token := model.Token{
  232. UserId: insertedUser.Id, // 使用插入后的用户ID
  233. Name: cleanUser.Username + "的初始令牌",
  234. Key: key,
  235. CreatedTime: common.GetTimestamp(),
  236. AccessedTime: common.GetTimestamp(),
  237. ExpiredTime: -1, // 永不过期
  238. RemainQuota: 500000, // 示例额度
  239. UnlimitedQuota: true,
  240. ModelLimitsEnabled: false,
  241. }
  242. if setting.DefaultUseAutoGroup {
  243. token.Group = "auto"
  244. }
  245. if err := token.Insert(); err != nil {
  246. c.JSON(http.StatusOK, gin.H{
  247. "success": false,
  248. "message": "创建默认令牌失败",
  249. })
  250. return
  251. }
  252. }
  253. c.JSON(http.StatusOK, gin.H{
  254. "success": true,
  255. "message": "",
  256. })
  257. return
  258. }
  259. func GetAllUsers(c *gin.Context) {
  260. pageInfo := common.GetPageQuery(c)
  261. users, total, err := model.GetAllUsers(pageInfo)
  262. if err != nil {
  263. common.ApiError(c, err)
  264. return
  265. }
  266. pageInfo.SetTotal(int(total))
  267. pageInfo.SetItems(users)
  268. common.ApiSuccess(c, pageInfo)
  269. return
  270. }
  271. func SearchUsers(c *gin.Context) {
  272. keyword := c.Query("keyword")
  273. group := c.Query("group")
  274. pageInfo := common.GetPageQuery(c)
  275. users, total, err := model.SearchUsers(keyword, group, pageInfo.GetStartIdx(), pageInfo.GetPageSize())
  276. if err != nil {
  277. common.ApiError(c, err)
  278. return
  279. }
  280. pageInfo.SetTotal(int(total))
  281. pageInfo.SetItems(users)
  282. common.ApiSuccess(c, pageInfo)
  283. return
  284. }
  285. func GetUser(c *gin.Context) {
  286. id, err := strconv.Atoi(c.Param("id"))
  287. if err != nil {
  288. common.ApiError(c, err)
  289. return
  290. }
  291. user, err := model.GetUserById(id, false)
  292. if err != nil {
  293. common.ApiError(c, err)
  294. return
  295. }
  296. myRole := c.GetInt("role")
  297. if myRole <= user.Role && myRole != common.RoleRootUser {
  298. c.JSON(http.StatusOK, gin.H{
  299. "success": false,
  300. "message": "无权获取同级或更高等级用户的信息",
  301. })
  302. return
  303. }
  304. c.JSON(http.StatusOK, gin.H{
  305. "success": true,
  306. "message": "",
  307. "data": user,
  308. })
  309. return
  310. }
  311. func GenerateAccessToken(c *gin.Context) {
  312. id := c.GetInt("id")
  313. user, err := model.GetUserById(id, true)
  314. if err != nil {
  315. common.ApiError(c, err)
  316. return
  317. }
  318. // get rand int 28-32
  319. randI := common.GetRandomInt(4)
  320. key, err := common.GenerateRandomKey(29 + randI)
  321. if err != nil {
  322. c.JSON(http.StatusOK, gin.H{
  323. "success": false,
  324. "message": "生成失败",
  325. })
  326. common.SysLog("failed to generate key: " + err.Error())
  327. return
  328. }
  329. user.SetAccessToken(key)
  330. if model.DB.Where("access_token = ?", user.AccessToken).First(user).RowsAffected != 0 {
  331. c.JSON(http.StatusOK, gin.H{
  332. "success": false,
  333. "message": "请重试,系统生成的 UUID 竟然重复了!",
  334. })
  335. return
  336. }
  337. if err := user.Update(false); err != nil {
  338. common.ApiError(c, err)
  339. return
  340. }
  341. c.JSON(http.StatusOK, gin.H{
  342. "success": true,
  343. "message": "",
  344. "data": user.AccessToken,
  345. })
  346. return
  347. }
  348. type TransferAffQuotaRequest struct {
  349. Quota int `json:"quota" binding:"required"`
  350. }
  351. func TransferAffQuota(c *gin.Context) {
  352. id := c.GetInt("id")
  353. user, err := model.GetUserById(id, true)
  354. if err != nil {
  355. common.ApiError(c, err)
  356. return
  357. }
  358. tran := TransferAffQuotaRequest{}
  359. if err := c.ShouldBindJSON(&tran); err != nil {
  360. common.ApiError(c, err)
  361. return
  362. }
  363. err = user.TransferAffQuotaToQuota(tran.Quota)
  364. if err != nil {
  365. c.JSON(http.StatusOK, gin.H{
  366. "success": false,
  367. "message": "划转失败 " + err.Error(),
  368. })
  369. return
  370. }
  371. c.JSON(http.StatusOK, gin.H{
  372. "success": true,
  373. "message": "划转成功",
  374. })
  375. }
  376. func GetAffCode(c *gin.Context) {
  377. id := c.GetInt("id")
  378. user, err := model.GetUserById(id, true)
  379. if err != nil {
  380. common.ApiError(c, err)
  381. return
  382. }
  383. if user.AffCode == "" {
  384. user.AffCode = common.GetRandomString(4)
  385. if err := user.Update(false); err != nil {
  386. c.JSON(http.StatusOK, gin.H{
  387. "success": false,
  388. "message": err.Error(),
  389. })
  390. return
  391. }
  392. }
  393. c.JSON(http.StatusOK, gin.H{
  394. "success": true,
  395. "message": "",
  396. "data": user.AffCode,
  397. })
  398. return
  399. }
  400. func GetSelf(c *gin.Context) {
  401. id := c.GetInt("id")
  402. user, err := model.GetUserById(id, false)
  403. if err != nil {
  404. common.ApiError(c, err)
  405. return
  406. }
  407. // Hide admin remarks: set to empty to trigger omitempty tag, ensuring the remark field is not included in JSON returned to regular users
  408. user.Remark = ""
  409. c.JSON(http.StatusOK, gin.H{
  410. "success": true,
  411. "message": "",
  412. "data": user,
  413. })
  414. return
  415. }
  416. func GetUserModels(c *gin.Context) {
  417. id, err := strconv.Atoi(c.Param("id"))
  418. if err != nil {
  419. id = c.GetInt("id")
  420. }
  421. user, err := model.GetUserCache(id)
  422. if err != nil {
  423. common.ApiError(c, err)
  424. return
  425. }
  426. groups := setting.GetUserUsableGroups(user.Group)
  427. var models []string
  428. for group := range groups {
  429. for _, g := range model.GetGroupEnabledModels(group) {
  430. if !common.StringsContains(models, g) {
  431. models = append(models, g)
  432. }
  433. }
  434. }
  435. c.JSON(http.StatusOK, gin.H{
  436. "success": true,
  437. "message": "",
  438. "data": models,
  439. })
  440. return
  441. }
  442. func UpdateUser(c *gin.Context) {
  443. var updatedUser model.User
  444. err := json.NewDecoder(c.Request.Body).Decode(&updatedUser)
  445. if err != nil || updatedUser.Id == 0 {
  446. c.JSON(http.StatusOK, gin.H{
  447. "success": false,
  448. "message": "无效的参数",
  449. })
  450. return
  451. }
  452. if updatedUser.Password == "" {
  453. updatedUser.Password = "$I_LOVE_U" // make Validator happy :)
  454. }
  455. if err := common.Validate.Struct(&updatedUser); err != nil {
  456. c.JSON(http.StatusOK, gin.H{
  457. "success": false,
  458. "message": "输入不合法 " + err.Error(),
  459. })
  460. return
  461. }
  462. originUser, err := model.GetUserById(updatedUser.Id, false)
  463. if err != nil {
  464. common.ApiError(c, err)
  465. return
  466. }
  467. myRole := c.GetInt("role")
  468. if myRole <= originUser.Role && myRole != common.RoleRootUser {
  469. c.JSON(http.StatusOK, gin.H{
  470. "success": false,
  471. "message": "无权更新同权限等级或更高权限等级的用户信息",
  472. })
  473. return
  474. }
  475. if myRole <= updatedUser.Role && myRole != common.RoleRootUser {
  476. c.JSON(http.StatusOK, gin.H{
  477. "success": false,
  478. "message": "无权将其他用户权限等级提升到大于等于自己的权限等级",
  479. })
  480. return
  481. }
  482. if updatedUser.Password == "$I_LOVE_U" {
  483. updatedUser.Password = "" // rollback to what it should be
  484. }
  485. updatePassword := updatedUser.Password != ""
  486. if err := updatedUser.Edit(updatePassword); err != nil {
  487. common.ApiError(c, err)
  488. return
  489. }
  490. if originUser.Quota != updatedUser.Quota {
  491. model.RecordLog(originUser.Id, model.LogTypeManage, fmt.Sprintf("管理员将用户额度从 %s修改为 %s", logger.LogQuota(originUser.Quota), logger.LogQuota(updatedUser.Quota)))
  492. }
  493. c.JSON(http.StatusOK, gin.H{
  494. "success": true,
  495. "message": "",
  496. })
  497. return
  498. }
  499. func UpdateSelf(c *gin.Context) {
  500. var user model.User
  501. err := json.NewDecoder(c.Request.Body).Decode(&user)
  502. if err != nil {
  503. c.JSON(http.StatusOK, gin.H{
  504. "success": false,
  505. "message": "无效的参数",
  506. })
  507. return
  508. }
  509. if user.Password == "" {
  510. user.Password = "$I_LOVE_U" // make Validator happy :)
  511. }
  512. if err := common.Validate.Struct(&user); err != nil {
  513. c.JSON(http.StatusOK, gin.H{
  514. "success": false,
  515. "message": "输入不合法 " + err.Error(),
  516. })
  517. return
  518. }
  519. cleanUser := model.User{
  520. Id: c.GetInt("id"),
  521. Username: user.Username,
  522. Password: user.Password,
  523. DisplayName: user.DisplayName,
  524. }
  525. if user.Password == "$I_LOVE_U" {
  526. user.Password = "" // rollback to what it should be
  527. cleanUser.Password = ""
  528. }
  529. updatePassword, err := checkUpdatePassword(user.OriginalPassword, user.Password, cleanUser.Id)
  530. if err != nil {
  531. common.ApiError(c, err)
  532. return
  533. }
  534. if err := cleanUser.Update(updatePassword); err != nil {
  535. common.ApiError(c, err)
  536. return
  537. }
  538. c.JSON(http.StatusOK, gin.H{
  539. "success": true,
  540. "message": "",
  541. })
  542. return
  543. }
  544. func checkUpdatePassword(originalPassword string, newPassword string, userId int) (updatePassword bool, err error) {
  545. var currentUser *model.User
  546. currentUser, err = model.GetUserById(userId, true)
  547. if err != nil {
  548. return
  549. }
  550. if !common.ValidatePasswordAndHash(originalPassword, currentUser.Password) {
  551. err = fmt.Errorf("原密码错误")
  552. return
  553. }
  554. if newPassword == "" {
  555. return
  556. }
  557. updatePassword = true
  558. return
  559. }
  560. func DeleteUser(c *gin.Context) {
  561. id, err := strconv.Atoi(c.Param("id"))
  562. if err != nil {
  563. common.ApiError(c, err)
  564. return
  565. }
  566. originUser, err := model.GetUserById(id, false)
  567. if err != nil {
  568. common.ApiError(c, err)
  569. return
  570. }
  571. myRole := c.GetInt("role")
  572. if myRole <= originUser.Role {
  573. c.JSON(http.StatusOK, gin.H{
  574. "success": false,
  575. "message": "无权删除同权限等级或更高权限等级的用户",
  576. })
  577. return
  578. }
  579. err = model.HardDeleteUserById(id)
  580. if err != nil {
  581. c.JSON(http.StatusOK, gin.H{
  582. "success": true,
  583. "message": "",
  584. })
  585. return
  586. }
  587. }
  588. func DeleteSelf(c *gin.Context) {
  589. id := c.GetInt("id")
  590. user, _ := model.GetUserById(id, false)
  591. if user.Role == common.RoleRootUser {
  592. c.JSON(http.StatusOK, gin.H{
  593. "success": false,
  594. "message": "不能删除超级管理员账户",
  595. })
  596. return
  597. }
  598. err := model.DeleteUserById(id)
  599. if err != nil {
  600. common.ApiError(c, err)
  601. return
  602. }
  603. c.JSON(http.StatusOK, gin.H{
  604. "success": true,
  605. "message": "",
  606. })
  607. return
  608. }
  609. func CreateUser(c *gin.Context) {
  610. var user model.User
  611. err := json.NewDecoder(c.Request.Body).Decode(&user)
  612. user.Username = strings.TrimSpace(user.Username)
  613. if err != nil || user.Username == "" || user.Password == "" {
  614. c.JSON(http.StatusOK, gin.H{
  615. "success": false,
  616. "message": "无效的参数",
  617. })
  618. return
  619. }
  620. if err := common.Validate.Struct(&user); err != nil {
  621. c.JSON(http.StatusOK, gin.H{
  622. "success": false,
  623. "message": "输入不合法 " + err.Error(),
  624. })
  625. return
  626. }
  627. if user.DisplayName == "" {
  628. user.DisplayName = user.Username
  629. }
  630. myRole := c.GetInt("role")
  631. if user.Role >= myRole {
  632. c.JSON(http.StatusOK, gin.H{
  633. "success": false,
  634. "message": "无法创建权限大于等于自己的用户",
  635. })
  636. return
  637. }
  638. // Even for admin users, we cannot fully trust them!
  639. cleanUser := model.User{
  640. Username: user.Username,
  641. Password: user.Password,
  642. DisplayName: user.DisplayName,
  643. }
  644. if err := cleanUser.Insert(0); err != nil {
  645. common.ApiError(c, err)
  646. return
  647. }
  648. c.JSON(http.StatusOK, gin.H{
  649. "success": true,
  650. "message": "",
  651. })
  652. return
  653. }
  654. type ManageRequest struct {
  655. Id int `json:"id"`
  656. Action string `json:"action"`
  657. }
  658. // ManageUser Only admin user can do this
  659. func ManageUser(c *gin.Context) {
  660. var req ManageRequest
  661. err := json.NewDecoder(c.Request.Body).Decode(&req)
  662. if err != nil {
  663. c.JSON(http.StatusOK, gin.H{
  664. "success": false,
  665. "message": "无效的参数",
  666. })
  667. return
  668. }
  669. user := model.User{
  670. Id: req.Id,
  671. }
  672. // Fill attributes
  673. model.DB.Unscoped().Where(&user).First(&user)
  674. if user.Id == 0 {
  675. c.JSON(http.StatusOK, gin.H{
  676. "success": false,
  677. "message": "用户不存在",
  678. })
  679. return
  680. }
  681. myRole := c.GetInt("role")
  682. if myRole <= user.Role && myRole != common.RoleRootUser {
  683. c.JSON(http.StatusOK, gin.H{
  684. "success": false,
  685. "message": "无权更新同权限等级或更高权限等级的用户信息",
  686. })
  687. return
  688. }
  689. switch req.Action {
  690. case "disable":
  691. user.Status = common.UserStatusDisabled
  692. if user.Role == common.RoleRootUser {
  693. c.JSON(http.StatusOK, gin.H{
  694. "success": false,
  695. "message": "无法禁用超级管理员用户",
  696. })
  697. return
  698. }
  699. case "enable":
  700. user.Status = common.UserStatusEnabled
  701. case "delete":
  702. if user.Role == common.RoleRootUser {
  703. c.JSON(http.StatusOK, gin.H{
  704. "success": false,
  705. "message": "无法删除超级管理员用户",
  706. })
  707. return
  708. }
  709. if err := user.Delete(); err != nil {
  710. c.JSON(http.StatusOK, gin.H{
  711. "success": false,
  712. "message": err.Error(),
  713. })
  714. return
  715. }
  716. case "promote":
  717. if myRole != common.RoleRootUser {
  718. c.JSON(http.StatusOK, gin.H{
  719. "success": false,
  720. "message": "普通管理员用户无法提升其他用户为管理员",
  721. })
  722. return
  723. }
  724. if user.Role >= common.RoleAdminUser {
  725. c.JSON(http.StatusOK, gin.H{
  726. "success": false,
  727. "message": "该用户已经是管理员",
  728. })
  729. return
  730. }
  731. user.Role = common.RoleAdminUser
  732. case "demote":
  733. if user.Role == common.RoleRootUser {
  734. c.JSON(http.StatusOK, gin.H{
  735. "success": false,
  736. "message": "无法降级超级管理员用户",
  737. })
  738. return
  739. }
  740. if user.Role == common.RoleCommonUser {
  741. c.JSON(http.StatusOK, gin.H{
  742. "success": false,
  743. "message": "该用户已经是普通用户",
  744. })
  745. return
  746. }
  747. user.Role = common.RoleCommonUser
  748. }
  749. if err := user.Update(false); err != nil {
  750. common.ApiError(c, err)
  751. return
  752. }
  753. clearUser := model.User{
  754. Role: user.Role,
  755. Status: user.Status,
  756. }
  757. c.JSON(http.StatusOK, gin.H{
  758. "success": true,
  759. "message": "",
  760. "data": clearUser,
  761. })
  762. return
  763. }
  764. func EmailBind(c *gin.Context) {
  765. email := c.Query("email")
  766. code := c.Query("code")
  767. if !common.VerifyCodeWithKey(email, code, common.EmailVerificationPurpose) {
  768. c.JSON(http.StatusOK, gin.H{
  769. "success": false,
  770. "message": "验证码错误或已过期",
  771. })
  772. return
  773. }
  774. session := sessions.Default(c)
  775. id := session.Get("id")
  776. user := model.User{
  777. Id: id.(int),
  778. }
  779. err := user.FillUserById()
  780. if err != nil {
  781. common.ApiError(c, err)
  782. return
  783. }
  784. user.Email = email
  785. // no need to check if this email already taken, because we have used verification code to check it
  786. err = user.Update(false)
  787. if err != nil {
  788. common.ApiError(c, err)
  789. return
  790. }
  791. c.JSON(http.StatusOK, gin.H{
  792. "success": true,
  793. "message": "",
  794. })
  795. return
  796. }
  797. type topUpRequest struct {
  798. Key string `json:"key"`
  799. }
  800. var topUpLocks sync.Map
  801. var topUpCreateLock sync.Mutex
  802. type topUpTryLock struct {
  803. ch chan struct{}
  804. }
  805. func newTopUpTryLock() *topUpTryLock {
  806. return &topUpTryLock{ch: make(chan struct{}, 1)}
  807. }
  808. func (l *topUpTryLock) TryLock() bool {
  809. select {
  810. case l.ch <- struct{}{}:
  811. return true
  812. default:
  813. return false
  814. }
  815. }
  816. func (l *topUpTryLock) Unlock() {
  817. select {
  818. case <-l.ch:
  819. default:
  820. }
  821. }
  822. func getTopUpLock(userID int) *topUpTryLock {
  823. if v, ok := topUpLocks.Load(userID); ok {
  824. return v.(*topUpTryLock)
  825. }
  826. topUpCreateLock.Lock()
  827. defer topUpCreateLock.Unlock()
  828. if v, ok := topUpLocks.Load(userID); ok {
  829. return v.(*topUpTryLock)
  830. }
  831. l := newTopUpTryLock()
  832. topUpLocks.Store(userID, l)
  833. return l
  834. }
  835. func TopUp(c *gin.Context) {
  836. id := c.GetInt("id")
  837. lock := getTopUpLock(id)
  838. if !lock.TryLock() {
  839. c.JSON(http.StatusOK, gin.H{
  840. "success": false,
  841. "message": "充值处理中,请稍后重试",
  842. })
  843. return
  844. }
  845. defer lock.Unlock()
  846. req := topUpRequest{}
  847. err := c.ShouldBindJSON(&req)
  848. if err != nil {
  849. common.ApiError(c, err)
  850. return
  851. }
  852. quota, err := model.Redeem(req.Key, id)
  853. if err != nil {
  854. common.ApiError(c, err)
  855. return
  856. }
  857. c.JSON(http.StatusOK, gin.H{
  858. "success": true,
  859. "message": "",
  860. "data": quota,
  861. })
  862. }
  863. type UpdateUserSettingRequest struct {
  864. QuotaWarningType string `json:"notify_type"`
  865. QuotaWarningThreshold float64 `json:"quota_warning_threshold"`
  866. WebhookUrl string `json:"webhook_url,omitempty"`
  867. WebhookSecret string `json:"webhook_secret,omitempty"`
  868. NotificationEmail string `json:"notification_email,omitempty"`
  869. AcceptUnsetModelRatioModel bool `json:"accept_unset_model_ratio_model"`
  870. RecordIpLog bool `json:"record_ip_log"`
  871. }
  872. func UpdateUserSetting(c *gin.Context) {
  873. var req UpdateUserSettingRequest
  874. if err := c.ShouldBindJSON(&req); err != nil {
  875. c.JSON(http.StatusOK, gin.H{
  876. "success": false,
  877. "message": "无效的参数",
  878. })
  879. return
  880. }
  881. // 验证预警类型
  882. if req.QuotaWarningType != dto.NotifyTypeEmail && req.QuotaWarningType != dto.NotifyTypeWebhook {
  883. c.JSON(http.StatusOK, gin.H{
  884. "success": false,
  885. "message": "无效的预警类型",
  886. })
  887. return
  888. }
  889. // 验证预警阈值
  890. if req.QuotaWarningThreshold <= 0 {
  891. c.JSON(http.StatusOK, gin.H{
  892. "success": false,
  893. "message": "预警阈值必须大于0",
  894. })
  895. return
  896. }
  897. // 如果是webhook类型,验证webhook地址
  898. if req.QuotaWarningType == dto.NotifyTypeWebhook {
  899. if req.WebhookUrl == "" {
  900. c.JSON(http.StatusOK, gin.H{
  901. "success": false,
  902. "message": "Webhook地址不能为空",
  903. })
  904. return
  905. }
  906. // 验证URL格式
  907. if _, err := url.ParseRequestURI(req.WebhookUrl); err != nil {
  908. c.JSON(http.StatusOK, gin.H{
  909. "success": false,
  910. "message": "无效的Webhook地址",
  911. })
  912. return
  913. }
  914. }
  915. // 如果是邮件类型,验证邮箱地址
  916. if req.QuotaWarningType == dto.NotifyTypeEmail && req.NotificationEmail != "" {
  917. // 验证邮箱格式
  918. if !strings.Contains(req.NotificationEmail, "@") {
  919. c.JSON(http.StatusOK, gin.H{
  920. "success": false,
  921. "message": "无效的邮箱地址",
  922. })
  923. return
  924. }
  925. }
  926. userId := c.GetInt("id")
  927. user, err := model.GetUserById(userId, true)
  928. if err != nil {
  929. common.ApiError(c, err)
  930. return
  931. }
  932. // 构建设置
  933. settings := dto.UserSetting{
  934. NotifyType: req.QuotaWarningType,
  935. QuotaWarningThreshold: req.QuotaWarningThreshold,
  936. AcceptUnsetRatioModel: req.AcceptUnsetModelRatioModel,
  937. RecordIpLog: req.RecordIpLog,
  938. }
  939. // 如果是webhook类型,添加webhook相关设置
  940. if req.QuotaWarningType == dto.NotifyTypeWebhook {
  941. settings.WebhookUrl = req.WebhookUrl
  942. if req.WebhookSecret != "" {
  943. settings.WebhookSecret = req.WebhookSecret
  944. }
  945. }
  946. // 如果提供了通知邮箱,添加到设置中
  947. if req.QuotaWarningType == dto.NotifyTypeEmail && req.NotificationEmail != "" {
  948. settings.NotificationEmail = req.NotificationEmail
  949. }
  950. // 更新用户设置
  951. user.SetSetting(settings)
  952. if err := user.Update(false); err != nil {
  953. c.JSON(http.StatusOK, gin.H{
  954. "success": false,
  955. "message": "更新设置失败: " + err.Error(),
  956. })
  957. return
  958. }
  959. c.JSON(http.StatusOK, gin.H{
  960. "success": true,
  961. "message": "设置已更新",
  962. })
  963. }