mirror of
https://github.com/fumiama/paper-manager.git
synced 2026-06-05 07:50:23 +08:00
implement file.AddFile
This commit is contained in:
@@ -1,9 +1,17 @@
|
|||||||
package global
|
package global
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/fumiama/go-docx"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -11,6 +19,10 @@ const (
|
|||||||
FileTableQuestion = "question"
|
FileTableQuestion = "question"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrMajorSplitsTooShort = errors.New("major splits too short")
|
||||||
|
)
|
||||||
|
|
||||||
// PaperType [4 开 一页纸 闭] [4 上下] [4 中末] [4 AB]
|
// PaperType [4 开 一页纸 闭] [4 上下] [4 中末] [4 AB]
|
||||||
type PaperType uint16
|
type PaperType uint16
|
||||||
|
|
||||||
@@ -161,6 +173,144 @@ type File struct {
|
|||||||
Questions []byte // Questions is for json struct QuestionJSON
|
Questions []byte // Questions is for json struct QuestionJSON
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddFile from FileFolder+tempath and copy it to File.Path.
|
||||||
|
// The para res must belong to a valid user
|
||||||
|
func (f *FileDatabase) AddFile(tempath string, reg *Regex) (*File, error) {
|
||||||
|
user, err := UserDB.GetUserByID(reg.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !user.IsFileManager() {
|
||||||
|
return nil, ErrInvalidRole
|
||||||
|
}
|
||||||
|
if strings.Contains(tempath, "..") {
|
||||||
|
return nil, os.ErrNotExist
|
||||||
|
}
|
||||||
|
tempath = FileFolder + tempath
|
||||||
|
docf, err := os.Open(tempath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer docf.Close()
|
||||||
|
h := md5.New()
|
||||||
|
_, err = io.Copy(h, docf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var buf [md5.Size]byte
|
||||||
|
id := binary.LittleEndian.Uint64(h.Sum(buf[:0]))
|
||||||
|
_, err = docf.Seek(0, io.SeekStart)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stat, err := docf.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sz := stat.Size()
|
||||||
|
doc, err := docx.Parse(docf, sz)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
majorre, err := regexp.Compile(reg.Major)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
docs := doc.SplitByParagraph(docx.SplitDocxByPlainTextRegex(majorre))
|
||||||
|
if len(docs) < 2 {
|
||||||
|
return nil, ErrMajorSplitsTooShort
|
||||||
|
}
|
||||||
|
file := &File{
|
||||||
|
ID: id,
|
||||||
|
UID: *user.ID,
|
||||||
|
UpTime: time.Now().Unix(),
|
||||||
|
Size: sz,
|
||||||
|
}
|
||||||
|
titlere, err := regexp.Compile(reg.Title)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
classre, err := regexp.Compile(reg.Class)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
opclre, err := regexp.Compile(reg.OpenCl)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
datere, err := regexp.Compile(reg.Date)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
timere, err := regexp.Compile(reg.Time)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ratere, err := regexp.Compile(reg.Rate)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, it := range docs[0].Document.Body.Items {
|
||||||
|
if p, ok := it.(*docx.Paragraph); ok {
|
||||||
|
text := p.String()
|
||||||
|
title := titlere.FindStringSubmatch(text)
|
||||||
|
if len(title) >= 5 {
|
||||||
|
years, semesters, mfs, abs := title[1], title[2], title[3], title[4]
|
||||||
|
y, err := strconv.Atoi(years)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
file.Year = StudyYear(y)
|
||||||
|
if len(semesters) > 0 {
|
||||||
|
file.Type = file.Type.SetFirstSecond(semesters[0])
|
||||||
|
}
|
||||||
|
file.Type = file.Type.SetMiddleFinal(mfs)
|
||||||
|
if len(abs) > 0 {
|
||||||
|
file.Type = file.Type.SetAB(abs[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class := classre.FindStringSubmatch(text)
|
||||||
|
if len(class) >= 2 {
|
||||||
|
file.Class = class[1]
|
||||||
|
}
|
||||||
|
opcl := opclre.FindStringSubmatch(text)
|
||||||
|
if len(opcl) >= 2 {
|
||||||
|
file.Type = file.Type.SetOpenClose(opcl[1])
|
||||||
|
}
|
||||||
|
date := datere.FindStringSubmatch(text)
|
||||||
|
if len(date) >= 4 {
|
||||||
|
y, m, d := date[1], date[2], date[3]
|
||||||
|
if y != "" && m != "" && d != "" {
|
||||||
|
yyyy, err := strconv.ParseUint(y, 10, 64)
|
||||||
|
if err == nil && yyyy > 1600 {
|
||||||
|
mm, err := strconv.ParseUint(m, 10, 64)
|
||||||
|
if err == nil && mm >= 1 && mm <= 12 {
|
||||||
|
dd, err := strconv.ParseUint(d, 10, 64)
|
||||||
|
if err == nil && dd >= 1 && dd <= 31 {
|
||||||
|
file.Date = uint32(yyyy*10000 + mm*100 + dd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
times := timere.FindStringSubmatch(text)
|
||||||
|
if len(times) >= 2 {
|
||||||
|
min, err := strconv.Atoi(times[1])
|
||||||
|
if err == nil && min > 0 {
|
||||||
|
file.Time = time.Minute * time.Duration(min)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rate := ratere.FindStringSubmatch(text)
|
||||||
|
if len(rate) >= 2 {
|
||||||
|
file.Rate = rate[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
docs = docs[1:]
|
||||||
|
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
|
||||||
// QuestionJSON is the struct representation of File.Questions
|
// QuestionJSON is the struct representation of File.Questions
|
||||||
type QuestionJSON struct {
|
type QuestionJSON struct {
|
||||||
Name string `json:"name"` // Name is name or Question ID
|
Name string `json:"name"` // Name is name or Question ID
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
// Regex stores user's config of splitting docx file
|
// Regex stores user's config of splitting docx file
|
||||||
type Regex struct {
|
type Regex struct {
|
||||||
ID int // ID is User(ID)
|
ID int // ID is User(ID)
|
||||||
Title string // Title default `.*(\d{4})\s*-.*学年.*(\d).*([中末]).*([AB])\s*卷`
|
Title string // Title default `.*(\d{4})\s*-.*学年.*(\d?).*([中末]?).*([AB]?)\s*卷`
|
||||||
Class string // Class default `考试科目:\s*(\S+)\s*`
|
Class string // Class default `考试科目:\s*(\S+)\s*`
|
||||||
OpenCl string // OpenCl default `考试形式:\s*(\S+)\s*`
|
OpenCl string // OpenCl default `考试形式:\s*(\S+)\s*`
|
||||||
Date string // Date default `考试日期:\s*(\d+)\s*年\s*(\d+)\s*月\s*(\d+)\s*日`
|
Date string // Date default `考试日期:\s*(\d+)\s*年\s*(\d+)\s*月\s*(\d+)\s*日`
|
||||||
@@ -20,7 +20,7 @@ type Regex struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newRegex() (reg Regex) {
|
func newRegex() (reg Regex) {
|
||||||
reg.Title = `.*(\d{4})\s*-.*学年.*(\d).*([中末]).*([AB])\s*卷`
|
reg.Title = `.*(\d{4})\s*-.*学年.*(\d?).*([中末]?).*([AB]?)\s*卷`
|
||||||
reg.Class = `考试科目:\s*(\S+)\s*`
|
reg.Class = `考试科目:\s*(\S+)\s*`
|
||||||
reg.OpenCl = `考试形式:\s*(\S+)\s*`
|
reg.OpenCl = `考试形式:\s*(\S+)\s*`
|
||||||
reg.Date = `考试日期:\s*(\d+)\s*年\s*(\d+)\s*月\s*(\d+)\s*日`
|
reg.Date = `考试日期:\s*(\d+)\s*年\s*(\d+)\s*月\s*(\d+)\s*日`
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fumiama/paper-manager/backend/utils"
|
"github.com/fumiama/paper-manager/backend/utils"
|
||||||
@@ -23,6 +24,7 @@ var (
|
|||||||
ErrEmptyName = errors.New("empty name")
|
ErrEmptyName = errors.New("empty name")
|
||||||
ErrInvalidUsersCount = errors.New("invalid users count")
|
ErrInvalidUsersCount = errors.New("invalid users count")
|
||||||
ErrInvalidUserID = errors.New("invalid user ID")
|
ErrInvalidUserID = errors.New("invalid user ID")
|
||||||
|
ErrInvalidAvatar = errors.New("invalid avatar")
|
||||||
ErrEmptyUserID = errors.New("empty user ID")
|
ErrEmptyUserID = errors.New("empty user ID")
|
||||||
ErrEmptyContact = errors.New("empty contact")
|
ErrEmptyContact = errors.New("empty contact")
|
||||||
ErrUsernameExists = errors.New("username exists")
|
ErrUsernameExists = errors.New("username exists")
|
||||||
@@ -147,6 +149,9 @@ func (u *UserDatabase) UpdateUserInfo(id int, opname, nick, avtr, desc string) e
|
|||||||
user.Nick = nick
|
user.Nick = nick
|
||||||
}
|
}
|
||||||
if avtr != "" {
|
if avtr != "" {
|
||||||
|
if strings.Contains(avtr, "..") {
|
||||||
|
return ErrInvalidAvatar
|
||||||
|
}
|
||||||
user.Avtr = avtr
|
user.Avtr = avtr
|
||||||
}
|
}
|
||||||
if desc != "" {
|
if desc != "" {
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ func setUserInfo(id int, nick, desc, avtr *string) error {
|
|||||||
}
|
}
|
||||||
if a == "" {
|
if a == "" {
|
||||||
*avtr = user.Avtr
|
*avtr = user.Avtr
|
||||||
} else if utils.IsNotExist(global.DataFolder + a) {
|
} else if strings.Contains(a, "..") || utils.IsNotExist(global.DataFolder+a) {
|
||||||
return os.ErrNotExist
|
return os.ErrNotExist
|
||||||
}
|
}
|
||||||
if a == user.Avtr {
|
if a == user.Avtr {
|
||||||
|
|||||||
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/go-docx v0.0.0-20230310052825-daf7190ea69b
|
||||||
github.com/fumiama/imgsz v0.0.2
|
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/go-docx v0.0.0-20230310052825-daf7190ea69b h1:1KYtEitNxRbh+O8mgGlji4nQKzf7SQHYxiuqDAwRCc8=
|
||||||
|
github.com/fumiama/go-docx v0.0.0-20230310052825-daf7190ea69b/go.mod h1:ssRF0IaB1hCcKIObp3FkZOsjTcAHpgii70JelNb4H8M=
|
||||||
github.com/fumiama/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak=
|
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/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=
|
||||||
|
|||||||
Reference in New Issue
Block a user