282 lines
7.7 KiB
Go
282 lines
7.7 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"regexp"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/cdle/sillyplus/utils"
|
|
"github.com/dop251/goja"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/goccy/go-json"
|
|
)
|
|
|
|
type Reply struct {
|
|
Index int `json:"index,omitempty"` // 排序
|
|
ID int `json:"id"` // ID,主键
|
|
Nickname string `json:"nickname"` // 类型 0全部 1用户 2群聊
|
|
Number string `json:"number"` // 号码 明确用户和群聊
|
|
Priority int `json:"priority"` // 决定 replies 排序,优先级越高排的越靠前
|
|
Keyword string `json:"keyword"` // 关键词,模糊查询
|
|
Value string `json:"value"` // 值,模糊查询
|
|
CreatedAt int `json:"created_at"` // 创建时间
|
|
Platforms []string `json:"platforms"` // 平台
|
|
}
|
|
|
|
var replies []Reply //一切增删查改只需作用到这个变量
|
|
var repliesLock sync.RWMutex
|
|
|
|
func init() {
|
|
REPLY.Foreach(func(b1, b2 []byte) error {
|
|
repliesLock.Lock()
|
|
defer repliesLock.Unlock()
|
|
rp := Reply{}
|
|
err := json.Unmarshal(b2, &rp)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
replies = append(replies, rp)
|
|
sort.Slice(replies, func(i, j int) bool {
|
|
return replies[i].Priority > replies[j].Priority
|
|
})
|
|
return nil
|
|
})
|
|
GinApi(GET, "/api/reply/list", RequireAuth, func(ctx *gin.Context) {
|
|
repliesLock.RLock()
|
|
defer repliesLock.RUnlock()
|
|
page, _ := strconv.Atoi(ctx.DefaultQuery("current", "1"))
|
|
perPage, _ := strconv.Atoi(ctx.DefaultQuery("pageSize", "20"))
|
|
keyword := ctx.Query("keyword")
|
|
value := ctx.Query("value")
|
|
// class_ := ctx.Query("class")
|
|
// class := utils.Int(class_)
|
|
number := ctx.Query("number")
|
|
// filter replies based on the query parameters
|
|
filteredReplies := make([]Reply, 0, len(replies))
|
|
for _, reply := range replies {
|
|
if keyword != "" && !strings.Contains(reply.Keyword, keyword) {
|
|
continue
|
|
}
|
|
if value != "" && !strings.Contains(reply.Value, value) {
|
|
continue
|
|
}
|
|
// if class_ != "" && reply.Class != class {
|
|
// continue
|
|
// }
|
|
if number != "" && reply.Number != number {
|
|
continue
|
|
}
|
|
filteredReplies = append(filteredReplies, reply)
|
|
}
|
|
sort.Slice(filteredReplies, func(i, j int) bool {
|
|
return filteredReplies[i].CreatedAt > filteredReplies[j].CreatedAt
|
|
})
|
|
// paginate the filtered replies
|
|
start := (page - 1) * perPage
|
|
end := start + perPage
|
|
if end > len(filteredReplies) {
|
|
end = len(filteredReplies)
|
|
}
|
|
paginatedReplies := filteredReplies[start:end]
|
|
index := start + 1
|
|
for i := range paginatedReplies {
|
|
filteredReplies[i].Index = index
|
|
index++
|
|
if filteredReplies[i].Nickname == "" || len(filteredReplies[i].Platforms) == 0 {
|
|
nk := Nickname{ID: filteredReplies[i].Number}
|
|
nickname.First(&nk)
|
|
if nk.Value != "" && filteredReplies[i].Nickname == "" {
|
|
filteredReplies[i].Nickname = nk.Value
|
|
}
|
|
if nk.Platform != "" && len(filteredReplies[i].Platforms) == 0 {
|
|
filteredReplies[i].Platforms = []string{nk.Platform}
|
|
}
|
|
}
|
|
}
|
|
ctx.JSON(200, map[string]interface{}{
|
|
"success": true,
|
|
"data": paginatedReplies,
|
|
"page": page,
|
|
"total": len(filteredReplies),
|
|
"platforms": getPltsLabel(),
|
|
})
|
|
})
|
|
|
|
GinApi(POST, "/api/reply", RequireAuth, func(ctx *gin.Context) {
|
|
repliesLock.Lock()
|
|
defer repliesLock.Unlock()
|
|
var reply Reply
|
|
data, _ := ioutil.ReadAll(ctx.Request.Body)
|
|
var v = map[string]interface{}{}
|
|
if err := json.Unmarshal(data, &reply); err != nil {
|
|
ctx.JSON(200, map[string]interface{}{
|
|
"success": false,
|
|
"errorMessage": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
json.Unmarshal(data, &v)
|
|
has := func(str string) bool {
|
|
_, ok := v[str]
|
|
return ok
|
|
}
|
|
if reply.ID < 0 {
|
|
reply.ID = 0
|
|
}
|
|
// find existing reply with the same ID
|
|
var existingReply *Reply
|
|
for i, r := range replies {
|
|
if r.ID == reply.ID {
|
|
existingReply = &replies[i]
|
|
break
|
|
}
|
|
}
|
|
if existingReply != nil {
|
|
// update existing reply
|
|
if has("nickname") {
|
|
existingReply.Nickname = reply.Nickname
|
|
}
|
|
if has("number") {
|
|
existingReply.Number = reply.Number
|
|
}
|
|
if has("keyword") {
|
|
existingReply.Keyword = reply.Keyword
|
|
}
|
|
if has("value") {
|
|
existingReply.Value = reply.Value
|
|
}
|
|
if has("priority") {
|
|
existingReply.Priority = reply.Priority
|
|
}
|
|
if has("platforms") {
|
|
existingReply.Platforms = reply.Platforms
|
|
}
|
|
reply = *existingReply
|
|
err := REPLY.Create(&reply)
|
|
if err != nil {
|
|
ctx.JSON(200, map[string]interface{}{
|
|
"success": false,
|
|
"errorMessage": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
} else {
|
|
reply.CreatedAt = int(time.Now().Unix())
|
|
err := REPLY.Create(&reply)
|
|
if err != nil {
|
|
ctx.JSON(200, map[string]interface{}{
|
|
"success": false,
|
|
"errorMessage": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
replies = append(replies, reply)
|
|
}
|
|
sort.Slice(replies, func(i, j int) bool {
|
|
return replies[i].Priority > replies[j].Priority
|
|
})
|
|
ctx.JSON(200, map[string]interface{}{
|
|
"success": true,
|
|
})
|
|
})
|
|
//删除功能
|
|
GinApi(DELETE, "/api/reply", RequireAuth, func(ctx *gin.Context) {
|
|
repliesLock.Lock()
|
|
defer repliesLock.Unlock()
|
|
id := utils.Int(ctx.Query("id"))
|
|
for i, r := range replies {
|
|
if r.ID == id {
|
|
REPLY.Set(r.ID, nil)
|
|
replies = append(replies[:i], replies[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
ctx.JSON(200, map[string]interface{}{
|
|
"success": true,
|
|
})
|
|
})
|
|
}
|
|
|
|
var REPLY = MakeBucket("reply")
|
|
|
|
// // 能处理字符:你好,我是${ user.name }
|
|
// func parseReply(str string) string {
|
|
// re := regexp.MustCompile(`\$\{\s*([^\s{}]+)\s*\}`)
|
|
// return re.ReplaceAllStringFunc(str, func(match string) string {
|
|
// bk := match[2 : len(match)-1]
|
|
// b_k := strings.Split(bk, ".")
|
|
// if len(b_k) != 3 {
|
|
// return fmt.Sprintf("${%s}", bk)
|
|
// }
|
|
// return MakeBucket(b_k[1]).GetString(b_k[2])
|
|
// })
|
|
// }
|
|
|
|
// 能处理字符:你好,我是${ user.name ?? 6 }
|
|
func parseReply2(str string) string {
|
|
re := regexp.MustCompile(`\$\{\s*([^{}]+)\s*\}`)
|
|
return re.ReplaceAllStringFunc(str, func(match string) string {
|
|
script := match[2 : len(match)-1]
|
|
script = regexp.MustCompile(`(\w+)\.(\w+)`).ReplaceAllStringFunc(script, func(match string) string {
|
|
parts := strings.Split(match, ".")
|
|
return fmt.Sprintf(`Bucket("%s")["%s"]`, parts[0], parts[1])
|
|
})
|
|
vm := goja.New()
|
|
vm.Set("Bucket", func(name string) interface{} {
|
|
return JsBucket(vm, name, "", false)
|
|
})
|
|
v, err := vm.RunString(script)
|
|
if err == nil {
|
|
return v.String()
|
|
}
|
|
return match
|
|
// b_k := strings.Split(bk, ".")
|
|
// if len(b_k) != 3 {
|
|
// return fmt.Sprintf("${%s}", bk)
|
|
// }
|
|
// return MakeBucket(b_k[1]).GetString(b_k[2])
|
|
// return ""
|
|
})
|
|
}
|
|
|
|
// rule 专用
|
|
func parseReply3(str string, f func(string, string)) string {
|
|
ks := map[string]bool{}
|
|
re := regexp.MustCompile(`\$\{\s*([^{}]+)\s*\}`)
|
|
return re.ReplaceAllStringFunc(str, func(match string) string {
|
|
script := match[2 : len(match)-1]
|
|
script = regexp.MustCompile(`(\w+)\.(\w+)`).ReplaceAllStringFunc(script, func(match string) string {
|
|
parts := strings.Split(match, ".")
|
|
k := fmt.Sprintf(`%s.%s`, parts[0], parts[1])
|
|
if _, ok := ks[k]; !ok {
|
|
ks[k] = true
|
|
f(parts[0], parts[1])
|
|
}
|
|
return fmt.Sprintf(`Bucket("%s")["%s"]`, parts[0], parts[1])
|
|
})
|
|
vm := goja.New()
|
|
// vm.Set("Bucket", func(name string) interface{} {
|
|
// return JsBucket(vm, name, "", false)
|
|
// })
|
|
vm.Set("Bucket", func(name string) interface{} {
|
|
return JsBucket2(vm, name, "", false)
|
|
})
|
|
v, err := vm.RunString(script)
|
|
if err == nil {
|
|
return v.String()
|
|
}
|
|
return match
|
|
// b_k := strings.Split(bk, ".")
|
|
// if len(b_k) != 3 {
|
|
// return fmt.Sprintf("${%s}", bk)
|
|
// }
|
|
// return MakeBucket(b_k[1]).GetString(b_k[2])
|
|
// return ""
|
|
})
|
|
}
|