mirror of
https://github.com/fumiama/paper-manager.git
synced 2026-06-12 12:10:25 +08:00
finish upload avatar
This commit is contained in:
@@ -1,26 +1,27 @@
|
|||||||
package file
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/fumiama/paper-manager/backend/global"
|
"github.com/fumiama/paper-manager/backend/global"
|
||||||
"github.com/fumiama/paper-manager/backend/utils"
|
"github.com/fumiama/paper-manager/backend/utils"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Handler serves contents in global.FileFolder
|
// FileHandler serves contents in global.FileFolder
|
||||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
func FileHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
if !utils.IsMethod("GET", w, r) {
|
if !utils.IsMethod("GET", w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := strings.LastIndex(r.URL.Path, "/")
|
if r.URL.Path[0] != '/' {
|
||||||
fn := r.URL.Path[i+1:]
|
r.URL.Path = "/" + r.URL.Path
|
||||||
|
}
|
||||||
|
fn := r.URL.Path[6:]
|
||||||
if fn == "" {
|
if fn == "" {
|
||||||
http.Error(w, "400 Bad Request: empty path", http.StatusBadRequest)
|
http.Error(w, "400 Bad Request: empty path", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name := global.FileFolder + fn
|
name := global.FileFolder + fn
|
||||||
logrus.Infoln("[file.Handler]\t serve", name)
|
logrus.Infoln("[file.FileHandler] serve", name)
|
||||||
http.ServeFile(w, r, name)
|
http.ServeFile(w, r, name)
|
||||||
}
|
}
|
||||||
@@ -52,9 +52,12 @@ func getLoginSalt(username string) (*saltinfo, error) {
|
|||||||
return nil, errNoSuchUser
|
return nil, errNoSuchUser
|
||||||
}
|
}
|
||||||
s, _ := loginstatus.Load(username)
|
s, _ := loginstatus.Load(username)
|
||||||
if s != loginStatusNo {
|
if s == loginStatusYes {
|
||||||
return nil, errInvalidLoginStatus
|
return nil, errInvalidLoginStatus
|
||||||
}
|
}
|
||||||
|
if s >= loginStatusFailLast {
|
||||||
|
return nil, errTooManyFailedLogins
|
||||||
|
}
|
||||||
salt := loginsalts.Get(username)
|
salt := loginsalts.Get(username)
|
||||||
if salt.count != nil {
|
if salt.count != nil {
|
||||||
if atomic.AddUintptr(salt.count, 1) >= maxSaltCount {
|
if atomic.AddUintptr(salt.count, 1) >= maxSaltCount {
|
||||||
|
|||||||
@@ -9,13 +9,16 @@ 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[0] != '/' {
|
||||||
|
r.URL.Path = "/" + r.URL.Path
|
||||||
|
}
|
||||||
if r.URL.Path == "/api/getLoginSalt" {
|
if r.URL.Path == "/api/getLoginSalt" {
|
||||||
if !utils.IsMethod("GET", w, r) {
|
if !utils.IsMethod("GET", w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
username := r.URL.Query().Get("username")
|
username := r.URL.Query().Get("username")
|
||||||
if username == "" {
|
if username == "" {
|
||||||
http.Error(w, "400 Bad Request: empty username", http.StatusBadRequest)
|
writeresult(w, codeError, nil, "empty username", typeError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
salt, err := getLoginSalt(username)
|
salt, err := getLoginSalt(username)
|
||||||
@@ -58,6 +61,18 @@ func Handler(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeresult(w, codeSuccess, r, messageOk, typeSuccess)
|
writeresult(w, codeSuccess, r, messageOk, typeSuccess)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if r.URL.Path == "/api/logout" {
|
||||||
|
if !utils.IsMethod("GET", w, r) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := logout(r.Header.Get("Authorization"))
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeresult(w, codeSuccess, nil, messageOk, typeSuccess)
|
||||||
|
return
|
||||||
|
}
|
||||||
if !utils.IsMethod("GET", w, r) {
|
if !utils.IsMethod("GET", w, r) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
98
backend/api/upload.go
Normal file
98
backend/api/upload.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fumiama/imgsz"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/fumiama/paper-manager/backend/global"
|
||||||
|
"github.com/fumiama/paper-manager/backend/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type upload struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Code int `json:"code"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UploadHandler receives uploaded files
|
||||||
|
func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !utils.IsMethod("POST", w, r) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
token := r.Header.Get("Authorization")
|
||||||
|
user := usertokens.Get(token)
|
||||||
|
if user == nil {
|
||||||
|
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ff, h, err := r.FormFile("avatar")
|
||||||
|
if err == nil {
|
||||||
|
defer ff.Close()
|
||||||
|
ct := h.Header.Get("Content-Type")
|
||||||
|
un := h.Filename
|
||||||
|
logrus.Infoln("[file.UploadHandler] receive avatar, username:", un, "& mime:", ct)
|
||||||
|
if !strings.HasPrefix(ct, "image/") {
|
||||||
|
writeresult(w, codeError, nil, "invalid mimetype", typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if un != user.Name {
|
||||||
|
writeresult(w, codeError, nil, "username mismatch", typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = os.MkdirAll(global.FileFolder+strconv.Itoa(*user.ID), 0755)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer(make([]byte, 0, h.Size))
|
||||||
|
_, err := io.Copy(buf, ff)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := buf.Bytes()
|
||||||
|
_, format, err := imgsz.DecodeSize(buf)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userf := global.FileFolder + strconv.Itoa(*user.ID) + "/"
|
||||||
|
err = os.MkdirAll(userf, 0755)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
avf := userf + "avatar." + format
|
||||||
|
err = os.WriteFile(avf, data, 0644)
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = global.UserDB.UpdateUserInfo(*user.ID, "", avf[6:], "")
|
||||||
|
if err != nil {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeresult(w, codeSuccess, &upload{
|
||||||
|
Message: messageOk,
|
||||||
|
Code: codeSuccess,
|
||||||
|
URL: avf[6:],
|
||||||
|
}, messageOk, typeSuccess)
|
||||||
|
user.Avtr = avf[6:]
|
||||||
|
usertokens.Set(token, user)
|
||||||
|
logrus.Infoln("[file.UploadHandler] save avatar to", avf[6:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != http.ErrMissingFile {
|
||||||
|
writeresult(w, codeError, nil, err.Error(), typeError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,10 +2,16 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/fumiama/paper-manager/backend/global"
|
"github.com/fumiama/paper-manager/backend/global"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
chineseDateLayout = "2006年01月02日15时04分05秒"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errInvalidToken = errors.New("invalid token")
|
errInvalidToken = errors.New("invalid token")
|
||||||
)
|
)
|
||||||
@@ -18,6 +24,9 @@ type getUserInfoResult struct {
|
|||||||
Desc string `json:"desc"`
|
Desc string `json:"desc"`
|
||||||
HomePath string `json:"homePath"`
|
HomePath string `json:"homePath"`
|
||||||
Roles []role `json:"roles"`
|
Roles []role `json:"roles"`
|
||||||
|
Date string `json:"date"`
|
||||||
|
Last string `json:"last"`
|
||||||
|
Contact string `json:"contact"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserInfo(token string) (*getUserInfoResult, error) {
|
func getUserInfo(token string) (*getUserInfoResult, error) {
|
||||||
@@ -25,6 +34,16 @@ func getUserInfo(token string) (*getUserInfoResult, error) {
|
|||||||
if user == nil {
|
if user == nil {
|
||||||
return nil, errInvalidToken
|
return nil, errInvalidToken
|
||||||
}
|
}
|
||||||
|
cont := user.Cont
|
||||||
|
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:])
|
||||||
|
cont = sb.String()
|
||||||
|
}
|
||||||
return &getUserInfoResult{
|
return &getUserInfoResult{
|
||||||
UserID: *user.ID,
|
UserID: *user.ID,
|
||||||
Username: user.Name,
|
Username: user.Name,
|
||||||
@@ -37,6 +56,19 @@ func getUserInfo(token string) (*getUserInfoResult, error) {
|
|||||||
}
|
}
|
||||||
return "/dashboard/workbench"
|
return "/dashboard/workbench"
|
||||||
}(),
|
}(),
|
||||||
Roles: []role{{RoleName: user.Role.Nick(), Value: user.Role.String()}},
|
Roles: []role{{RoleName: user.Role.Nick(), Value: user.Role.String()}},
|
||||||
|
Date: time.Unix(user.Date, 0).Format(chineseDateLayout),
|
||||||
|
Last: time.Unix(user.Last, 0).Format(chineseDateLayout),
|
||||||
|
Contact: cont,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logout(token string) error {
|
||||||
|
user := usertokens.Get(token)
|
||||||
|
if user == nil {
|
||||||
|
return errInvalidToken
|
||||||
|
}
|
||||||
|
loginstatus.Delete(user.Name)
|
||||||
|
usertokens.Delete(token)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func init() {
|
|||||||
func initdir(folder string) {
|
func initdir(folder string) {
|
||||||
err := os.MkdirAll(folder, 0755)
|
err := os.MkdirAll(folder, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorln("[os.MkdirAll]\t", err)
|
logrus.Errorln("[os.MkdirAll]", err)
|
||||||
os.Exit(line())
|
os.Exit(line())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ var (
|
|||||||
ErrEmptyUserID = errors.New("empty user ID")
|
ErrEmptyUserID = errors.New("empty user ID")
|
||||||
ErrEmptyContect = errors.New("empty contact")
|
ErrEmptyContect = errors.New("empty contact")
|
||||||
ErrUsernameExists = errors.New("username exists")
|
ErrUsernameExists = errors.New("username exists")
|
||||||
|
ErrInvalidName = errors.New("invalid name")
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -88,7 +89,7 @@ func init() {
|
|||||||
Cont: "028-61830156",
|
Cont: "028-61830156",
|
||||||
Desc: "日は山の端にかかりぬ",
|
Desc: "日は山の端にかかりぬ",
|
||||||
}, "系统")
|
}, "系统")
|
||||||
logrus.Warn("[global.user] 初次启动, 创建初始账户 fumiama 密码 123456")
|
logrus.Warn("[user] 初次启动, 创建初始账户 fumiama 密码 123456")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +122,11 @@ func (u *UserDatabase) AddUser(user *User, opname string) error {
|
|||||||
if u.IsNameExists(user.Name) {
|
if u.IsNameExists(user.Name) {
|
||||||
return ErrUsernameExists
|
return ErrUsernameExists
|
||||||
}
|
}
|
||||||
|
for _, c := range user.Name {
|
||||||
|
if !(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') {
|
||||||
|
return ErrInvalidName
|
||||||
|
}
|
||||||
|
}
|
||||||
user.Date = time.Now().Unix()
|
user.Date = time.Now().Unix()
|
||||||
user.Last = user.Date
|
user.Last = user.Date
|
||||||
_ = u.notifyUserAdded(opname, user.Name)
|
_ = u.notifyUserAdded(opname, user.Name)
|
||||||
@@ -146,7 +152,7 @@ func (u *UserDatabase) UpdateUserInfo(id int, nick, avtr, desc string) error {
|
|||||||
}
|
}
|
||||||
u.mu.Lock()
|
u.mu.Lock()
|
||||||
defer u.mu.Unlock()
|
defer u.mu.Unlock()
|
||||||
return u.db.Insert(UserTableUser, user)
|
return u.db.Insert(UserTableUser, &user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUserRole ...
|
// UpdateUserRole ...
|
||||||
@@ -161,7 +167,7 @@ func (u *UserDatabase) UpdateUserRole(id int, nr UserRole) error {
|
|||||||
user.Role = nr
|
user.Role = nr
|
||||||
u.mu.Lock()
|
u.mu.Lock()
|
||||||
defer u.mu.Unlock()
|
defer u.mu.Unlock()
|
||||||
return u.db.Insert(UserTableUser, user)
|
return u.db.Insert(UserTableUser, &user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUserPassword ...
|
// UpdateUserPassword ...
|
||||||
@@ -178,7 +184,7 @@ func (u *UserDatabase) UpdateUserPassword(id int, npwd string) error {
|
|||||||
_ = u.notifyPasswordChange(user.Name, npwd)
|
_ = u.notifyPasswordChange(user.Name, npwd)
|
||||||
u.mu.Lock()
|
u.mu.Lock()
|
||||||
defer u.mu.Unlock()
|
defer u.mu.Unlock()
|
||||||
return u.db.Insert(UserTableUser, user)
|
return u.db.Insert(UserTableUser, &user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateUserContact ...
|
// UpdateUserContact ...
|
||||||
@@ -194,12 +200,18 @@ func (u *UserDatabase) UpdateUserContact(id int, ncont string) error {
|
|||||||
_ = u.notifyContactChange(user.Name, ncont)
|
_ = u.notifyContactChange(user.Name, ncont)
|
||||||
u.mu.Lock()
|
u.mu.Lock()
|
||||||
defer u.mu.Unlock()
|
defer u.mu.Unlock()
|
||||||
return u.db.Insert(UserTableUser, user)
|
return u.db.Insert(UserTableUser, &user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserByName avoids sql injection by removing ; ' " =
|
// GetUserByName avoids sql injection by removing ; ' " =
|
||||||
func (u *UserDatabase) GetUserByName(username string) (user User, err error) {
|
func (u *UserDatabase) GetUserByName(username string) (user User, err error) {
|
||||||
username = strings.NewReplacer(";", "", "'", "", `"`, "", "=", "").Replace(username)
|
username = strings.NewReplacer(";", "", "'", "", `"`, "", "=", "").Replace(username)
|
||||||
|
for _, c := range username {
|
||||||
|
if !(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') {
|
||||||
|
err = ErrInvalidName
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
u.mu.RLock()
|
u.mu.RLock()
|
||||||
err = u.db.Find(UserTableUser, &user, "WHERE Name='"+username+"'")
|
err = u.db.Find(UserTableUser, &user, "WHERE Name='"+username+"'")
|
||||||
u.mu.RUnlock()
|
u.mu.RUnlock()
|
||||||
@@ -209,6 +221,11 @@ func (u *UserDatabase) GetUserByName(username string) (user User, err error) {
|
|||||||
// IsNameExists avoids sql injection by removing ; ' " =
|
// IsNameExists avoids sql injection by removing ; ' " =
|
||||||
func (u *UserDatabase) IsNameExists(username string) bool {
|
func (u *UserDatabase) IsNameExists(username string) bool {
|
||||||
username = strings.NewReplacer(";", "", "'", "", `"`, "", "=", "").Replace(username)
|
username = strings.NewReplacer(";", "", "'", "", `"`, "", "=", "").Replace(username)
|
||||||
|
for _, c := range username {
|
||||||
|
if !(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
u.mu.RLock()
|
u.mu.RLock()
|
||||||
defer u.mu.RUnlock()
|
defer u.mu.RUnlock()
|
||||||
return u.db.CanFind(UserTableUser, "WHERE Name='"+username+"'")
|
return u.db.CanFind(UserTableUser, "WHERE Name='"+username+"'")
|
||||||
@@ -265,6 +282,21 @@ func (u *UserDatabase) GetSuperIDs() (ids []int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsUser checks if token is valid for a user
|
||||||
|
func (user *User) IsUser() bool {
|
||||||
|
return user.Role == RoleUser || user.Role == RoleFileManager || user.Role == RoleSuper
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsFileManager checks if token is valid for a filemgr
|
||||||
|
func (user *User) IsFileManager() bool {
|
||||||
|
return user.Role == RoleFileManager || user.Role == RoleSuper
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSuper checks if token is valid for a super
|
||||||
|
func (user *User) IsSuper() bool {
|
||||||
|
return user.Role == RoleSuper
|
||||||
|
}
|
||||||
|
|
||||||
// Message is shown in the workbench
|
// Message is shown in the workbench
|
||||||
type Message struct {
|
type Message struct {
|
||||||
ID *int
|
ID *int
|
||||||
@@ -282,7 +314,7 @@ func (u *UserDatabase) SendMessage(m *Message) error {
|
|||||||
m.Date = time.Now().Unix()
|
m.Date = time.Now().Unix()
|
||||||
u.mu.Lock()
|
u.mu.Lock()
|
||||||
defer u.mu.Unlock()
|
defer u.mu.Unlock()
|
||||||
return u.db.InsertUnique(UserTableMessage, &m)
|
return u.db.InsertUnique(UserTableMessage, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyRegister will send register notification to all supers
|
// NotifyRegister will send register notification to all supers
|
||||||
@@ -290,6 +322,11 @@ func (u *UserDatabase) NotifyRegister(name, cont, pswd string) error {
|
|||||||
if name == "" {
|
if name == "" {
|
||||||
return ErrEmptyName
|
return ErrEmptyName
|
||||||
}
|
}
|
||||||
|
for _, c := range name {
|
||||||
|
if !(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') {
|
||||||
|
return ErrInvalidName
|
||||||
|
}
|
||||||
|
}
|
||||||
if pswd == "" {
|
if pswd == "" {
|
||||||
return ErrEmptyPassword
|
return ErrEmptyPassword
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ func IP(r *http.Request) string {
|
|||||||
// IsMethod check if the method meets the requirement
|
// IsMethod check if the method meets the requirement
|
||||||
// and response 405 Method Not Allowed if not matched
|
// and response 405 Method Not Allowed if not matched
|
||||||
func IsMethod(m string, w http.ResponseWriter, r *http.Request) bool {
|
func IsMethod(m string, w http.ResponseWriter, r *http.Request) bool {
|
||||||
logrus.Infoln("[utils.IsMethod]\t accept", IP(r), r.Method, r.URL)
|
logrus.Infoln("[utils.IsMethod] accept", IP(r), r.Method, r.URL)
|
||||||
if r.Method != m {
|
if r.Method != m {
|
||||||
http.Error(w, "405 Method Not Allowed", http.StatusMethodNotAllowed)
|
http.Error(w, "405 Method Not Allowed", http.StatusMethodNotAllowed)
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export default [
|
|||||||
return resultSuccess(codeList)
|
return resultSuccess(codeList)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
/*{
|
||||||
url: '/api/logout',
|
url: '/api/logout',
|
||||||
timeout: 200,
|
timeout: 200,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -156,13 +156,13 @@ export default [
|
|||||||
}
|
}
|
||||||
return resultSuccess(undefined, { message: 'Token has been destroyed' })
|
return resultSuccess(undefined, { message: 'Token has been destroyed' })
|
||||||
},
|
},
|
||||||
},
|
},*/
|
||||||
{
|
/*{
|
||||||
url: '/api/testRetry',
|
url: '/api/testRetry',
|
||||||
statusCode: 405,
|
statusCode: 405,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
response: () => {
|
response: () => {
|
||||||
return resultError('Error!')
|
return resultError('Error!')
|
||||||
},
|
},
|
||||||
},
|
},*/
|
||||||
] as MockMethod[]
|
] as MockMethod[]
|
||||||
|
|||||||
@@ -66,6 +66,12 @@ export interface GetUserInfoModel {
|
|||||||
avatar: string
|
avatar: string
|
||||||
// 介绍
|
// 介绍
|
||||||
desc?: string
|
desc?: string
|
||||||
|
// 创建日期
|
||||||
|
date: string
|
||||||
|
// 上次修改密码日期
|
||||||
|
last: string
|
||||||
|
// 电话
|
||||||
|
contact: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GetLoginSaltModel {
|
export interface GetLoginSaltModel {
|
||||||
|
|||||||
@@ -187,7 +187,7 @@
|
|||||||
try {
|
try {
|
||||||
setModalProps({ confirmLoading: true })
|
setModalProps({ confirmLoading: true })
|
||||||
const result = await uploadApi({ name: 'file', file: blob, filename })
|
const result = await uploadApi({ name: 'file', file: blob, filename })
|
||||||
emit('uploadSuccess', { source: previewSource.value, data: result.url })
|
emit('uploadSuccess', { source: previewSource.value, data: result.data.result.url })
|
||||||
closeModal()
|
closeModal()
|
||||||
} finally {
|
} finally {
|
||||||
setModalProps({ confirmLoading: false })
|
setModalProps({ confirmLoading: false })
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
<div class="change-avatar">
|
<div class="change-avatar">
|
||||||
<div class="mb-2">头像</div>
|
<div class="mb-2">头像</div>
|
||||||
<CropperAvatar
|
<CropperAvatar
|
||||||
:uploadApi="uploadApi"
|
:uploadApi="onUpload as any"
|
||||||
:value="avatar"
|
:value="avatarRef"
|
||||||
btnText="更换头像"
|
btnText="更换头像"
|
||||||
:btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
|
:btnProps="{ preIcon: 'ant-design:cloud-upload-outlined' }"
|
||||||
@change="updateAvatar"
|
@change="updateAvatar"
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button, Row, Col } from 'ant-design-vue'
|
import { Button, Row, Col } from 'ant-design-vue'
|
||||||
import { computed, defineComponent, onMounted } from 'vue'
|
import { ref, defineComponent, onMounted } from 'vue'
|
||||||
import { BasicForm, useForm } from '/@/components/Form/index'
|
import { BasicForm, useForm } from '/@/components/Form/index'
|
||||||
import { CollapseContainer } from '/@/components/Container'
|
import { CollapseContainer } from '/@/components/Container'
|
||||||
import { CropperAvatar } from '/@/components/Cropper'
|
import { CropperAvatar } from '/@/components/Cropper'
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
import { useMessage } from '/@/hooks/web/useMessage'
|
import { useMessage } from '/@/hooks/web/useMessage'
|
||||||
|
|
||||||
import headerImg from '/@/assets/images/header.jpg'
|
import headerImg from '/@/assets/images/header.jpg'
|
||||||
import { accountInfoApi } from '/@/api/demo/account'
|
|
||||||
import { baseSetschemas } from './data'
|
import { baseSetschemas } from './data'
|
||||||
import { useUserStore } from '/@/store/modules/user'
|
import { useUserStore } from '/@/store/modules/user'
|
||||||
import { uploadApi } from '/@/api/sys/upload'
|
import { uploadApi } from '/@/api/sys/upload'
|
||||||
@@ -48,6 +47,7 @@
|
|||||||
setup() {
|
setup() {
|
||||||
const { createMessage } = useMessage()
|
const { createMessage } = useMessage()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
const { avatar } = userStore.getUserInfo
|
||||||
|
|
||||||
const [register, { setFieldsValue }] = useForm({
|
const [register, { setFieldsValue }] = useForm({
|
||||||
labelWidth: 120,
|
labelWidth: 120,
|
||||||
@@ -56,27 +56,36 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const data = await accountInfoApi()
|
const data = userStore.getUserInfo
|
||||||
setFieldsValue(data)
|
setFieldsValue(data)
|
||||||
})
|
})
|
||||||
|
|
||||||
const avatar = computed(() => {
|
const avatarRef = ref(avatar || headerImg)
|
||||||
const { avatar } = userStore.getUserInfo
|
|
||||||
console.log(avatar)
|
|
||||||
return avatar || headerImg
|
|
||||||
})
|
|
||||||
|
|
||||||
function updateAvatar({ src, data }) {
|
function updateAvatar({ src }) {
|
||||||
const userinfo = userStore.getUserInfo
|
const userinfo = userStore.getUserInfo
|
||||||
userinfo.avatar = src
|
userinfo.avatar = src
|
||||||
userStore.setUserInfo(userinfo)
|
userStore.setUserInfo(userinfo)
|
||||||
console.log('data', data)
|
}
|
||||||
|
|
||||||
|
async function onUpload(value: { file: Blob; name: string }) {
|
||||||
|
const data = userStore.getUserInfo
|
||||||
|
const result = await uploadApi(
|
||||||
|
{
|
||||||
|
name: 'avatar',
|
||||||
|
file: value.file,
|
||||||
|
filename: data.username,
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
)
|
||||||
|
avatarRef.value = result.data.url
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
avatar,
|
avatarRef,
|
||||||
register,
|
register,
|
||||||
uploadApi: uploadApi as any,
|
onUpload,
|
||||||
updateAvatar,
|
updateAvatar,
|
||||||
handleSubmit: () => {
|
handleSubmit: () => {
|
||||||
createMessage.success('更新成功!')
|
createMessage.success('更新成功!')
|
||||||
|
|||||||
@@ -23,14 +23,28 @@
|
|||||||
import { List } from 'ant-design-vue'
|
import { List } from 'ant-design-vue'
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
import { CollapseContainer } from '/@/components/Container/index'
|
import { CollapseContainer } from '/@/components/Container/index'
|
||||||
|
import { useUserStore } from '/@/store/modules/user'
|
||||||
import { secureSettingList } from './data'
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { CollapseContainer, List, ListItem: List.Item, ListItemMeta: List.Item.Meta },
|
components: { CollapseContainer, List, ListItem: List.Item, ListItemMeta: List.Item.Meta },
|
||||||
setup() {
|
setup() {
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const { last, contact } = userStore.getUserInfo
|
||||||
return {
|
return {
|
||||||
list: secureSettingList,
|
list: [
|
||||||
|
{
|
||||||
|
key: '1',
|
||||||
|
title: '账户密码',
|
||||||
|
description: '上次修改密码: ' + last,
|
||||||
|
extra: '修改',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: '2',
|
||||||
|
title: '我的手机',
|
||||||
|
description: '已绑定手机: ' + contact,
|
||||||
|
extra: '修改',
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,14 +1,5 @@
|
|||||||
import { FormSchema } from '/@/components/Form/index'
|
import { FormSchema } from '/@/components/Form/index'
|
||||||
|
|
||||||
export interface ListItem {
|
|
||||||
key: string
|
|
||||||
title: string
|
|
||||||
description: string
|
|
||||||
extra?: string
|
|
||||||
avatar?: string
|
|
||||||
color?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
// tab的list
|
// tab的list
|
||||||
export const settingList = [
|
export const settingList = [
|
||||||
{
|
{
|
||||||
@@ -26,31 +17,15 @@ export const settingList = [
|
|||||||
// 基础设置 form
|
// 基础设置 form
|
||||||
export const baseSetschemas: FormSchema[] = [
|
export const baseSetschemas: FormSchema[] = [
|
||||||
{
|
{
|
||||||
field: 'name',
|
field: 'realName',
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
label: '昵称',
|
label: '昵称',
|
||||||
colProps: { span: 18 },
|
colProps: { span: 18 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'introduction',
|
field: 'desc',
|
||||||
component: 'InputTextArea',
|
component: 'InputTextArea',
|
||||||
label: '个人简介',
|
label: '个人简介',
|
||||||
colProps: { span: 18 },
|
colProps: { span: 18 },
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
// 安全设置 list
|
|
||||||
export const secureSettingList: ListItem[] = [
|
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
title: '账户密码',
|
|
||||||
description: '上次修改密码: 2022年1月1日0时0分0秒',
|
|
||||||
extra: '修改',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '2',
|
|
||||||
title: '我的手机',
|
|
||||||
description: '已绑定手机: 138****8293',
|
|
||||||
extra: '修改',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|||||||
3
frontend/vben/types/store.d.ts
vendored
3
frontend/vben/types/store.d.ts
vendored
@@ -30,6 +30,9 @@ export interface UserInfo {
|
|||||||
desc?: string
|
desc?: string
|
||||||
homePath?: string
|
homePath?: string
|
||||||
roles: RoleInfo[]
|
roles: RoleInfo[]
|
||||||
|
date: string
|
||||||
|
last: string
|
||||||
|
contact: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BeforeMiniState {
|
export interface BeforeMiniState {
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -7,6 +7,7 @@ require (
|
|||||||
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b
|
||||||
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e
|
||||||
github.com/fumiama/go-base16384 v1.6.4
|
github.com/fumiama/go-base16384 v1.6.4
|
||||||
|
github.com/fumiama/imgsz v0.0.2
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -11,6 +11,8 @@ github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b h1:Zt3pFQditAdWTHCO
|
|||||||
github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
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 h1:rYDRwD/th2cG4U7QLokpzmST1cCxZGXtHmolOUePt5o=
|
||||||
github.com/fumiama/go-base16384 v1.6.4/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
github.com/fumiama/go-base16384 v1.6.4/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM=
|
||||||
|
github.com/fumiama/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak=
|
||||||
|
github.com/fumiama/imgsz v0.0.2/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4=
|
||||||
github.com/fumiama/sqlite3 v1.20.0-with-win386 h1:ZR1AXGBEtkfq9GAXehOVcwn+aaCG8itrkgEsz4ggx5k=
|
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/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 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
|||||||
10
main.go
10
main.go
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/fumiama/paper-manager/backend/api"
|
"github.com/fumiama/paper-manager/backend/api"
|
||||||
"github.com/fumiama/paper-manager/backend/file"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func line() int {
|
func line() int {
|
||||||
@@ -26,14 +25,15 @@ func main() {
|
|||||||
flag.Parse()
|
flag.Parse()
|
||||||
l, err := net.Listen("tcp", *addr)
|
l, err := net.Listen("tcp", *addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorln("[net.Listen]\t", err)
|
logrus.Errorln("[net.Listen]", err)
|
||||||
os.Exit(line())
|
os.Exit(line())
|
||||||
}
|
}
|
||||||
|
|
||||||
http.HandleFunc("/api/", api.Handler)
|
http.HandleFunc("/api/", api.Handler)
|
||||||
http.HandleFunc("/file/", file.Handler)
|
http.HandleFunc("/file/", api.FileHandler)
|
||||||
|
http.HandleFunc("/upload", api.UploadHandler)
|
||||||
|
|
||||||
logrus.Infoln("[http.Serve]\t start at", l.Addr())
|
logrus.Infoln("[http.Serve] start at", l.Addr())
|
||||||
logrus.Errorln("[http.Serve]\t", http.Serve(l, nil))
|
logrus.Errorln("[http.Serve]", http.Serve(l, nil))
|
||||||
os.Exit(line())
|
os.Exit(line())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user