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

implement file.AddFile

This commit is contained in:
源文雨
2023-03-22 23:31:34 +08:00
parent 929c5ecfbb
commit 05e59426cd
6 changed files with 161 additions and 3 deletions

View File

@@ -1,9 +1,17 @@
package global
import (
"crypto/md5"
"encoding/binary"
"errors"
"io"
"os"
"regexp"
"strconv"
"strings"
"time"
"github.com/fumiama/go-docx"
)
const (
@@ -11,6 +19,10 @@ const (
FileTableQuestion = "question"
)
var (
ErrMajorSplitsTooShort = errors.New("major splits too short")
)
// PaperType [4 开 一页纸 闭] [4 上下] [4 中末] [4 AB]
type PaperType uint16
@@ -161,6 +173,144 @@ type File struct {
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
type QuestionJSON struct {
Name string `json:"name"` // Name is name or Question ID

View File

@@ -9,7 +9,7 @@ import (
// Regex stores user's config of splitting docx file
type Regex struct {
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*`
OpenCl string // OpenCl default `考试形式:\s*(\S+)\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) {
reg.Title = `.*(\d{4})\s*-.*学年.*(\d).*([中末]).*([AB])\s*卷`
reg.Title = `.*(\d{4})\s*-.*学年.*(\d?).*([中末]?).*([AB]?)\s*卷`
reg.Class = `考试科目:\s*(\S+)\s*`
reg.OpenCl = `考试形式:\s*(\S+)\s*`
reg.Date = `考试日期:\s*(\d+)\s*年\s*(\d+)\s*月\s*(\d+)\s*日`

View File

@@ -4,6 +4,7 @@ import (
"errors"
"os"
"strconv"
"strings"
"time"
"github.com/fumiama/paper-manager/backend/utils"
@@ -23,6 +24,7 @@ var (
ErrEmptyName = errors.New("empty name")
ErrInvalidUsersCount = errors.New("invalid users count")
ErrInvalidUserID = errors.New("invalid user ID")
ErrInvalidAvatar = errors.New("invalid avatar")
ErrEmptyUserID = errors.New("empty user ID")
ErrEmptyContact = errors.New("empty contact")
ErrUsernameExists = errors.New("username exists")
@@ -147,6 +149,9 @@ func (u *UserDatabase) UpdateUserInfo(id int, opname, nick, avtr, desc string) e
user.Nick = nick
}
if avtr != "" {
if strings.Contains(avtr, "..") {
return ErrInvalidAvatar
}
user.Avtr = avtr
}
if desc != "" {

View File

@@ -179,7 +179,7 @@ func setUserInfo(id int, nick, desc, avtr *string) error {
}
if a == "" {
*avtr = user.Avtr
} else if utils.IsNotExist(global.DataFolder + a) {
} else if strings.Contains(a, "..") || utils.IsNotExist(global.DataFolder+a) {
return os.ErrNotExist
}
if a == user.Avtr {

1
go.mod
View File

@@ -7,6 +7,7 @@ require (
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/fumiama/go-docx v0.0.0-20230310052825-daf7190ea69b
github.com/fumiama/imgsz v0.0.2
github.com/sirupsen/logrus v1.9.0
)

2
go.sum
View File

@@ -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/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-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/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4=
github.com/fumiama/sqlite3 v1.20.0-with-win386 h1:ZR1AXGBEtkfq9GAXehOVcwn+aaCG8itrkgEsz4ggx5k=