api_uploaduser.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. package admin
  2. import (
  3. "fmt"
  4. "io"
  5. "net/http"
  6. "os"
  7. "path"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "github.com/bjdgyc/anylink/dbdata"
  12. "github.com/bjdgyc/anylink/pkg/utils"
  13. mapset "github.com/deckarep/golang-set"
  14. "github.com/spf13/cast"
  15. "github.com/xuri/excelize/v2"
  16. )
  17. func UserUpload(w http.ResponseWriter, r *http.Request) {
  18. r.ParseMultipartForm(8 << 20)
  19. file, header, err := r.FormFile("file")
  20. if err != nil || !strings.Contains(header.Filename, ".xlsx") || !strings.Contains(header.Filename, ".xls") {
  21. RespError(w, RespInternalErr, "文件解析失败:仅支持xlsx或xls文件")
  22. return
  23. }
  24. defer file.Close()
  25. // go/path-injection
  26. // base.Cfg.FilesPath 可以直接对外访问,不能上传文件到此
  27. fileName := path.Join(os.TempDir(), utils.RandomRunes(10))
  28. newFile, err := os.Create(fileName)
  29. if err != nil {
  30. RespError(w, RespInternalErr, "创建文件失败:", err)
  31. return
  32. }
  33. defer newFile.Close()
  34. io.Copy(newFile, file)
  35. if err = UploadUser(newFile.Name()); err != nil {
  36. RespError(w, RespInternalErr, err)
  37. os.Remove(fileName)
  38. return
  39. }
  40. os.Remove(fileName)
  41. RespSucess(w, "批量添加成功")
  42. }
  43. func UploadUser(file string) error {
  44. f, err := excelize.OpenFile(file)
  45. if err != nil {
  46. return err
  47. }
  48. defer func() {
  49. if err := f.Close(); err != nil {
  50. return
  51. }
  52. }()
  53. rows, err := f.GetRows("Sheet1")
  54. if err != nil {
  55. return err
  56. }
  57. if rows[0][0] != "id" || rows[0][1] != "username" || rows[0][2] != "nickname" || rows[0][3] != "email" || rows[0][4] != "pin_code" || rows[0][5] != "limittime" || rows[0][6] != "otp_secret" || rows[0][7] != "disable_otp" || rows[0][8] != "groups" || rows[0][9] != "status" || rows[0][10] != "send_email" {
  58. return fmt.Errorf("批量添加失败,表格格式不正确")
  59. }
  60. var k []interface{}
  61. for _, v := range dbdata.GetGroupNames() {
  62. k = append(k, v)
  63. }
  64. for index, row := range rows {
  65. if index == 0 {
  66. continue
  67. }
  68. id, _ := strconv.Atoi(row[0])
  69. if len(row[4]) < 6 {
  70. row[4] = utils.RandomRunes(8)
  71. }
  72. limittime, _ := time.ParseInLocation("2006-01-02 15:04:05", row[5], time.Local)
  73. disableOtp, _ := strconv.ParseBool(row[7])
  74. var group []string
  75. if row[8] == "" {
  76. return fmt.Errorf("第%d行数据错误,用户组不允许为空", index)
  77. }
  78. for _, v := range strings.Split(row[8], ",") {
  79. if s := mapset.NewSetFromSlice(k); s.Contains(v) {
  80. group = append(group, v)
  81. } else {
  82. return fmt.Errorf("用户组【%s】不存在,请检查第%d行数据", v, index)
  83. }
  84. }
  85. status := cast.ToInt8(row[9])
  86. sendmail, _ := strconv.ParseBool(row[10])
  87. // createdAt, _ := time.ParseInLocation("2006-01-02 15:04:05", row[11], time.Local)
  88. // updatedAt, _ := time.ParseInLocation("2006-01-02 15:04:05", row[12], time.Local)
  89. user := &dbdata.User{
  90. Id: id,
  91. Username: row[1],
  92. Nickname: row[2],
  93. Email: row[3],
  94. PinCode: row[4],
  95. LimitTime: &limittime,
  96. OtpSecret: row[6],
  97. DisableOtp: disableOtp,
  98. Groups: group,
  99. Status: status,
  100. SendEmail: sendmail,
  101. // CreatedAt: createdAt,
  102. // UpdatedAt: updatedAt,
  103. }
  104. if err := dbdata.AddBatch(user); err != nil {
  105. return fmt.Errorf("请检查第%d行数据是否导入有重复用户", index)
  106. }
  107. if user.SendEmail {
  108. if err := userAccountMail(user); err != nil {
  109. return err
  110. }
  111. }
  112. }
  113. return nil
  114. }