mirror of
https://github.com/fumiama/paper-manager.git
synced 2026-06-06 00:10:23 +08:00
487 lines
12 KiB
Go
487 lines
12 KiB
Go
package backend
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
base14 "github.com/fumiama/go-base16384"
|
|
"github.com/fumiama/paper-manager/backend/global"
|
|
"github.com/fumiama/paper-manager/backend/utils"
|
|
)
|
|
|
|
const (
|
|
chineseDateLayout = "2006年01月02日15时04分05秒"
|
|
)
|
|
|
|
var (
|
|
errInvalidToken = errors.New("invalid token")
|
|
errNoListUsersPermission = errors.New("no list users permission")
|
|
errNoSetRolePermission = errors.New("no set role permission")
|
|
errInvalidRole = errors.New("invalid role")
|
|
)
|
|
|
|
type getUserInfoResult struct {
|
|
UserID int `json:"userId"`
|
|
Username string `json:"username"`
|
|
RealName string `json:"realName"`
|
|
Avatar string `json:"avatar"`
|
|
Desc string `json:"desc"`
|
|
HomePath string `json:"homePath"`
|
|
Roles []role `json:"roles"`
|
|
Date int64 `json:"date"`
|
|
Last string `json:"last"`
|
|
Contact string `json:"contact"`
|
|
}
|
|
|
|
func hideContact(cont string) string {
|
|
if len(cont) > 7 {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(cont[:3])
|
|
for i := 0; i < len(cont)-7; i++ {
|
|
sb.WriteByte('*')
|
|
}
|
|
sb.WriteString(cont[len(cont)-4:])
|
|
return sb.String()
|
|
}
|
|
return cont
|
|
}
|
|
|
|
func getUserInfo(token string) (*getUserInfoResult, error) {
|
|
user := usertokens.Get(token)
|
|
if user == nil {
|
|
return nil, errInvalidToken
|
|
}
|
|
return &getUserInfoResult{
|
|
UserID: *user.ID,
|
|
Username: user.Name,
|
|
RealName: user.Nick,
|
|
Avatar: user.Avtr,
|
|
Desc: user.Desc,
|
|
HomePath: func() string {
|
|
if user.Role == global.RoleSuper {
|
|
return "/dashboard/analysis"
|
|
}
|
|
return "/dashboard/workbench"
|
|
}(),
|
|
Roles: []role{{RoleName: user.Role.Nick(), Value: user.Role.String()}},
|
|
Date: user.Date,
|
|
Last: time.Unix(user.Last, 0).Format(chineseDateLayout),
|
|
Contact: hideContact(user.Cont),
|
|
}, nil
|
|
}
|
|
|
|
func getUsersCount(token string) (int, error) {
|
|
user := usertokens.Get(token)
|
|
if user == nil {
|
|
return 0, errInvalidToken
|
|
}
|
|
return global.UserDB.GetUsersCount()
|
|
}
|
|
|
|
type getUsersListResult struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Nick string `json:"nick"`
|
|
Stat bool `json:"stat"`
|
|
Role string `json:"role"`
|
|
Date string `json:"date"`
|
|
Desc string `json:"desc"`
|
|
}
|
|
|
|
func getUsersList(token string) ([]getUsersListResult, error) {
|
|
user := usertokens.Get(token)
|
|
if user == nil {
|
|
return nil, errInvalidToken
|
|
}
|
|
if !user.IsSuper() {
|
|
return nil, errNoListUsersPermission
|
|
}
|
|
us, err := global.UserDB.GetUsers()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ret := make([]getUsersListResult, len(us))
|
|
for i, u := range us {
|
|
ret[i].ID = *u.ID
|
|
ret[i].Name = u.Name
|
|
ret[i].Nick = u.Nick
|
|
ret[i].Stat = u.Pswd != ""
|
|
ret[i].Role = u.Role.Nick()
|
|
ret[i].Date = time.Unix(u.Date, 0).Format(chineseDateLayout)
|
|
ret[i].Desc = u.Desc
|
|
}
|
|
return ret, nil
|
|
}
|
|
|
|
func isNameExist(token, name string) (bool, error) {
|
|
user := usertokens.Get(token)
|
|
if user == nil {
|
|
return false, errInvalidToken
|
|
}
|
|
if !user.IsSuper() {
|
|
return false, errNoListUsersPermission
|
|
}
|
|
return global.UserDB.IsNameExists(name), nil
|
|
}
|
|
|
|
func setUserPassword(id int, token, npwd string) error {
|
|
user, err := global.UserDB.GetUserByID(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
h := md5.New()
|
|
h.Write(base14.StringToBytes(user.Pswd))
|
|
h.Write(base14.StringToBytes(npwd))
|
|
if token != hex.EncodeToString(h.Sum(make([]byte, 0, 16))) {
|
|
return errInvalidToken
|
|
}
|
|
return global.UserDB.UpdateUserPassword(id, user.Name, npwd)
|
|
}
|
|
|
|
func setUserContact(id int, token, ncont string) error {
|
|
user, err := global.UserDB.GetUserByID(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
h := md5.New()
|
|
h.Write(base14.StringToBytes(user.Cont))
|
|
h.Write(base14.StringToBytes(ncont))
|
|
if token != hex.EncodeToString(h.Sum(make([]byte, 0, 16))) {
|
|
return errInvalidToken
|
|
}
|
|
return global.UserDB.UpdateUserContact(id, user.Name, ncont)
|
|
}
|
|
|
|
// setUserInfo may change the arguments
|
|
func setUserInfo(id int, nick, desc, avtr *string) error {
|
|
user, err := global.UserDB.GetUserByID(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
n, d, a := *nick, *desc, *avtr
|
|
if n == "" {
|
|
*nick = user.Nick
|
|
}
|
|
if n == user.Nick {
|
|
n = ""
|
|
}
|
|
if d == "" {
|
|
*desc = user.Desc
|
|
}
|
|
if d == user.Desc {
|
|
d = ""
|
|
}
|
|
if a == "" {
|
|
*avtr = user.Avtr
|
|
} else if utils.IsNotExist(global.DataFolder + a) {
|
|
return os.ErrNotExist
|
|
}
|
|
if a == user.Avtr {
|
|
a = ""
|
|
}
|
|
return global.UserDB.UpdateUserInfo(id, user.Name, n, a, d)
|
|
}
|
|
|
|
// setOthersInfo may change the arguments
|
|
func setOthersInfo(id int, opname, nick, desc string) error {
|
|
user, err := global.UserDB.GetUserByID(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if nick == user.Nick {
|
|
nick = ""
|
|
} else if nick != "" {
|
|
user.Nick = nick
|
|
}
|
|
if desc == user.Desc {
|
|
desc = ""
|
|
} else if desc != "" {
|
|
user.Desc = desc
|
|
}
|
|
return global.UserDB.UpdateUserInfo(id, opname, nick, "", desc)
|
|
}
|
|
|
|
func setUserRole(id int, role global.UserRole, opname string) error {
|
|
if !role.IsVaild() {
|
|
return errInvalidRole
|
|
}
|
|
user, err := global.UserDB.GetUserByID(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if role == user.Role {
|
|
return nil
|
|
}
|
|
return global.UserDB.UpdateUserRole(*user.ID, role, opname)
|
|
}
|
|
|
|
func resetPassword(ip, name, mobile string) error {
|
|
if registerlimit.Get(ip) {
|
|
return errRequestTooFast
|
|
}
|
|
if ip == "" {
|
|
return errInvalidIP
|
|
}
|
|
registerlimit.Set(ip, true)
|
|
return global.UserDB.NotifyResetPassword(ip, name, mobile)
|
|
}
|
|
|
|
func init() {
|
|
apimap["/api/getUserInfo"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
|
|
token := r.Header.Get("Authorization")
|
|
ret, err := getUserInfo(token)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
writeresult(w, codeSuccess, ret, messageOk, typeSuccess)
|
|
}}
|
|
|
|
apimap["/api/getUsersCount"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
|
|
token := r.Header.Get("Authorization")
|
|
n, err := getUsersCount(token)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
writeresult(w, codeSuccess, n, messageOk, typeSuccess)
|
|
}}
|
|
|
|
apimap["/api/getUsersList"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
|
|
token := r.Header.Get("Authorization")
|
|
ret, err := getUsersList(token)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
writeresult(w, codeSuccess, &ret, messageOk, typeSuccess)
|
|
}}
|
|
|
|
apimap["/api/isNameExist"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
|
|
token := r.Header.Get("Authorization")
|
|
name := r.URL.Query().Get("username")
|
|
if name == "" {
|
|
writeresult(w, codeError, nil, "empty username", typeError)
|
|
return
|
|
}
|
|
yes, err := isNameExist(token, name)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
writeresult(w, codeSuccess, yes, messageOk, typeSuccess)
|
|
}}
|
|
|
|
apimap["/api/setPassword"] = &apihandler{"POST", func(w http.ResponseWriter, r *http.Request) {
|
|
type setpasswordbody struct {
|
|
Token string `json:"token"`
|
|
Password string `json:"password"`
|
|
}
|
|
token := r.Header.Get("Authorization")
|
|
user := usertokens.Get(token)
|
|
if user == nil {
|
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
|
return
|
|
}
|
|
var body setpasswordbody
|
|
defer r.Body.Close()
|
|
err := json.NewDecoder(r.Body).Decode(&body)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
err = setUserPassword(*user.ID, body.Token, body.Password)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
type message struct {
|
|
M string `json:"msg"`
|
|
}
|
|
writeresult(w, codeSuccess, &message{M: "成功, 请重新登录"}, messageOk, typeSuccess)
|
|
_ = logout(token)
|
|
}}
|
|
|
|
apimap["/api/setContact"] = &apihandler{"POST", func(w http.ResponseWriter, r *http.Request) {
|
|
type setcontactbody struct {
|
|
Token string `json:"token"`
|
|
Contact string `json:"contact"`
|
|
}
|
|
token := r.Header.Get("Authorization")
|
|
user := usertokens.Get(token)
|
|
if user == nil {
|
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
|
return
|
|
}
|
|
var body setcontactbody
|
|
defer r.Body.Close()
|
|
err := json.NewDecoder(r.Body).Decode(&body)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
err = setUserContact(*user.ID, body.Token, body.Contact)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
user.Cont = hideContact(body.Contact)
|
|
type message struct {
|
|
M string `json:"msg"`
|
|
}
|
|
writeresult(w, codeSuccess, &message{M: "成功, 已将消息报告给课程组长"}, messageOk, typeSuccess)
|
|
}}
|
|
|
|
apimap["/api/setUserInfo"] = &apihandler{"POST", func(w http.ResponseWriter, r *http.Request) {
|
|
type setuserinfobody struct {
|
|
ID int `json:"id"`
|
|
Nick string `json:"nick"`
|
|
Desc string `json:"desc"`
|
|
Avtr string `json:"avtr"`
|
|
}
|
|
token := r.Header.Get("Authorization")
|
|
user := usertokens.Get(token)
|
|
if user == nil {
|
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
|
return
|
|
}
|
|
var body setuserinfobody
|
|
defer r.Body.Close()
|
|
err := json.NewDecoder(r.Body).Decode(&body)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
type message struct {
|
|
M string `json:"msg"`
|
|
}
|
|
if body.ID != 0 {
|
|
if !user.IsSuper() {
|
|
writeresult(w, codeError, nil, "no permission to set others' info", typeError)
|
|
return
|
|
}
|
|
err = setOthersInfo(body.ID, user.Name, body.Nick, body.Desc)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
writeresult(w, codeSuccess, &message{M: "成功"}, messageOk, typeSuccess)
|
|
return
|
|
}
|
|
err = setUserInfo(*user.ID, &body.Nick, &body.Desc, &body.Avtr)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
user.Nick = body.Nick
|
|
user.Desc = body.Desc
|
|
user.Avtr = body.Avtr
|
|
writeresult(w, codeSuccess, &message{M: "成功"}, messageOk, typeSuccess)
|
|
}}
|
|
|
|
apimap["/api/setRole"] = &apihandler{"POST", func(w http.ResponseWriter, r *http.Request) {
|
|
type setrolebody struct {
|
|
ID int `json:"id"`
|
|
Role global.UserRole `json:"role"`
|
|
}
|
|
token := r.Header.Get("Authorization")
|
|
user := usertokens.Get(token)
|
|
if user == nil {
|
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
|
return
|
|
}
|
|
if !user.IsSuper() {
|
|
writeresult(w, codeError, nil, errNoSetRolePermission.Error(), typeError)
|
|
return
|
|
}
|
|
var body setrolebody
|
|
defer r.Body.Close()
|
|
err := json.NewDecoder(r.Body).Decode(&body)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
if body.ID == *user.ID {
|
|
writeresult(w, codeError, nil, "cannot set self", typeError)
|
|
return
|
|
}
|
|
err = setUserRole(body.ID, body.Role, user.Name)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
writeresult(w, codeSuccess, nil, messageOk, typeSuccess)
|
|
}}
|
|
|
|
apimap["/api/disableUser"] = &apihandler{"POST", func(w http.ResponseWriter, r *http.Request) {
|
|
type disableuserbody struct {
|
|
ID int `json:"id"`
|
|
}
|
|
token := r.Header.Get("Authorization")
|
|
user := usertokens.Get(token)
|
|
if user == nil {
|
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
|
return
|
|
}
|
|
if !user.IsSuper() {
|
|
writeresult(w, codeError, nil, errNoSetRolePermission.Error(), typeError)
|
|
return
|
|
}
|
|
var body disableuserbody
|
|
defer r.Body.Close()
|
|
err := json.NewDecoder(r.Body).Decode(&body)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
if body.ID == *user.ID {
|
|
writeresult(w, codeError, nil, "cannot disbale self", typeError)
|
|
return
|
|
}
|
|
err = global.UserDB.DisableUser(body.ID, user.Name)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
writeresult(w, codeSuccess, nil, messageOk, typeSuccess)
|
|
}}
|
|
|
|
apimap["/api/resetPassword"] = &apihandler{"POST", func(w http.ResponseWriter, r *http.Request) {
|
|
type resetpwdbody struct {
|
|
Username string `json:"username"`
|
|
Mobile string `json:"mobile"`
|
|
}
|
|
if r.Header.Get("Authorization") != "" {
|
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
|
return
|
|
}
|
|
var body resetpwdbody
|
|
defer r.Body.Close()
|
|
err := json.NewDecoder(r.Body).Decode(&body)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
ip := r.RemoteAddr
|
|
i := strings.LastIndex(ip, ":")
|
|
if i >= 0 {
|
|
ip = ip[:i]
|
|
}
|
|
err = resetPassword(ip, body.Username, body.Mobile)
|
|
if err != nil {
|
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
|
return
|
|
}
|
|
type message struct {
|
|
M string `json:"msg"`
|
|
}
|
|
writeresult(w, codeSuccess, &message{M: "已上报, 请耐心等待通知"}, messageOk, typeSuccess)
|
|
}}
|
|
}
|