1
0
mirror of https://github.com/fumiama/paper-manager.git synced 2026-06-11 11:40:23 +08:00

add /api/getUserRegex

This commit is contained in:
源文雨
2023-04-21 00:29:25 +08:00
parent f65874cf52
commit 155420d0a7
10 changed files with 337 additions and 276 deletions

View File

@@ -1,13 +1,283 @@
package backend
import (
"errors"
"net/http"
"strconv"
"strings"
"time"
sql "github.com/FloatTech/sqlite"
"github.com/fumiama/paper-manager/backend/global"
"github.com/fumiama/paper-manager/backend/utils"
"github.com/sirupsen/logrus"
)
var (
errNoDeletePermission = errors.New("no delete permission")
errExtractUIDError = errors.New("extract uid error")
errParseFilePath = errors.New("parse filepath error")
errNoDownloadPermission = errors.New("no download permission")
)
type filelist struct {
ID int `json:"id"`
Title string `json:"title"`
Desc string `json:"description"`
Size float64 `json:"size"`
Ques int `json:"questions"`
Auth string `json:"author"`
Date string `json:"datetime"`
Per uint `json:"percent"`
}
func getFileList(count int, istemp bool) ([]filelist, error) {
lst, err := global.FileDB.ListUploadedFile(istemp)
if err != nil && err != sql.ErrNullResult {
return nil, err
}
if count > 0 && len(lst) > count {
lst = lst[:count]
}
result := make([]filelist, len(lst))
for i, v := range lst {
result[i].ID = *v.ID
j := strings.LastIndex(v.Path, "/")
if j <= 0 {
result[i].Title = v.Path
} else {
result[i].Title = v.Path[j+1:]
}
result[i].Desc = v.Desc
result[i].Size = float64(v.Size) / 1024 / 1024 // MB
result[i].Ques = v.QuesC
result[i].Auth = v.UpName
result[i].Date = time.Unix(v.UpTime, 0).Format(chineseYYMMDDLayout)
if !v.HasntAnalyzed {
result[i].Per = 100
} else {
result[i].Per = analyzeper.Get(*v.ID)
}
}
return result, nil
}
func getFileInfo(lstid int) (*filelist, error) {
lst, err := global.FileDB.ListFileByID(lstid)
if err != nil && err != sql.ErrNullResult {
return nil, err
}
result := filelist{
ID: lstid,
Desc: lst.Desc,
Size: float64(lst.Size) / 1024 / 1024, // MB
Ques: lst.QuesC,
Auth: lst.UpName,
Date: time.Unix(lst.UpTime, 0).Format(chineseYYMMDDLayout),
}
j := strings.LastIndex(lst.Path, "/")
if j <= 0 {
result.Title = lst.Path
} else {
result.Title = lst.Path[j+1:]
}
if !lst.HasntAnalyzed {
result.Per = 100
} else {
result.Per = analyzeper.Get(lstid)
}
return &result, nil
}
func dlFile(lstid int, user *global.User) (string, error) {
lst, err := global.FileDB.ListFileByID(lstid)
if err != nil {
return "", err
}
if strings.HasPrefix(lst.Path, global.PaperFolder+"tmp/") {
uidstr := lst.Path[17:]
i := strings.Index(uidstr, "/")
if i <= 0 {
return "", errExtractUIDError
}
uid, err := strconv.Atoi(uidstr[:i])
if err != nil {
return "", err
}
if uid != *user.ID {
return "", errNoDownloadPermission
}
return lst.Path[6:], nil
}
if strings.HasPrefix(lst.Path, global.PaperFolder) {
return lst.Path[6:], nil
}
return "", errParseFilePath
}
type filestatus struct {
Name string `json:"name"`
Size float64 `json:"size"`
Rate float64 `json:"rate"`
Questions []question `json:"questions"`
Duplications []duplication `json:"duplications"` // Duplications length == 10
}
func getFileStatus(lstid int, user *global.User) (*filestatus, error) {
file, sz, istemp, err := global.FileDB.GetFile(lstid, *user.ID)
if err != nil {
return nil, err
}
qs, ds, filerate, err := parseFileQuestions(file.Questions, istemp)
if err != nil {
return nil, err
}
return &filestatus{
Name: file.Class + ".docx",
Size: float64(sz) / 1024 / 1024, // MB
Rate: filerate * 100,
Questions: qs,
Duplications: ds,
}, nil
}
func init() {
apimap["/api/getFileList"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
istemp := r.URL.Query().Get("permanent") != "true"
count := -1
var err error
countstr := r.URL.Query().Get("count")
if countstr != "" {
count, err = strconv.Atoi(countstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
}
lst, err := getFileList(count, istemp)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
writeresult(w, codeSuccess, &lst, messageOk, typeSuccess)
}}
apimap["/api/getFileInfo"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
var err error
idstr := r.URL.Query().Get("id")
if idstr == "" {
writeresult(w, codeError, nil, "empty id", typeError)
return
}
id, err := strconv.Atoi(idstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
inf, err := getFileInfo(id)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
writeresult(w, codeSuccess, inf, messageOk, typeSuccess)
}}
apimap["/api/delFile"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
istemp := r.URL.Query().Get("permanent") != "true"
if !user.IsSuper() && !istemp {
writeresult(w, codeError, nil, errNoDeletePermission.Error(), typeError)
return
}
idstr := r.URL.Query().Get("id")
if idstr == "" {
writeresult(w, codeError, nil, "empty id", typeError)
return
}
id, err := strconv.Atoi(idstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
err = global.FileDB.DelFile(id, *user.ID, istemp)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
writeresult(w, codeSuccess, "删除成功", messageOk, typeSuccess)
}}
apimap["/api/dlFile"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
idstr := r.URL.Query().Get("id")
if idstr == "" {
writeresult(w, codeError, nil, "empty id", typeError)
return
}
id, err := strconv.Atoi(idstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
type message struct {
URL string `json:"url"`
}
u, err := dlFile(id, user)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
writeresult(w, codeSuccess, &message{URL: u}, messageOk, typeSuccess)
}}
apimap["/api/getFileStatus"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
idstr := r.URL.Query().Get("id")
if idstr == "" {
writeresult(w, codeError, nil, "empty id", typeError)
return
}
id, err := strconv.Atoi(idstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
fstat, err := getFileStatus(id, user)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
writeresult(w, codeSuccess, fstat, messageOk, typeSuccess)
}}
}
// FileHandler serves contents in global.FileFolder
func FileHandler(w http.ResponseWriter, r *http.Request) {
if !utils.IsMethod("GET", w, r) {

View File

@@ -21,7 +21,7 @@ type Regex struct {
Sub string // Sub default `(\d+)、`
}
func newRegex() (reg Regex) {
func GetDefaultRegex() (reg Regex) {
reg.Title = `.*(\d{4})\s*-.*学年.*(\d).*([中末]).*([AB])\s*卷`
reg.Class = `(考试科目|课程名称)\s*(\S+)\s*`
reg.OpenCl = `考试形式:\s*(\S+)\s*`
@@ -52,7 +52,7 @@ func (u *UserDatabase) SetUserRegex(id int, name, re string) error {
if err != nil {
return err
}
reg := newRegex()
reg := GetDefaultRegex()
rreg := reflect.ValueOf(&reg).Elem()
f := rreg.FieldByName(name)
if !f.IsValid() {
@@ -80,7 +80,7 @@ func (u *UserDatabase) GetUserRegex(id int) (*Regex, error) {
u.mu.RUnlock()
reg.ID = *user.ID
rf := reflect.ValueOf(reg)
defaultrf := reflect.ValueOf(newRegex())
defaultrf := reflect.ValueOf(GetDefaultRegex())
for i := 0; i < rf.NumField(); i++ {
if rf.Field(i).IsZero() {
rf.Field(i).Set(defaultrf.Field(i))

View File

@@ -98,7 +98,7 @@ type loginResult struct {
var (
usertokens = ttl.NewCacheOn(time.Hour, [4]func(string, *global.User){
nil, nil, func(t string, _ *global.User) { loginstatus.Delete(t) }, nil,
nil, nil, func(_ string, user *global.User) { loginstatus.Delete(user.Name) }, nil,
})
)

View File

@@ -7,7 +7,6 @@ import (
"strings"
"time"
sql "github.com/FloatTech/sqlite"
"github.com/FloatTech/ttl"
"github.com/fumiama/paper-manager/backend/global"
"github.com/fumiama/paper-manager/backend/utils"
@@ -22,123 +21,10 @@ const (
var analyzeper = ttl.NewCache[int, uint](time.Hour)
var (
errNoAnalyzePermission = errors.New("no analyze permission")
errNoDeletePermission = errors.New("no delete permission")
errNoDownloadPermission = errors.New("no download permission")
errNoAnalyzePermission = errors.New("no analyze permission")
)
type filelist struct {
ID int `json:"id"`
Title string `json:"title"`
Desc string `json:"description"`
Size float64 `json:"size"`
Ques int `json:"questions"`
Auth string `json:"author"`
Date string `json:"datetime"`
Per uint `json:"percent"`
}
type filestatus struct {
Name string `json:"name"`
Size float64 `json:"size"`
Rate float64 `json:"rate"`
Questions []question `json:"questions"`
Duplications []duplication `json:"duplications"` // Duplications length == 10
}
func init() {
apimap["/api/getFileList"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
istemp := r.URL.Query().Get("permanent") != "true"
count := -1
var err error
countstr := r.URL.Query().Get("count")
if countstr != "" {
count, err = strconv.Atoi(countstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
}
lst, err := global.FileDB.ListUploadedFile(istemp)
if err != nil && err != sql.ErrNullResult {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
if count > 0 && len(lst) > count {
lst = lst[:count]
}
result := make([]filelist, len(lst))
for i, v := range lst {
result[i].ID = *v.ID
j := strings.LastIndex(v.Path, "/")
if j <= 0 {
result[i].Title = v.Path
} else {
result[i].Title = v.Path[j+1:]
}
result[i].Desc = v.Desc
result[i].Size = float64(v.Size) / 1024 / 1024 // MB
result[i].Ques = v.QuesC
result[i].Auth = v.UpName
result[i].Date = time.Unix(v.UpTime, 0).Format(chineseYYMMDDLayout)
if !v.HasntAnalyzed {
result[i].Per = 100
} else {
result[i].Per = analyzeper.Get(*v.ID)
}
}
writeresult(w, codeSuccess, &result, messageOk, typeSuccess)
}}
apimap["/api/getFileInfo"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
var err error
idstr := r.URL.Query().Get("id")
if idstr == "" {
writeresult(w, codeError, nil, "empty id", typeError)
return
}
id, err := strconv.Atoi(idstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
lst, err := global.FileDB.ListFileByID(id)
if err != nil && err != sql.ErrNullResult {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
result := filelist{
ID: id,
Desc: lst.Desc,
Size: float64(lst.Size) / 1024 / 1024, // MB
Ques: lst.QuesC,
Auth: lst.UpName,
Date: time.Unix(lst.UpTime, 0).Format(chineseYYMMDDLayout),
}
j := strings.LastIndex(lst.Path, "/")
if j <= 0 {
result.Title = lst.Path
} else {
result.Title = lst.Path[j+1:]
}
if !lst.HasntAnalyzed {
result.Per = 100
} else {
result.Per = analyzeper.Get(id)
}
writeresult(w, codeSuccess, &result, messageOk, typeSuccess)
}}
apimap["/api/getFilePercent"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
@@ -158,6 +44,7 @@ func init() {
}
writeresult(w, codeSuccess, analyzeper.Get(id), messageOk, typeSuccess)
}}
apimap["/api/analyzeFile"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
@@ -211,120 +98,6 @@ func init() {
writeresult(w, codeSuccess, &message{C: 0, M: "分析完成"}, messageOk, typeSuccess)
}
}}
apimap["/api/delFile"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
istemp := r.URL.Query().Get("permanent") != "true"
if !user.IsSuper() && !istemp {
writeresult(w, codeError, nil, errNoDeletePermission.Error(), typeError)
return
}
idstr := r.URL.Query().Get("id")
if idstr == "" {
writeresult(w, codeError, nil, "empty id", typeError)
return
}
id, err := strconv.Atoi(idstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
err = global.FileDB.DelFile(id, *user.ID, istemp)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
writeresult(w, codeSuccess, "删除成功", messageOk, typeSuccess)
}}
apimap["/api/dlFile"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
idstr := r.URL.Query().Get("id")
if idstr == "" {
writeresult(w, codeError, nil, "empty id", typeError)
return
}
id, err := strconv.Atoi(idstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
lst, err := global.FileDB.ListFileByID(id)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
type message struct {
URL string `json:"url"`
}
if strings.HasPrefix(lst.Path, global.PaperFolder+"tmp/") {
uidstr := lst.Path[17:]
i := strings.Index(uidstr, "/")
if i <= 0 {
writeresult(w, codeError, nil, "extract uid error", typeError)
return
}
uid, err := strconv.Atoi(uidstr[:i])
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
if uid != *user.ID {
writeresult(w, codeError, nil, errNoDownloadPermission.Error(), typeError)
return
}
writeresult(w, codeSuccess, &message{URL: lst.Path[6:]}, messageOk, typeSuccess)
return
}
if strings.HasPrefix(lst.Path, global.PaperFolder) {
writeresult(w, codeSuccess, &message{URL: lst.Path[6:]}, messageOk, typeSuccess)
return
}
writeresult(w, codeError, nil, "parse filepath error", typeError)
}}
apimap["/api/getFileStatus"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
user := usertokens.Get(token)
if user == nil {
writeresult(w, codeError, nil, errInvalidToken.Error(), typeError)
return
}
idstr := r.URL.Query().Get("id")
if idstr == "" {
writeresult(w, codeError, nil, "empty id", typeError)
return
}
id, err := strconv.Atoi(idstr)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
file, sz, istemp, err := global.FileDB.GetFile(id, *user.ID)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
qs, ds, filerate, err := parseFileQuestions(file.Questions, istemp)
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
writeresult(w, codeSuccess, &filestatus{
Name: file.Class + ".docx",
Size: float64(sz) / 1024 / 1024, // MB
Rate: filerate * 100,
Questions: qs,
Duplications: ds,
}, messageOk, typeSuccess)
}}
}
// PaperHandler serves protected contents in global.PaperFolder

26
backend/regex.go Normal file
View File

@@ -0,0 +1,26 @@
package backend
import (
"net/http"
"github.com/fumiama/paper-manager/backend/global"
)
func getUserRegex(token string) (*global.Regex, error) {
user := usertokens.Get(token)
if user == nil {
return nil, errInvalidToken
}
return global.UserDB.GetUserRegex(*user.ID)
}
func init() {
apimap["/api/getUserRegex"] = &apihandler{"GET", func(w http.ResponseWriter, r *http.Request) {
reg, err := getUserRegex(r.Header.Get("Authorization"))
if err != nil {
writeresult(w, codeError, nil, err.Error(), typeError)
return
}
writeresult(w, codeSuccess, reg, messageOk, typeSuccess)
}}
}