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

split global.user

This commit is contained in:
源文雨
2023-03-22 22:38:52 +08:00
parent e0161613dd
commit 929c5ecfbb
5 changed files with 551 additions and 531 deletions

352
backend/global/message.go Normal file
View File

@@ -0,0 +1,352 @@
package global
import (
"strconv"
"time"
)
const (
MessageNormal MessageType = iota
MessageRegister
MessageUserAdded
MessageContactChange
MessagePasswordChange
MessageResetPassword
MessageOperator
)
type MessageType uint8
// 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
}
// Type decide message type by fields Name, Cont and Pswd.
func (m *Message) Type() MessageType {
switch {
case m.Name != "" && m.Cont != "" && m.Pswd != "":
return MessageRegister
case m.Name == "" && m.Cont != "" && m.Pswd == "":
return MessageUserAdded
case m.Name != "" && m.Cont != "" && m.Pswd == "":
return MessageContactChange
case m.Name != "" && m.Cont == "" && m.Pswd != "":
return MessagePasswordChange
case m.Name != "" && m.Cont == "" && m.Pswd == "":
return MessageResetPassword
case m.Name == "" && m.Cont != "" && m.Pswd != "":
return MessageOperator
default:
return MessageNormal
}
}
// SendMessage will send a normal message to id
func (u *UserDatabase) SendMessage(text, opname string, to int) error {
if !u.IsIDExists(to) {
return ErrInvalidUserID
}
m := Message{ToID: to, Date: time.Now().Unix(), Text: text, Cont: opname, Pswd: "opname"}
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(ip, name, cont, pswd string) error {
if name == "" {
return ErrEmptyName
}
if cont == "" {
return ErrEmptyContact
}
if pswd == "" {
return ErrEmptyPassword
}
for _, c := range name {
if !(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') {
return ErrInvalidName
}
}
if u.IsNameExists(name) {
return ErrInvalidName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: "收到来自 " + ip + ", 用户名 " + 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
}
// NotifyResetPassword will send notification to all supers
func (u *UserDatabase) NotifyResetPassword(ip, name, cont string) error {
if name == "" {
return ErrEmptyName
}
if cont == "" {
return ErrEmptyContact
}
for _, c := range name {
if !(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') {
return ErrInvalidName
}
}
user, err := u.GetUserByName(name)
if err != nil {
return err
}
if cont != user.Cont {
return ErrInvalidContact
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
err = u.SendMessage("发送重置密码请求", user.Name, *user.ID)
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: "收到来自 " + ip + ", 用户名 " + user.Name + " 的重置密码请求, 联系方式: " + user.Cont,
Name: user.Name,
}
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, nuid int) error {
if opname == "" || name == "" {
return ErrEmptyName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: opname + " 添加了用户 " + name,
Cont: opname,
}
u.mu.Lock()
defer u.mu.Unlock()
for _, to := range tos {
if nuid == to {
continue
}
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, id int) error {
if name == "" {
return ErrEmptyName
}
if cont == "" {
return ErrEmptyContact
}
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 {
if id == to {
continue
}
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, opname string, id int) error {
if name == "" {
return ErrEmptyName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: "用户 " + name + " 被 " + opname + " 更改了密码",
Name: name,
Pswd: npwd,
}
u.mu.Lock()
defer u.mu.Unlock()
for _, to := range tos {
if id == to {
continue
}
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) notifyUpdateUserRole(name, opname string, role UserRole, id int) error {
if name == "" || opname == "" {
return ErrEmptyName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: name + " 的权限被 " + opname + " 变更为 " + role.Nick(),
Cont: opname,
Pswd: "opname",
}
u.mu.Lock()
defer u.mu.Unlock()
for _, to := range tos {
if id == to {
continue
}
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) notifyDisableUser(name, opname string, id int) error {
if name == "" || opname == "" {
return ErrEmptyName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: name + " 的账户被 " + opname + " 禁用",
Cont: opname,
Pswd: "opname",
}
u.mu.Lock()
defer u.mu.Unlock()
for _, to := range tos {
if id == to {
continue
}
m.ToID = to
err = u.db.InsertUnique(UserTableMessage, &m)
if err != nil {
return err
}
}
return nil
}
// GetMessagesOfUser will change non-empty Pswd field to "-"
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)+" ORDER BY Date DESC", func() error {
if m.Pswd != "" {
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
}

81
backend/global/regex.go Normal file
View File

@@ -0,0 +1,81 @@
package global
import (
"reflect"
"regexp"
"strconv"
)
// 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*卷`
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*日`
Time string // Time default `考试时长:\s*(\d+)\s*分钟`
Rate string // Rate default `成绩构成比例:\s*(.*%)\s*`
Major string // Major default `([一二三四五六七八九十]+)、\s*(.*)\s*.*([空题]?)\s*(\d*).*共\s*(\d+)\s*分.*`
Sub string // Sub default `(\d+)、`
}
func newRegex() (reg Regex) {
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*日`
reg.Time = `考试时长:\s*(\d+)\s*分钟`
reg.Rate = `成绩构成比例:\s*(.*%)\s*`
reg.Major = `([一二三四五六七八九十]+)、\s*(.*)\s*.*([空题]?)\s*(\d*).*共\s*(\d+)\s*分.*`
reg.Sub = `(\d+)、`
return
}
// SetUserRegex set Regex.name = re
func (u *UserDatabase) SetUserRegex(id int, name, re string) error {
if name == "" || name == "ID" {
return ErrInvalidFieldName
}
if re == "" {
return ErrEmptyRegex
}
user, err := UserDB.GetUserByID(id)
if err != nil {
return err
}
if !user.IsFileManager() {
return ErrInvalidRole
}
_, err = regexp.Compile(re)
if err != nil {
return err
}
reg := newRegex()
rreg := reflect.ValueOf(&reg).Elem()
f := rreg.FieldByName(name)
if !f.IsValid() {
return ErrNoSuchFieldName
}
u.mu.Lock()
defer u.mu.Unlock()
_ = u.db.Find(UserTableRegex, &reg, "WHERE ID="+strconv.Itoa(id))
reg.ID = id
f.SetString(re)
return u.db.Insert(UserTableRegex, &reg)
}
// GetUserRegex default newRegex()
func (u *UserDatabase) GetUserRegex(id int) (*Regex, error) {
user, err := UserDB.GetUserByID(id)
if err != nil {
return nil, err
}
if !user.IsFileManager() {
return nil, ErrInvalidRole
}
reg := newRegex()
u.mu.RLock()
_ = u.db.Find(UserTableRegex, &reg, "WHERE ID="+strconv.Itoa(id))
u.mu.RUnlock()
return &reg, nil
}

62
backend/global/role.go Normal file
View File

@@ -0,0 +1,62 @@
package global
const (
RoleNil UserRole = iota
RoleSuper
RoleFileManager
RoleUser
RoleTop
)
type UserRole uint8
func (r UserRole) IsVaild() bool {
return r > RoleNil && r < RoleTop
}
func (r UserRole) String() string {
switch r {
case RoleSuper:
return "super"
case RoleFileManager:
return "filemgr"
case RoleUser:
return "user"
}
return "invalid"
}
func (r UserRole) Nick() string {
switch r {
case RoleSuper:
return "课程组长"
case RoleFileManager:
return "归档代理"
case RoleUser:
return "课程组员"
}
return "非法角色"
}
// UpdateUserRole ...
func (u *UserDatabase) UpdateUserRole(id int, nr UserRole, opname string) error {
if nr == RoleNil || nr > RoleUser {
return ErrInvalidRole
}
user, err := u.GetUserByID(id)
if err != nil {
return err
}
if opname == user.Name {
return ErrInvalidName
}
user.Role = nr
u.mu.Lock()
err = u.db.Insert(UserTableUser, &user)
u.mu.Unlock()
if err != nil {
return err
}
_ = u.SendMessage("您的权限被 "+opname+" 变更为 "+user.Role.Nick(), opname, *user.ID)
return u.notifyUpdateUserRole(user.Name, opname, nr, *user.ID)
}

View File

@@ -3,8 +3,6 @@ package global
import (
"errors"
"os"
"reflect"
"regexp"
"strconv"
"time"
@@ -12,56 +10,6 @@ import (
"github.com/sirupsen/logrus"
)
const (
RoleNil UserRole = iota
RoleSuper
RoleFileManager
RoleUser
RoleTop
)
type UserRole uint8
func (r UserRole) IsVaild() bool {
return r > RoleNil && r < RoleTop
}
func (r UserRole) String() string {
switch r {
case RoleSuper:
return "super"
case RoleFileManager:
return "filemgr"
case RoleUser:
return "user"
}
return "invalid"
}
func (r UserRole) Nick() string {
switch r {
case RoleSuper:
return "课程组长"
case RoleFileManager:
return "归档代理"
case RoleUser:
return "课程组员"
}
return "非法角色"
}
const (
MessageNormal MessageType = iota
MessageRegister
MessageUserAdded
MessageContactChange
MessagePasswordChange
MessageResetPassword
MessageOperator
)
type MessageType uint8
const (
UserTableUser = "user"
UserTableMessage = "msg"
@@ -216,29 +164,6 @@ func (u *UserDatabase) UpdateUserInfo(id int, opname, nick, avtr, desc string) e
return u.SendMessage("更新了个人信息", opname, *user.ID)
}
// UpdateUserRole ...
func (u *UserDatabase) UpdateUserRole(id int, nr UserRole, opname string) error {
if nr == RoleNil || nr > RoleUser {
return ErrInvalidRole
}
user, err := u.GetUserByID(id)
if err != nil {
return err
}
if opname == user.Name {
return ErrInvalidName
}
user.Role = nr
u.mu.Lock()
err = u.db.Insert(UserTableUser, &user)
u.mu.Unlock()
if err != nil {
return err
}
_ = u.SendMessage("您的权限被 "+opname+" 变更为 "+user.Role.Nick(), opname, *user.ID)
return u.notifyUpdateUserRole(user.Name, opname, nr, *user.ID)
}
// DisableUser ...
func (u *UserDatabase) DisableUser(id int, opname string) error {
user, err := u.GetUserByID(id)
@@ -414,459 +339,3 @@ func (user *User) IsFileManager() bool {
func (user *User) IsSuper() bool {
return user.Role == RoleSuper
}
// 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
}
// Type decide message type by fields Name, Cont and Pswd.
func (m *Message) Type() MessageType {
switch {
case m.Name != "" && m.Cont != "" && m.Pswd != "":
return MessageRegister
case m.Name == "" && m.Cont != "" && m.Pswd == "":
return MessageUserAdded
case m.Name != "" && m.Cont != "" && m.Pswd == "":
return MessageContactChange
case m.Name != "" && m.Cont == "" && m.Pswd != "":
return MessagePasswordChange
case m.Name != "" && m.Cont == "" && m.Pswd == "":
return MessageResetPassword
case m.Name == "" && m.Cont != "" && m.Pswd != "":
return MessageOperator
default:
return MessageNormal
}
}
// SendMessage will send a normal message to id
func (u *UserDatabase) SendMessage(text, opname string, to int) error {
if !u.IsIDExists(to) {
return ErrInvalidUserID
}
m := Message{ToID: to, Date: time.Now().Unix(), Text: text, Cont: opname, Pswd: "opname"}
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(ip, name, cont, pswd string) error {
if name == "" {
return ErrEmptyName
}
if cont == "" {
return ErrEmptyContact
}
if pswd == "" {
return ErrEmptyPassword
}
for _, c := range name {
if !(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') {
return ErrInvalidName
}
}
if u.IsNameExists(name) {
return ErrInvalidName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: "收到来自 " + ip + ", 用户名 " + 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
}
// NotifyResetPassword will send notification to all supers
func (u *UserDatabase) NotifyResetPassword(ip, name, cont string) error {
if name == "" {
return ErrEmptyName
}
if cont == "" {
return ErrEmptyContact
}
for _, c := range name {
if !(c >= '0' && c <= '9') && !(c >= 'A' && c <= 'Z') && !(c >= 'a' && c <= 'z') {
return ErrInvalidName
}
}
user, err := u.GetUserByName(name)
if err != nil {
return err
}
if cont != user.Cont {
return ErrInvalidContact
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
err = u.SendMessage("发送重置密码请求", user.Name, *user.ID)
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: "收到来自 " + ip + ", 用户名 " + user.Name + " 的重置密码请求, 联系方式: " + user.Cont,
Name: user.Name,
}
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, nuid int) error {
if opname == "" || name == "" {
return ErrEmptyName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: opname + " 添加了用户 " + name,
Cont: opname,
}
u.mu.Lock()
defer u.mu.Unlock()
for _, to := range tos {
if nuid == to {
continue
}
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, id int) error {
if name == "" {
return ErrEmptyName
}
if cont == "" {
return ErrEmptyContact
}
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 {
if id == to {
continue
}
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, opname string, id int) error {
if name == "" {
return ErrEmptyName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: "用户 " + name + " 被 " + opname + " 更改了密码",
Name: name,
Pswd: npwd,
}
u.mu.Lock()
defer u.mu.Unlock()
for _, to := range tos {
if id == to {
continue
}
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) notifyUpdateUserRole(name, opname string, role UserRole, id int) error {
if name == "" || opname == "" {
return ErrEmptyName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: name + " 的权限被 " + opname + " 变更为 " + role.Nick(),
Cont: opname,
Pswd: "opname",
}
u.mu.Lock()
defer u.mu.Unlock()
for _, to := range tos {
if id == to {
continue
}
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) notifyDisableUser(name, opname string, id int) error {
if name == "" || opname == "" {
return ErrEmptyName
}
tos, err := u.GetSuperIDs()
if err != nil {
return err
}
m := Message{
Date: time.Now().Unix(),
Text: name + " 的账户被 " + opname + " 禁用",
Cont: opname,
Pswd: "opname",
}
u.mu.Lock()
defer u.mu.Unlock()
for _, to := range tos {
if id == to {
continue
}
m.ToID = to
err = u.db.InsertUnique(UserTableMessage, &m)
if err != nil {
return err
}
}
return nil
}
// GetMessagesOfUser will change non-empty Pswd field to "-"
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)+" ORDER BY Date DESC", func() error {
if m.Pswd != "" {
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
}
// MonthlyAPIVisit counts the api visit history
type MonthlyAPIVisit struct {
YM uint32 // YM is yyyymm
Count uint32 // visit count this mounth
}
// VisitAPI increases count of this mounth by 1
func (u *UserDatabase) VisitAPI() {
now := time.Now()
ym := uint32(now.Year())*100 + uint32(now.Month())
var v MonthlyAPIVisit
u.mu.Lock()
defer u.mu.Unlock()
_ = u.db.Find(UserTableMonthlyAPIVisit, &v, "WHERE YM="+strconv.FormatUint(uint64(ym), 10))
v.YM = ym
v.Count++
err := u.db.Insert(UserTableMonthlyAPIVisit, &v)
if err != nil {
logrus.Warnln("[global.user] insert visit error:", err)
}
}
// GetAnnualAPIVisitCount get the latest 12 mounths' count
func (u *UserDatabase) GetAnnualAPIVisitCount() (cnts [12]uint32) {
var v MonthlyAPIVisit
var yms [12]uint32
now := time.Now()
y100 := uint32(now.Year()) * 100
py100 := uint32(now.Year()-1) * 100
nm := int(now.Month())
for i := 0; i < nm; i++ {
yms[i] = y100 + uint32(i+1)
}
for i := nm; i < 12; i++ {
yms[i] = py100 + uint32(i+1)
}
u.mu.RLock()
defer u.mu.RUnlock()
i := 0
for _, ym := range yms {
_ = u.db.Find(UserTableMonthlyAPIVisit, &v, "WHERE YM="+strconv.FormatUint(uint64(ym), 10))
cnts[i] = v.Count
i++
v.Count = 0
}
return
}
// 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*卷`
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*日`
Time string // Time default `考试时长:\s*(\d+)\s*分钟`
Rate string // Rate default `成绩构成比例:\s*(.*%)\s*`
Major string // Major default `([一二三四五六七八九十]+)、\s*(.*)\s*.*([空题]?)\s*(\d*).*共\s*(\d+)\s*分.*`
Sub string // Sub default `(\d+)、`
}
func newRegex() (reg Regex) {
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*日`
reg.Time = `考试时长:\s*(\d+)\s*分钟`
reg.Rate = `成绩构成比例:\s*(.*%)\s*`
reg.Major = `([一二三四五六七八九十]+)、\s*(.*)\s*.*([空题]?)\s*(\d*).*共\s*(\d+)\s*分.*`
reg.Sub = `(\d+)、`
return
}
// SetUserRegex set Regex.name = re
func (u *UserDatabase) SetUserRegex(id int, name, re string) error {
if name == "" || name == "ID" {
return ErrInvalidFieldName
}
if re == "" {
return ErrEmptyRegex
}
user, err := UserDB.GetUserByID(id)
if err != nil {
return err
}
if !user.IsFileManager() {
return ErrInvalidRole
}
_, err = regexp.Compile(re)
if err != nil {
return err
}
reg := newRegex()
rreg := reflect.ValueOf(&reg).Elem()
f := rreg.FieldByName(name)
if !f.IsValid() {
return ErrNoSuchFieldName
}
u.mu.Lock()
defer u.mu.Unlock()
_ = u.db.Find(UserTableRegex, &reg, "WHERE ID="+strconv.Itoa(id))
reg.ID = id
f.SetString(re)
return u.db.Insert(UserTableRegex, &reg)
}
// GetUserRegex default newRegex()
func (u *UserDatabase) GetUserRegex(id int) (*Regex, error) {
user, err := UserDB.GetUserByID(id)
if err != nil {
return nil, err
}
if !user.IsFileManager() {
return nil, ErrInvalidRole
}
reg := newRegex()
u.mu.RLock()
_ = u.db.Find(UserTableRegex, &reg, "WHERE ID="+strconv.Itoa(id))
u.mu.RUnlock()
return &reg, nil
}

56
backend/global/visit.go Normal file
View File

@@ -0,0 +1,56 @@
package global
import (
"strconv"
"time"
"github.com/sirupsen/logrus"
)
// MonthlyAPIVisit counts the api visit history
type MonthlyAPIVisit struct {
YM uint32 // YM is yyyymm
Count uint32 // visit count this mounth
}
// VisitAPI increases count of this mounth by 1
func (u *UserDatabase) VisitAPI() {
now := time.Now()
ym := uint32(now.Year())*100 + uint32(now.Month())
var v MonthlyAPIVisit
u.mu.Lock()
defer u.mu.Unlock()
_ = u.db.Find(UserTableMonthlyAPIVisit, &v, "WHERE YM="+strconv.FormatUint(uint64(ym), 10))
v.YM = ym
v.Count++
err := u.db.Insert(UserTableMonthlyAPIVisit, &v)
if err != nil {
logrus.Warnln("[global.user] insert visit error:", err)
}
}
// GetAnnualAPIVisitCount get the latest 12 mounths' count
func (u *UserDatabase) GetAnnualAPIVisitCount() (cnts [12]uint32) {
var v MonthlyAPIVisit
var yms [12]uint32
now := time.Now()
y100 := uint32(now.Year()) * 100
py100 := uint32(now.Year()-1) * 100
nm := int(now.Month())
for i := 0; i < nm; i++ {
yms[i] = y100 + uint32(i+1)
}
for i := nm; i < 12; i++ {
yms[i] = py100 + uint32(i+1)
}
u.mu.RLock()
defer u.mu.RUnlock()
i := 0
for _, ym := range yms {
_ = u.db.Find(UserTableMonthlyAPIVisit, &v, "WHERE YM="+strconv.FormatUint(uint64(ym), 10))
cnts[i] = v.Count
i++
v.Count = 0
}
return
}