diff --git a/config.default.yml b/config.default.yml index 94f24d4..e5e8f5a 100644 --- a/config.default.yml +++ b/config.default.yml @@ -1,5 +1,6 @@ port: 10230 url: '' +self_key: '' image_root: '/images' line: secret: '' diff --git a/model/line_message_log.go b/model/line_message_log.go index 2fabaa6..857f3b2 100644 --- a/model/line_message_log.go +++ b/model/line_message_log.go @@ -1,6 +1,9 @@ package model -import "time" +import ( + "fmt" + "time" +) // LineMessageLog - type LineMessageLog struct { @@ -12,6 +15,13 @@ type LineMessageLog struct { Mtime time.Time `db:"mtime" cc:"mtime"` } +// LineMessageLogWithUG - +type LineMessageLogWithUG struct { + LineMessageLog + GroupName string `db:"group_name" cc:"group_name"` + UserName string `db:"user_name" cc:"user_name"` +} + // AddLineMessageLog - func AddLineMessageLog(g, u, msg string) (msglog *LineMessageLog, err error) { query := `insert into "public"."line_message_log" ("group", "user", "message") values ($1, $2, $3)` @@ -19,3 +29,46 @@ func AddLineMessageLog(g, u, msg string) (msglog *LineMessageLog, err error) { err = x.Get(msglog, query, g, u, msg) return } + +// GetLineMessageLogCount - +func GetLineMessageLogCount() (c int, err error) { + err = x.Get(&c, `select count(*) as c from "public"."line_message_log"`) + return +} + +// GetLineMessageLogList - +func GetLineMessageLogList(g, u string, offset, limit int) (logs []*LineMessageLogWithUG, err error) { + params := struct { + Group string `db:"group"` + User string `db:"user"` + }{} + query := `select m.*, g.name as group_name, u.name as user_name from "public"."line_message_log" m + left join "public"."line_user" u + on u.id = m.user + left join "public"."line_group" g + on g.id = m.group + ` + where := "" + if len(g) > 0 { + where = ` where g.id = :group` + params.Group = g + } + if len(u) > 0 { + if len(where) > 0 { + where += ` and u.id = :user` + } else { + where += ` where u.id = :user` + } + params.User = u + } + order := `order by m.ctime desc` + pager := fmt.Sprintf("offset %d limit %d", offset, limit) + + stmt, err := x.PrepareNamed(fmt.Sprintf("%s %s %s %s", query, where, order, pager)) + if err != nil { + return nil, err + } + + err = stmt.Select(&logs, params) + return +} diff --git a/module/config/config.go b/module/config/config.go index f609ff5..8bdcbee 100644 --- a/module/config/config.go +++ b/module/config/config.go @@ -14,6 +14,7 @@ import ( type Config struct { Port int `yaml:"port"` URL string `yaml:"url"` + SelfKey string `yaml:"self_key"` ImageRoot string `yaml:"image_root"` Line struct { Secret string `yaml:"secret"` diff --git a/module/context/context.go b/module/context/context.go index 6c304c3..f83c611 100644 --- a/module/context/context.go +++ b/module/context/context.go @@ -53,6 +53,12 @@ func (c *Context) DataFormat(msg interface{}) { c.AbortWithStatusJSON(obj.Status, obj.Obj) } +// Forbidden - +func (c *Context) Forbidden(msg interface{}) { + obj := apimsg.GetRes("Forbidden", msg) + c.AbortWithStatusJSON(obj.Status, obj.Obj) +} + // Success - func (c *Context) Success(msg interface{}) { obj := apimsg.GetRes("Success", msg) diff --git a/module/twitch-irc/twitch-irc.go b/module/twitch-irc/twitch-irc.go index b3f83c6..181a8df 100644 --- a/module/twitch-irc/twitch-irc.go +++ b/module/twitch-irc/twitch-irc.go @@ -86,10 +86,6 @@ func JoinChannel(ch string) { return } - if indexOf(channels, ch) != -1 { - return - } - m := &MsgObj{ Command: "JOIN", Params: []string{ diff --git a/module/utils/utils.go b/module/utils/utils.go index cdd7762..937282e 100644 --- a/module/utils/utils.go +++ b/module/utils/utils.go @@ -1,6 +1,7 @@ package utils import ( + "math" "os" "path" "reflect" @@ -9,6 +10,48 @@ import ( "strings" ) +// PageObject - +type PageObject struct { + Page int `json:"page" cc:"page"` + Total int `json:"total" cc:"total"` + Offset int `json:"offset" cc:"offset"` + Limit int `json:"limit" cc:"limit"` +} + +// CalcPage - +func CalcPage(count, page, max int) (po PageObject) { + if count < 0 { + count = 0 + } + if page < 1 { + page = 1 + } + if max < 1 { + max = 1 + } + + total := int(math.Ceil(float64(count) / float64(max))) + if total < 1 { + total = 1 + } + if page > total { + page = total + } + offset := (page - 1) * max + if offset > count { + offset = count + } + limit := max + + po = PageObject{} + po.Limit = limit + po.Page = page + po.Offset = offset + po.Total = total + + return +} + // ToMap struct to map[string]interface{} func ToMap(ss interface{}) map[string]interface{} { t := reflect.ValueOf(ss) diff --git a/router/api/api.go b/router/api/api.go index d38433c..605f228 100644 --- a/router/api/api.go +++ b/router/api/api.go @@ -1,9 +1,12 @@ package api import ( + "strconv" + "git.trj.tw/golang/mtfosbot/model" "git.trj.tw/golang/mtfosbot/module/apis/twitch" "git.trj.tw/golang/mtfosbot/module/context" + "git.trj.tw/golang/mtfosbot/module/utils" "github.com/gin-gonic/contrib/sessions" "golang.org/x/crypto/bcrypt" ) @@ -100,3 +103,49 @@ func GetSessionData(c *context.Context) { } c.Success(user) } + +// GetLineMessageLog - +func GetLineMessageLog(c *context.Context) { + numP := 1 + if p, ok := c.GetQuery("p"); ok { + if i, err := strconv.Atoi(p); err == nil { + numP = i + } + } + numMax := 20 + if max, ok := c.GetQuery("max"); ok { + if m, err := strconv.Atoi(max); err == nil { + numMax = m + } + } + + g := c.DefaultQuery("group", "") + u := c.DefaultQuery("user", "") + + count, err := model.GetLineMessageLogCount() + if err != nil { + c.ServerError(nil) + return + } + + page := utils.CalcPage(count, numP, numMax) + + logs, err := model.GetLineMessageLogList(g, u, page.Offset, page.Limit) + if err != nil { + c.ServerError(nil) + return + } + + resMap := make([]map[string]interface{}, 0) + + for _, v := range logs { + m := utils.ToMap(v.LineMessageLog) + m["group_name"] = v.GroupName + m["user_name"] = v.UserName + resMap = append(resMap, m) + } + + c.Success(map[string]interface{}{ + "list": resMap, + }) +} diff --git a/router/private/private.go b/router/private/private.go new file mode 100644 index 0000000..3ddd349 --- /dev/null +++ b/router/private/private.go @@ -0,0 +1,108 @@ +package private + +import ( + "fmt" + "strings" + + "git.trj.tw/golang/mtfosbot/model" + "git.trj.tw/golang/mtfosbot/module/apis/line" + "git.trj.tw/golang/mtfosbot/module/config" + "git.trj.tw/golang/mtfosbot/module/context" +) + +// VerifyKey - +func VerifyKey(c *context.Context) { + conf := config.GetConf() + key := c.GetHeader("X-Mtfos-Key") + + if len(key) == 0 { + c.Forbidden(nil) + return + } + + if key != conf.SelfKey { + c.Forbidden(nil) + return + } + + c.Next() +} + +// GetFacebookPageIDs - +func GetFacebookPageIDs(c *context.Context) { + pages, err := model.GetAllFacebookPage() + if err != nil { + c.ServerError(nil) + return + } + + ids := make([]string, 0) + for _, v := range pages { + ids = append(ids, v.ID) + } + + c.Success(map[string]interface{}{ + "list": ids, + }) +} + +// UpdateFacebookPagePost - +func UpdateFacebookPagePost(c *context.Context) { + var err error + type pageStruct struct { + ID string `json:"id"` + PostID string `json:"post_id"` + Link string `json:"link"` + Text string `json:"text"` + } + bodyArg := struct { + Pages []pageStruct `json:"pages"` + }{} + + err = c.BindData(&bodyArg) + if err != nil { + c.DataFormat(nil) + return + } + + for _, v := range bodyArg.Pages { + if len(v.ID) == 0 || len(v.PostID) == 0 || len(v.Link) == 0 { + continue + } + + page, err := model.GetFacebookPage(v.ID) + if err != nil { + continue + } + if page.LastPost == v.PostID { + continue + } + err = page.UpdatePost(v.PostID) + if err != nil { + continue + } + + err = page.GetGroups() + if err != nil { + continue + } + + for _, g := range page.Groups { + if g.Notify { + tmpl := g.Tmpl + if len(tmpl) > 0 { + tmpl = strings.Replace(tmpl, "{link}", v.Link, -1) + tmpl = strings.Replace(tmpl, "{txt}", v.Text, -1) + } else { + tmpl = fmt.Sprintf("%s\n%s", v.Text, v.Link) + } + msg := line.TextMessage{ + Text: tmpl, + } + line.PushMessage(g.ID, msg) + } + } + } + + c.Success(nil) +} diff --git a/router/routes/routes.go b/router/routes/routes.go index 0bed2f3..36eceb7 100644 --- a/router/routes/routes.go +++ b/router/routes/routes.go @@ -9,6 +9,7 @@ import ( "git.trj.tw/golang/mtfosbot/router/api" "git.trj.tw/golang/mtfosbot/router/google" "git.trj.tw/golang/mtfosbot/router/line" + "git.trj.tw/golang/mtfosbot/router/private" "git.trj.tw/golang/mtfosbot/router/rimg" "git.trj.tw/golang/mtfosbot/router/twitch" "github.com/gin-contrib/cors" @@ -59,9 +60,17 @@ func SetRoutes(r *gin.Engine) { { apiGroup.POST("/login", context.PatchCtx(api.UserLogin)) apiGroup.POST("/logout", context.PatchCtx(api.UserLogout)) + apiGroup.GET("/line_msg", context.PatchCtx(api.CheckSession), context.PatchCtx(api.GetLineMessageLog)) apiGroup.GET("/session", context.PatchCtx(api.CheckSession), context.PatchCtx(api.GetSessionData)) apiGroup.GET("/twitch/channel/:chid/opay/bar", context.PatchCtx(api.GetDonateBarStatus)) } + + privateAPIGroup := apiGroup.Group("/private", context.PatchCtx(private.VerifyKey)) + { + privateAPIGroup.GET("/pages", context.PatchCtx(private.GetFacebookPageIDs)) + privateAPIGroup.POST("/pageposts", context.PatchCtx(private.UpdateFacebookPagePost)) + } + apiTwitchGroup := apiGroup.Group("/twitch", context.PatchCtx(api.CheckSession)) { apiTwitchGroup.GET("/channels", context.PatchCtx(api.GetChannels), context.PatchCtx(api.GetChannelList)) @@ -73,7 +82,6 @@ func SetRoutes(r *gin.Engine) { twitchChannelGroup.GET("/opay/setting", context.PatchCtx(api.GetDonateSetting)) twitchChannelGroup.PUT("/opay/setting", context.PatchCtx(api.UpdateDonateSetting)) } - } r.POST("/line", context.PatchCtx(line.GetRawBody), context.PatchCtx(line.VerifyLine), context.PatchCtx(line.GetLineMessage))