package admin import ( "bytes" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "net/url" "strconv" "strings" "text/template" "time" "github.com/bjdgyc/anylink/base" "github.com/bjdgyc/anylink/dbdata" "github.com/bjdgyc/anylink/sessdata" "github.com/skip2/go-qrcode" mail "github.com/xhit/go-simple-mail/v2" ) func UserList(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() prefix := r.FormValue("prefix") prefix = strings.TrimSpace(prefix) pageS := r.FormValue("page") page, _ := strconv.Atoi(pageS) if page < 1 { page = 1 } var ( pageSize = dbdata.PageSize count int datas []dbdata.User err error ) // 查询前缀匹配 if len(prefix) > 0 { fuzzy := "%" + prefix + "%" where := "username LIKE ? OR nickname LIKE ? OR email LIKE ?" count = dbdata.FindWhereCount(&dbdata.User{}, where, fuzzy, fuzzy, fuzzy) err = dbdata.FindWhere(&datas, pageSize, page, where, fuzzy, fuzzy, fuzzy) } else { count = dbdata.CountAll(&dbdata.User{}) err = dbdata.Find(&datas, pageSize, page) } if err != nil && !dbdata.CheckErrNotFound(err) { RespError(w, RespInternalErr, err) return } data := map[string]interface{}{ "count": count, "page_size": pageSize, "datas": datas, } RespSucess(w, data) } func UserDetail(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() idS := r.FormValue("id") id, _ := strconv.Atoi(idS) if id < 1 { RespError(w, RespParamErr, "用户名错误") return } var user dbdata.User err := dbdata.One("Id", id, &user) if err != nil { RespError(w, RespInternalErr, err) return } RespSucess(w, user) } func UserSet(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() body, err := io.ReadAll(r.Body) if err != nil { RespError(w, RespInternalErr, err) return } defer r.Body.Close() data := &dbdata.User{} err = json.Unmarshal(body, data) if err != nil { RespError(w, RespInternalErr, err) return } err = dbdata.SetUser(data) if err != nil { RespError(w, RespInternalErr, err) return } // 发送邮件 if data.SendEmail { err = userAccountMail(data) if err != nil { RespError(w, RespInternalErr, err) return } } // 修改用户资料后执行过期用户检测 sessdata.CloseUserLimittimeSession() RespSucess(w, nil) } func UserDel(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() idS := r.FormValue("id") id, _ := strconv.Atoi(idS) if id < 1 { RespError(w, RespParamErr, "用户id错误") return } user := dbdata.User{Id: id} err := dbdata.Del(&user) if err != nil { RespError(w, RespInternalErr, err) return } RespSucess(w, nil) } func UserOtpQr(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() b64S := r.FormValue("b64") idS := r.FormValue("id") id, _ := strconv.Atoi(idS) var b64 bool if b64S == "1" { b64 = true } data, err := userOtpQr(id, b64) if err != nil { base.Error(err) } io.WriteString(w, data) } func userOtpQr(uid int, b64 bool) (string, error) { var user dbdata.User err := dbdata.One("Id", uid, &user) if err != nil { return "", err } issuer := url.QueryEscape(base.Cfg.Issuer) qrstr := fmt.Sprintf("otpauth://totp/%s:%s?issuer=%s&secret=%s", issuer, user.Email, issuer, user.OtpSecret) qr, _ := qrcode.New(qrstr, qrcode.High) if b64 { data, err := qr.PNG(300) if err != nil { return "", err } s := base64.StdEncoding.EncodeToString(data) return s, nil } buf := bytes.NewBuffer(nil) err = qr.Write(300, buf) return buf.String(), err } // 在线用户 func UserOnline(w http.ResponseWriter, r *http.Request) { datas := sessdata.OnlineSess() data := map[string]interface{}{ "count": len(datas), "page_size": dbdata.PageSize, "datas": datas, } RespSucess(w, data) } func UserOffline(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() token := r.FormValue("token") sessdata.CloseSess(token, dbdata.UserLogoutAdmin) RespSucess(w, nil) } func UserReline(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() token := r.FormValue("token") sessdata.CloseCSess(token) RespSucess(w, nil) } type userAccountMailData struct { Issuer string LinkAddr string Group string Username string Nickname string PinCode string OtpImg string OtpImgBase64 string DisableOtp bool } func userAccountMail(user *dbdata.User) error { // 平台通知 htmlBody := `