diff --git a/backend/global/message.go b/backend/global/message.go new file mode 100644 index 0000000..c67d2d4 --- /dev/null +++ b/backend/global/message.go @@ -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 +} diff --git a/backend/global/regex.go b/backend/global/regex.go new file mode 100644 index 0000000..5b2f5b5 --- /dev/null +++ b/backend/global/regex.go @@ -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(®).Elem() + f := rreg.FieldByName(name) + if !f.IsValid() { + return ErrNoSuchFieldName + } + u.mu.Lock() + defer u.mu.Unlock() + _ = u.db.Find(UserTableRegex, ®, "WHERE ID="+strconv.Itoa(id)) + reg.ID = id + f.SetString(re) + return u.db.Insert(UserTableRegex, ®) +} + +// 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, ®, "WHERE ID="+strconv.Itoa(id)) + u.mu.RUnlock() + return ®, nil +} diff --git a/backend/global/role.go b/backend/global/role.go new file mode 100644 index 0000000..2a47908 --- /dev/null +++ b/backend/global/role.go @@ -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) +} diff --git a/backend/global/user.go b/backend/global/user.go index 3e94ddf..6d6b44b 100644 --- a/backend/global/user.go +++ b/backend/global/user.go @@ -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(®).Elem() - f := rreg.FieldByName(name) - if !f.IsValid() { - return ErrNoSuchFieldName - } - u.mu.Lock() - defer u.mu.Unlock() - _ = u.db.Find(UserTableRegex, ®, "WHERE ID="+strconv.Itoa(id)) - reg.ID = id - f.SetString(re) - return u.db.Insert(UserTableRegex, ®) -} - -// 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, ®, "WHERE ID="+strconv.Itoa(id)) - u.mu.RUnlock() - return ®, nil -} diff --git a/backend/global/visit.go b/backend/global/visit.go new file mode 100644 index 0000000..2e7ec9f --- /dev/null +++ b/backend/global/visit.go @@ -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 +}