mirror of
https://github.com/fumiama/paper-manager.git
synced 2026-06-12 12:10:25 +08:00
finish backend login
This commit is contained in:
37
backend/api/base.go
Normal file
37
backend/api/base.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
codeError = -1
|
||||||
|
codeSuccess = 0
|
||||||
|
codeTimeout = 401
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
typeSuccess = "success"
|
||||||
|
typeError = "error"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
messageOk = "ok"
|
||||||
|
)
|
||||||
|
|
||||||
|
type base struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Result any `json:"result"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeresult(w io.Writer, c int, r any, m, t string) error {
|
||||||
|
return json.NewEncoder(w).Encode(&base{
|
||||||
|
Code: c,
|
||||||
|
Result: r,
|
||||||
|
Message: m,
|
||||||
|
Type: t,
|
||||||
|
})
|
||||||
|
}
|
||||||
142
backend/api/login.go
Normal file
142
backend/api/login.go
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
crand "crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"math/rand"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/FloatTech/ttl"
|
||||||
|
"github.com/RomiChan/syncx"
|
||||||
|
base14 "github.com/fumiama/go-base16384"
|
||||||
|
|
||||||
|
"github.com/fumiama/paper-manager/backend/global"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNoSuchUser = errors.New("invalid username or password")
|
||||||
|
errTooManySalts = errors.New("too many salts")
|
||||||
|
errInvalidLoginStatus = errors.New("invalid login status")
|
||||||
|
errEmptySalt = errors.New("empty salt")
|
||||||
|
errWrongPassword = errors.New("invalid username or password")
|
||||||
|
errTooManyFailedLogins = errors.New("too many failed logins")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
loginStatusYes = iota - 1
|
||||||
|
loginStatusNo
|
||||||
|
loginStatusFail1
|
||||||
|
loginStatusFail2
|
||||||
|
loginStatusFail3
|
||||||
|
loginStatusFailLast
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxSaltCount = 4
|
||||||
|
|
||||||
|
type saltinfo struct {
|
||||||
|
Salt string `json:"salt"`
|
||||||
|
count *uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
loginsalts = ttl.NewCache[string, saltinfo](time.Minute)
|
||||||
|
loginstatus = syncx.Map[string, int]{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLoginSalt(username string) (*saltinfo, error) {
|
||||||
|
if !global.UserDB.IsNameExists(username) {
|
||||||
|
return nil, errNoSuchUser
|
||||||
|
}
|
||||||
|
s, _ := loginstatus.Load(username)
|
||||||
|
if s != loginStatusNo {
|
||||||
|
return nil, errInvalidLoginStatus
|
||||||
|
}
|
||||||
|
salt := loginsalts.Get(username)
|
||||||
|
if salt.count != nil {
|
||||||
|
if atomic.AddUintptr(salt.count, 1) >= maxSaltCount {
|
||||||
|
time.AfterFunc(time.Minute*2, func() { atomic.StoreUintptr(salt.count, 0) })
|
||||||
|
return nil, errTooManySalts
|
||||||
|
}
|
||||||
|
if salt.Salt != "" {
|
||||||
|
return &salt, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf := make([]byte, 7*(rand.Intn(8)+1))
|
||||||
|
_, err := crand.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
salt.Salt = base14.EncodeToString(buf)
|
||||||
|
salt.count = new(uintptr)
|
||||||
|
loginsalts.Set(username, salt)
|
||||||
|
return &salt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type role struct {
|
||||||
|
RoleName string `json:"roleName"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type loginResult struct {
|
||||||
|
Roles []role `json:"roles"`
|
||||||
|
UserID int `json:"userId"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
RealName string `json:"realName"`
|
||||||
|
Desc string `json:"desc"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
usertokens = ttl.NewCache[string, *global.User](time.Hour)
|
||||||
|
)
|
||||||
|
|
||||||
|
func login(username, challenge string) (*loginResult, error) {
|
||||||
|
if !global.UserDB.IsNameExists(username) {
|
||||||
|
return nil, errNoSuchUser
|
||||||
|
}
|
||||||
|
s, loaded := loginstatus.LoadOrStore(username, loginStatusFail1)
|
||||||
|
if loaded {
|
||||||
|
if s == loginStatusYes {
|
||||||
|
return nil, errInvalidLoginStatus
|
||||||
|
}
|
||||||
|
if s >= loginStatusFailLast {
|
||||||
|
return nil, errTooManyFailedLogins
|
||||||
|
}
|
||||||
|
loginstatus.Store(username, s+1)
|
||||||
|
}
|
||||||
|
salt := loginsalts.Get(username)
|
||||||
|
if salt.count == nil || salt.Salt == "" {
|
||||||
|
return nil, errEmptySalt
|
||||||
|
}
|
||||||
|
user, err := global.UserDB.GetUserByName(username)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
h := md5.New()
|
||||||
|
h.Write(base14.StringToBytes(user.Pswd))
|
||||||
|
h.Write(base14.StringToBytes(salt.Salt))
|
||||||
|
passchlg := hex.EncodeToString(h.Sum(make([]byte, 0, md5.Size)))
|
||||||
|
if passchlg != challenge {
|
||||||
|
return nil, errWrongPassword
|
||||||
|
}
|
||||||
|
var buf [6 * 8]byte
|
||||||
|
_, err = crand.Read(buf[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
token := base64.RawStdEncoding.EncodeToString(buf[:])
|
||||||
|
usertokens.Set(token, &user)
|
||||||
|
loginstatus.Store(username, loginStatusYes)
|
||||||
|
return &loginResult{
|
||||||
|
Roles: []role{{RoleName: user.Role.Nick(), Value: user.Role.String()}},
|
||||||
|
UserID: *user.ID,
|
||||||
|
Username: user.Name,
|
||||||
|
Token: token,
|
||||||
|
RealName: user.Nick,
|
||||||
|
Desc: user.Desc,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/fumiama/paper-manager/backend/utils"
|
"github.com/fumiama/paper-manager/backend/utils"
|
||||||
@@ -8,8 +9,62 @@ import (
|
|||||||
|
|
||||||
// Handler serves all backend /api call
|
// Handler serves all backend /api call
|
||||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.URL.Path == "/api/getLoginSalt" {
|
||||||
|
if !utils.IsMethod("GET", w, r) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
username := r.URL.Query().Get("username")
|
||||||
|
if username == "" {
|
||||||
|
http.Error(w, "400 Bad Request: empty username", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
salt, err := getLoginSalt(username)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeresult(w, codeSuccess, salt, messageOk, typeSuccess)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.URL.Path == "/api/login" {
|
||||||
|
if !utils.IsMethod("POST", w, r) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer r.Body.Close()
|
||||||
|
var body loginbody
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&body)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r, err := login(body.Username, body.Password)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeresult(w, codeSuccess, r, messageOk, typeSuccess)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.URL.Path == "/api/getUserInfo" {
|
||||||
|
if !utils.IsMethod("GET", w, r) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token := r.Header.Get("Authorization")
|
||||||
|
r, err := getUserInfo(token)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeresult(w, codeSuccess, r, messageOk, typeSuccess)
|
||||||
|
return
|
||||||
|
}
|
||||||
if !utils.IsMethod("GET", w, r) {
|
if !utils.IsMethod("GET", w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Error(w, "404 Not Found", http.StatusNotFound)
|
http.Error(w, "404 Not Found", http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type loginbody struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|||||||
42
backend/api/user.go
Normal file
42
backend/api/user.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/fumiama/paper-manager/backend/global"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errInvalidToken = errors.New("invalid token")
|
||||||
|
)
|
||||||
|
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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()}},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
26
backend/global/db.go
Normal file
26
backend/global/db.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package global
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
sql "github.com/FloatTech/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
userdbpath = DataFolder + "user.db"
|
||||||
|
filedbpath = DataFolder + "file.db"
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserDatabase struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
db sql.Sqlite
|
||||||
|
}
|
||||||
|
type FileDatabase struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
db sql.Sqlite
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
UserDB = UserDatabase{db: sql.Sqlite{DBPath: userdbpath}}
|
||||||
|
FileDB = FileDatabase{db: sql.Sqlite{DBPath: filedbpath}}
|
||||||
|
)
|
||||||
16
backend/global/file.go
Normal file
16
backend/global/file.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package global
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
err := FileDB.db.Open(time.Hour)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
ID *int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FileDatabase) AddFile() {}
|
||||||
440
backend/global/user.go
Normal file
440
backend/global/user.go
Normal file
@@ -0,0 +1,440 @@
|
|||||||
|
package global
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/fumiama/paper-manager/backend/utils"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RoleNil UserRole = iota
|
||||||
|
RoleSuper
|
||||||
|
RoleFileManager
|
||||||
|
RoleUser
|
||||||
|
)
|
||||||
|
|
||||||
|
type UserRole uint8
|
||||||
|
|
||||||
|
func (r UserRole) String() string {
|
||||||
|
switch r {
|
||||||
|
case RoleSuper:
|
||||||
|
return "super"
|
||||||
|
case RoleFileManager:
|
||||||
|
return "filemgr"
|
||||||
|
case RoleUser:
|
||||||
|
return "user"
|
||||||
|
}
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r UserRole) Nick() string {
|
||||||
|
switch r {
|
||||||
|
case RoleSuper:
|
||||||
|
return "课程组长"
|
||||||
|
case RoleFileManager:
|
||||||
|
return "归档代理"
|
||||||
|
case RoleUser:
|
||||||
|
return "课程组员"
|
||||||
|
}
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserTableUser = "user"
|
||||||
|
UserTableMessage = "msg"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidRole = errors.New("invalid role")
|
||||||
|
ErrEmptyPassword = errors.New("empty password")
|
||||||
|
ErrEmptyName = errors.New("empty name")
|
||||||
|
ErrInvalidUsersCount = errors.New("invalid users count")
|
||||||
|
ErrEmptyUserID = errors.New("empty user ID")
|
||||||
|
ErrEmptyContect = errors.New("empty contact")
|
||||||
|
ErrUsernameExists = errors.New("username exists")
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
isinit := utils.IsNotExist(UserDB.db.DBPath)
|
||||||
|
err := UserDB.db.Open(time.Hour)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = UserDB.db.DB.Exec("PRAGMA foreign_keys = ON;")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = UserDB.db.Create(UserTableUser, &User{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = UserDB.db.Create(UserTableMessage, &Message{},
|
||||||
|
"FOREIGN KEY(ToID) REFERENCES "+UserTableUser+"(ID)",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if isinit { // 添加初始账户
|
||||||
|
UserDB.AddUser(&User{
|
||||||
|
Role: RoleSuper,
|
||||||
|
Pswd: "123456",
|
||||||
|
Name: "fumiama",
|
||||||
|
Nick: "源文雨",
|
||||||
|
Avtr: "https://q1.qlogo.cn/g?b=qq&nk=1332524221&s=640",
|
||||||
|
Cont: "028-61830156",
|
||||||
|
Desc: "日は山の端にかかりぬ",
|
||||||
|
}, "系统")
|
||||||
|
logrus.Warn("[global.user] 初次启动, 创建初始账户 fumiama 密码 123456")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// User stores a user in table named UserTableUser
|
||||||
|
type User struct {
|
||||||
|
ID *int
|
||||||
|
Role UserRole
|
||||||
|
Date int64 // Date is the creating date's unix timestamp
|
||||||
|
Pswd string
|
||||||
|
Last int64 // Last is the last password reseting unix timestamp
|
||||||
|
Name string
|
||||||
|
Nick string
|
||||||
|
Avtr string // Avtr is the user's avatar, typically a image url
|
||||||
|
Cont string // Cont is the user's contact, ex. phone number
|
||||||
|
Desc string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddUser but cannot customize the ID field for it is self-increasing
|
||||||
|
func (u *UserDatabase) AddUser(user *User, opname string) error {
|
||||||
|
user.ID = nil
|
||||||
|
if user.Role == RoleNil || user.Role > RoleUser {
|
||||||
|
return ErrInvalidRole
|
||||||
|
}
|
||||||
|
if user.Pswd == "" {
|
||||||
|
return ErrEmptyPassword
|
||||||
|
}
|
||||||
|
if user.Name == "" {
|
||||||
|
return ErrEmptyName
|
||||||
|
}
|
||||||
|
if u.IsNameExists(user.Name) {
|
||||||
|
return ErrUsernameExists
|
||||||
|
}
|
||||||
|
user.Date = time.Now().Unix()
|
||||||
|
user.Last = user.Date
|
||||||
|
_ = u.notifyUserAdded(opname, user.Name)
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
return u.db.InsertUnique(UserTableUser, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserInfo ...
|
||||||
|
func (u *UserDatabase) UpdateUserInfo(id int, nick, avtr, desc string) error {
|
||||||
|
user, err := u.GetUserByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if nick != "" {
|
||||||
|
user.Nick = nick
|
||||||
|
}
|
||||||
|
if avtr != "" {
|
||||||
|
user.Avtr = avtr
|
||||||
|
}
|
||||||
|
if desc != "" {
|
||||||
|
user.Desc = desc
|
||||||
|
}
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
return u.db.Insert(UserTableUser, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserRole ...
|
||||||
|
func (u *UserDatabase) UpdateUserRole(id int, nr UserRole) error {
|
||||||
|
if nr == RoleNil || nr > RoleUser {
|
||||||
|
return ErrInvalidRole
|
||||||
|
}
|
||||||
|
user, err := u.GetUserByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user.Role = nr
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
return u.db.Insert(UserTableUser, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserPassword ...
|
||||||
|
func (u *UserDatabase) UpdateUserPassword(id int, npwd string) error {
|
||||||
|
if npwd == "" {
|
||||||
|
return ErrEmptyPassword
|
||||||
|
}
|
||||||
|
user, err := u.GetUserByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user.Last = time.Now().Unix()
|
||||||
|
user.Pswd = npwd
|
||||||
|
_ = u.notifyPasswordChange(user.Name, npwd)
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
return u.db.Insert(UserTableUser, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateUserContact ...
|
||||||
|
func (u *UserDatabase) UpdateUserContact(id int, ncont string) error {
|
||||||
|
if ncont == "" {
|
||||||
|
return ErrEmptyContect
|
||||||
|
}
|
||||||
|
user, err := u.GetUserByID(id)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user.Cont = ncont
|
||||||
|
_ = u.notifyContactChange(user.Name, ncont)
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
return u.db.Insert(UserTableUser, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByName avoids sql injection by removing ; ' " =
|
||||||
|
func (u *UserDatabase) GetUserByName(username string) (user User, err error) {
|
||||||
|
username = strings.NewReplacer(";", "", "'", "", `"`, "", "=", "").Replace(username)
|
||||||
|
u.mu.RLock()
|
||||||
|
err = u.db.Find(UserTableUser, &user, "WHERE Name='"+username+"'")
|
||||||
|
u.mu.RUnlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNameExists avoids sql injection by removing ; ' " =
|
||||||
|
func (u *UserDatabase) IsNameExists(username string) bool {
|
||||||
|
username = strings.NewReplacer(";", "", "'", "", `"`, "", "=", "").Replace(username)
|
||||||
|
u.mu.RLock()
|
||||||
|
defer u.mu.RUnlock()
|
||||||
|
return u.db.CanFind(UserTableUser, "WHERE Name='"+username+"'")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserByID ...
|
||||||
|
func (u *UserDatabase) GetUserByID(id int) (user User, err error) {
|
||||||
|
u.mu.RLock()
|
||||||
|
err = u.db.Find(UserTableUser, &user, "WHERE ID="+strconv.Itoa(id))
|
||||||
|
u.mu.RUnlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelUserByID ...
|
||||||
|
func (u *UserDatabase) DelUserByID(id int) (err error) {
|
||||||
|
u.mu.Lock()
|
||||||
|
err = u.db.Del(UserTableUser, "WHERE ID="+strconv.Itoa(id))
|
||||||
|
u.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUsers will set Pswd field to empty
|
||||||
|
func (u *UserDatabase) GetUsers() (users []User, err error) {
|
||||||
|
var user User
|
||||||
|
u.mu.RLock()
|
||||||
|
defer u.mu.RUnlock()
|
||||||
|
n, err := u.db.Count(UserTableUser)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
users = make([]User, n)
|
||||||
|
i := 0
|
||||||
|
err = u.db.FindFor(UserTableUser, &user, "", func() error {
|
||||||
|
user.Pswd = ""
|
||||||
|
users[i] = user
|
||||||
|
i++
|
||||||
|
if i >= n {
|
||||||
|
return ErrInvalidUsersCount
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *UserDatabase) GetSuperIDs() (ids []int, err error) {
|
||||||
|
var user User
|
||||||
|
ids = make([]int, 0, 16)
|
||||||
|
u.mu.RLock()
|
||||||
|
defer u.mu.RUnlock()
|
||||||
|
err = u.db.FindFor(UserTableUser, &user, "WHERE Role="+strconv.Itoa(int(RoleSuper)), func() error {
|
||||||
|
ids = append(ids, *user.ID)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message is shown in the workbench
|
||||||
|
type Message struct {
|
||||||
|
ID *int
|
||||||
|
ToID int // ToID user's ID
|
||||||
|
Date int64
|
||||||
|
Text string // Text is the message content
|
||||||
|
Name string // Name is the user's name to add in register message
|
||||||
|
Cont string // Cont is the user's phone number to add in register message or an operator's name in add user message
|
||||||
|
Pswd string // Pswd is the user's password to add in register message
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendMessage will send a message
|
||||||
|
func (u *UserDatabase) SendMessage(m *Message) error {
|
||||||
|
m.ID = nil
|
||||||
|
m.Date = time.Now().Unix()
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
return u.db.InsertUnique(UserTableMessage, &m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyRegister will send register notification to all supers
|
||||||
|
func (u *UserDatabase) NotifyRegister(name, cont, pswd string) error {
|
||||||
|
if name == "" {
|
||||||
|
return ErrEmptyName
|
||||||
|
}
|
||||||
|
if pswd == "" {
|
||||||
|
return ErrEmptyPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
tos, err := u.GetSuperIDs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := Message{
|
||||||
|
Date: time.Now().Unix(),
|
||||||
|
Text: "收到来自 " + name + " 的注册请求, 联系方式: " + cont,
|
||||||
|
Name: name,
|
||||||
|
Cont: cont,
|
||||||
|
Pswd: pswd,
|
||||||
|
}
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
for _, to := range tos {
|
||||||
|
m.ToID = to
|
||||||
|
err = u.db.InsertUnique(UserTableMessage, &m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// notifyUserAdded will send notification to all supers
|
||||||
|
func (u *UserDatabase) notifyUserAdded(opname, name string) error {
|
||||||
|
if opname == "" || name == "" {
|
||||||
|
return ErrEmptyName
|
||||||
|
}
|
||||||
|
|
||||||
|
tos, err := u.GetSuperIDs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := Message{
|
||||||
|
Date: time.Now().Unix(),
|
||||||
|
Text: opname + "添加了用户 " + name,
|
||||||
|
Name: name,
|
||||||
|
Cont: opname,
|
||||||
|
}
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
for _, to := range tos {
|
||||||
|
m.ToID = to
|
||||||
|
err = u.db.InsertUnique(UserTableMessage, &m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// notifyContactChange will send notification to all supers
|
||||||
|
func (u *UserDatabase) notifyContactChange(name, cont string) error {
|
||||||
|
if name == "" {
|
||||||
|
return ErrEmptyName
|
||||||
|
}
|
||||||
|
|
||||||
|
tos, err := u.GetSuperIDs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := Message{
|
||||||
|
Date: time.Now().Unix(),
|
||||||
|
Text: "用户 " + name + " 更改联系方式为: " + cont,
|
||||||
|
Name: name,
|
||||||
|
Cont: cont,
|
||||||
|
}
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
for _, to := range tos {
|
||||||
|
m.ToID = to
|
||||||
|
err = u.db.InsertUnique(UserTableMessage, &m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// notifyPasswordChange will send notification to all supers
|
||||||
|
func (u *UserDatabase) notifyPasswordChange(name, npwd string) error {
|
||||||
|
if name == "" {
|
||||||
|
return ErrEmptyName
|
||||||
|
}
|
||||||
|
|
||||||
|
tos, err := u.GetSuperIDs()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m := Message{
|
||||||
|
Date: time.Now().Unix(),
|
||||||
|
Text: "用户 " + name + " 更改了密码",
|
||||||
|
Name: name,
|
||||||
|
Pswd: npwd,
|
||||||
|
}
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
for _, to := range tos {
|
||||||
|
m.ToID = to
|
||||||
|
err = u.db.InsertUnique(UserTableMessage, &m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessagesOfUser set Pswd field to empty
|
||||||
|
func (u *UserDatabase) GetMessagesOfUser(to int) (ms []Message, err error) {
|
||||||
|
u.mu.RLock()
|
||||||
|
defer u.mu.RUnlock()
|
||||||
|
n, err := u.db.Count(UserTableMessage)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ms = make([]Message, 0, n)
|
||||||
|
m := Message{}
|
||||||
|
err = u.db.FindFor(UserTableMessage, &m, "WHERE ToID="+strconv.Itoa(to), func() error {
|
||||||
|
m.Pswd = ""
|
||||||
|
ms = append(ms, m)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageByID ...
|
||||||
|
func (u *UserDatabase) GetMessageByID(id int) (m Message, err error) {
|
||||||
|
u.mu.RLock()
|
||||||
|
err = u.db.Find(UserTableMessage, &m, "WHERE ID="+strconv.Itoa(id))
|
||||||
|
u.mu.RUnlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelMessageByID ...
|
||||||
|
func (u *UserDatabase) DelMessageByID(id int) (err error) {
|
||||||
|
u.mu.Lock()
|
||||||
|
err = u.db.Del(UserTableMessage, "WHERE ID="+strconv.Itoa(id))
|
||||||
|
u.mu.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
25
backend/utils/file.go
Normal file
25
backend/utils/file.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
// IsExist 文件/路径存在
|
||||||
|
func IsExist(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
return err == nil || os.IsExist(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotExist 文件/路径不存在
|
||||||
|
func IsNotExist(path string) bool {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
return err != nil && os.IsNotExist(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileSize 获取文件大小
|
||||||
|
func FileSize(path string) (n int64) {
|
||||||
|
stat, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n = stat.Size()
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -1,260 +0,0 @@
|
|||||||
import { resultSuccess, resultError, getRequestToken, requestParams } from '../_util'
|
|
||||||
import { MockMethod } from 'vite-plugin-mock'
|
|
||||||
import { createFakeUserList } from './user'
|
|
||||||
|
|
||||||
// single
|
|
||||||
const dashboardRoute = {
|
|
||||||
path: '/dashboard',
|
|
||||||
name: 'Dashboard',
|
|
||||||
component: 'LAYOUT',
|
|
||||||
redirect: '/dashboard/analysis',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.dashboard.dashboard',
|
|
||||||
hideChildrenInMenu: true,
|
|
||||||
icon: 'bx:bx-home',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'analysis',
|
|
||||||
name: 'Analysis',
|
|
||||||
component: '/dashboard/analysis/index',
|
|
||||||
meta: {
|
|
||||||
hideMenu: true,
|
|
||||||
hideBreadcrumb: true,
|
|
||||||
title: 'routes.dashboard.analysis',
|
|
||||||
currentActiveMenu: '/dashboard',
|
|
||||||
icon: 'bx:bx-home',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'workbench',
|
|
||||||
name: 'Workbench',
|
|
||||||
component: '/dashboard/workbench/index',
|
|
||||||
meta: {
|
|
||||||
hideMenu: true,
|
|
||||||
hideBreadcrumb: true,
|
|
||||||
title: 'routes.dashboard.workbench',
|
|
||||||
currentActiveMenu: '/dashboard',
|
|
||||||
icon: 'bx:bx-home',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const backRoute = {
|
|
||||||
path: 'back',
|
|
||||||
name: 'PermissionBackDemo',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.demo.permission.back',
|
|
||||||
},
|
|
||||||
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'page',
|
|
||||||
name: 'BackAuthPage',
|
|
||||||
component: '/demo/permission/back/index',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.demo.permission.backPage',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'btn',
|
|
||||||
name: 'BackAuthBtn',
|
|
||||||
component: '/demo/permission/back/Btn',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.demo.permission.backBtn',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const authRoute = {
|
|
||||||
path: '/permission',
|
|
||||||
name: 'Permission',
|
|
||||||
component: 'LAYOUT',
|
|
||||||
redirect: '/permission/front/page',
|
|
||||||
meta: {
|
|
||||||
icon: 'carbon:user-role',
|
|
||||||
title: 'routes.demo.permission.permission',
|
|
||||||
},
|
|
||||||
children: [backRoute],
|
|
||||||
}
|
|
||||||
|
|
||||||
const levelRoute = {
|
|
||||||
path: '/level',
|
|
||||||
name: 'Level',
|
|
||||||
component: 'LAYOUT',
|
|
||||||
redirect: '/level/menu1/menu1-1',
|
|
||||||
meta: {
|
|
||||||
icon: 'carbon:user-role',
|
|
||||||
title: 'routes.demo.level.level',
|
|
||||||
},
|
|
||||||
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'menu1',
|
|
||||||
name: 'Menu1Demo',
|
|
||||||
meta: {
|
|
||||||
title: 'Menu1',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'menu1-1',
|
|
||||||
name: 'Menu11Demo',
|
|
||||||
meta: {
|
|
||||||
title: 'Menu1-1',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'menu1-1-1',
|
|
||||||
name: 'Menu111Demo',
|
|
||||||
component: '/demo/level/Menu111',
|
|
||||||
meta: {
|
|
||||||
title: 'Menu111',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu1-2',
|
|
||||||
name: 'Menu12Demo',
|
|
||||||
component: '/demo/level/Menu12',
|
|
||||||
meta: {
|
|
||||||
title: 'Menu1-2',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'menu2',
|
|
||||||
name: 'Menu2Demo',
|
|
||||||
component: '/demo/level/Menu2',
|
|
||||||
meta: {
|
|
||||||
title: 'Menu2',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const sysRoute = {
|
|
||||||
path: '/system',
|
|
||||||
name: 'System',
|
|
||||||
component: 'LAYOUT',
|
|
||||||
redirect: '/system/account',
|
|
||||||
meta: {
|
|
||||||
icon: 'ion:settings-outline',
|
|
||||||
title: 'routes.demo.system.moduleName',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'account',
|
|
||||||
name: 'AccountManagement',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.demo.system.account',
|
|
||||||
ignoreKeepAlive: true,
|
|
||||||
},
|
|
||||||
component: '/demo/system/account/index',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'account_detail/:id',
|
|
||||||
name: 'AccountDetail',
|
|
||||||
meta: {
|
|
||||||
hideMenu: true,
|
|
||||||
title: 'routes.demo.system.account_detail',
|
|
||||||
ignoreKeepAlive: true,
|
|
||||||
showMenu: false,
|
|
||||||
currentActiveMenu: '/system/account',
|
|
||||||
},
|
|
||||||
component: '/demo/system/account/AccountDetail',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'role',
|
|
||||||
name: 'RoleManagement',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.demo.system.role',
|
|
||||||
ignoreKeepAlive: true,
|
|
||||||
},
|
|
||||||
component: '/demo/system/role/index',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'dept',
|
|
||||||
name: 'DeptManagement',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.demo.system.dept',
|
|
||||||
ignoreKeepAlive: true,
|
|
||||||
},
|
|
||||||
component: '/demo/system/dept/index',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'changePassword',
|
|
||||||
name: 'ChangePassword',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.demo.system.password',
|
|
||||||
ignoreKeepAlive: true,
|
|
||||||
},
|
|
||||||
component: '/demo/system/password/index',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
const linkRoute = {
|
|
||||||
path: '/link',
|
|
||||||
name: 'Link',
|
|
||||||
component: 'LAYOUT',
|
|
||||||
meta: {
|
|
||||||
icon: 'ion:tv-outline',
|
|
||||||
title: 'routes.demo.iframe.frame',
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: 'doc',
|
|
||||||
name: 'Doc',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.demo.iframe.doc',
|
|
||||||
frameSrc: 'https://vvbin.cn/doc-next/',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: 'https://vvbin.cn/doc-next/',
|
|
||||||
name: 'DocExternal',
|
|
||||||
component: 'LAYOUT',
|
|
||||||
meta: {
|
|
||||||
title: 'routes.demo.iframe.docExternal',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
|
|
||||||
export default [
|
|
||||||
{
|
|
||||||
url: '/api/getMenuList',
|
|
||||||
timeout: 1000,
|
|
||||||
method: 'get',
|
|
||||||
response: (request: requestParams) => {
|
|
||||||
const token = getRequestToken(request)
|
|
||||||
if (!token) {
|
|
||||||
return resultError('Invalid token!')
|
|
||||||
}
|
|
||||||
const checkUser = createFakeUserList().find((item) => item.token === token)
|
|
||||||
if (!checkUser) {
|
|
||||||
return resultError('Invalid user token!')
|
|
||||||
}
|
|
||||||
const id = checkUser.userId
|
|
||||||
let menu: Object[]
|
|
||||||
switch (id) {
|
|
||||||
case '1':
|
|
||||||
dashboardRoute.redirect = dashboardRoute.path + '/' + dashboardRoute.children[0].path
|
|
||||||
menu = [dashboardRoute, authRoute, levelRoute, sysRoute, linkRoute]
|
|
||||||
break
|
|
||||||
case '2':
|
|
||||||
dashboardRoute.redirect = dashboardRoute.path + '/' + dashboardRoute.children[1].path
|
|
||||||
menu = [dashboardRoute, authRoute, levelRoute, linkRoute]
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
menu = []
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultSuccess(menu)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
] as MockMethod[]
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { MockMethod } from 'vite-plugin-mock'
|
import { MockMethod } from 'vite-plugin-mock'
|
||||||
import md5 from 'md5'
|
|
||||||
import { resultError, resultSuccess, getRequestToken, requestParams } from '../_util'
|
import { resultError, resultSuccess, getRequestToken, requestParams } from '../_util'
|
||||||
|
|
||||||
export function createFakeUserList() {
|
export function createFakeUserList() {
|
||||||
@@ -61,26 +60,22 @@ const fakeCodeList: any = {
|
|||||||
'2': ['2000', '4000', '6000'],
|
'2': ['2000', '4000', '6000'],
|
||||||
}
|
}
|
||||||
export default [
|
export default [
|
||||||
{
|
/*{
|
||||||
url: '/api/getLoginSalt',
|
url: '/api/getLoginSalt',
|
||||||
timeout: 200,
|
timeout: 200,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
response: () => {
|
response: () => {
|
||||||
return resultSuccess({ salt: 'nc8w9f82hfioq2ci9hcwehcq' })
|
return resultSuccess({ salt: 'nc8w9f82hfioq2ci9hcwehcq' })
|
||||||
},
|
},
|
||||||
},
|
},*/
|
||||||
// mock user login
|
// mock user login
|
||||||
{
|
/*{
|
||||||
url: '/api/login',
|
url: '/api/login',
|
||||||
timeout: 200,
|
timeout: 200,
|
||||||
method: 'post',
|
method: 'post',
|
||||||
response: ({ body }) => {
|
response: ({ body }) => {
|
||||||
const { username, password } = body
|
const { username } = body
|
||||||
const checkUser = createFakeUserList().find(
|
const checkUser = createFakeUserList().find((item) => item.username === username)
|
||||||
(item) =>
|
|
||||||
item.username === username &&
|
|
||||||
password === md5(item.password + 'nc8w9f82hfioq2ci9hcwehcq'),
|
|
||||||
)
|
|
||||||
if (!checkUser) {
|
if (!checkUser) {
|
||||||
return resultError('Incorrect account or password!')
|
return resultError('Incorrect account or password!')
|
||||||
}
|
}
|
||||||
@@ -94,7 +89,7 @@ export default [
|
|||||||
desc,
|
desc,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},*/
|
||||||
// mock reset password
|
// mock reset password
|
||||||
{
|
{
|
||||||
url: '/api/resetPassword',
|
url: '/api/resetPassword',
|
||||||
@@ -119,19 +114,19 @@ export default [
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
/*{
|
||||||
url: '/api/getUserInfo',
|
url: '/api/getUserInfo',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
response: (request: requestParams) => {
|
response: (request: requestParams) => {
|
||||||
const token = getRequestToken(request)
|
const token = getRequestToken(request)
|
||||||
if (!token) return resultError('Invalid token')
|
if (!token) return resultError('Invalid token')
|
||||||
const checkUser = createFakeUserList().find((item) => item.token === token)
|
const checkUser = createFakeUserList()[0]
|
||||||
if (!checkUser) {
|
if (!checkUser) {
|
||||||
return resultError('The corresponding user information was not obtained!')
|
return resultError('The corresponding user information was not obtained!')
|
||||||
}
|
}
|
||||||
return resultSuccess(checkUser)
|
return resultSuccess(checkUser)
|
||||||
},
|
},
|
||||||
},
|
},*/
|
||||||
{
|
{
|
||||||
url: '/api/getPermCode',
|
url: '/api/getPermCode',
|
||||||
timeout: 200,
|
timeout: 200,
|
||||||
|
|||||||
24
go.mod
24
go.mod
@@ -2,6 +2,26 @@ module github.com/fumiama/paper-manager
|
|||||||
|
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require github.com/sirupsen/logrus v1.9.0
|
require (
|
||||||
|
github.com/FloatTech/sqlite v1.6.0
|
||||||
|
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
||||||
|
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
||||||
|
github.com/fumiama/go-base16384 v1.6.4
|
||||||
|
github.com/sirupsen/logrus v1.9.0
|
||||||
|
)
|
||||||
|
|
||||||
require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
|
require (
|
||||||
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
|
||||||
|
golang.org/x/text v0.3.7 // indirect
|
||||||
|
modernc.org/libc v1.21.5 // indirect
|
||||||
|
modernc.org/mathutil v1.5.0 // indirect
|
||||||
|
modernc.org/memory v1.4.0 // indirect
|
||||||
|
modernc.org/sqlite v1.20.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
replace modernc.org/sqlite => github.com/fumiama/sqlite3 v1.20.0-with-win386
|
||||||
|
|
||||||
|
replace github.com/remyoudompheng/bigfft => github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b
|
||||||
|
|||||||
33
go.sum
33
go.sum
@@ -1,15 +1,42 @@
|
|||||||
|
github.com/FloatTech/sqlite v1.6.0 h1:YJpd+DClVseBWeWz7VF5gNhlTly6Fg0Ds1j7yHp3Nu0=
|
||||||
|
github.com/FloatTech/sqlite v1.6.0/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY=
|
||||||
|
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw=
|
||||||
|
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs=
|
||||||
|
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA=
|
||||||
|
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b h1:Zt3pFQditAdWTHCOVkiloc9ZauBoWrb37guFV4iIRvE=
|
||||||
|
github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
|
github.com/fumiama/go-base16384 v1.6.4 h1:rYDRwD/th2cG4U7QLokpzmST1cCxZGXtHmolOUePt5o=
|
||||||
|
github.com/fumiama/go-base16384 v1.6.4/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||||
|
github.com/fumiama/sqlite3 v1.20.0-with-win386 h1:ZR1AXGBEtkfq9GAXehOVcwn+aaCG8itrkgEsz4ggx5k=
|
||||||
|
github.com/fumiama/sqlite3 v1.20.0-with-win386/go.mod h1:Os58MHwYCcYZCy2PGChBrQtBAw5/LS1ZZOkfc+C/I7s=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
modernc.org/libc v1.21.5 h1:xBkU9fnHV+hvZuPSRszN0AXDG4M7nwPLwTWwkYcvLCI=
|
||||||
|
modernc.org/libc v1.21.5/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
|
||||||
|
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||||
|
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
|
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
|
||||||
|
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||||
|
|||||||
Reference in New Issue
Block a user