浏览代码

feat: add `to` field to specify the receiver (close #48)

JustSong 2 年之前
父节点
当前提交
3d38260e5b
共有 10 个文件被更改,包括 55 次插入3 次删除
  1. 3 0
      README.md
  2. 6 1
      channel/corp.go
  3. 13 0
      channel/ding.go
  4. 10 0
      channel/discord.go
  5. 1 0
      channel/email.go
  6. 15 2
      channel/lark.go
  7. 1 0
      channel/telegram.go
  8. 3 0
      channel/wechat-corp-account.go
  9. 2 0
      controller/message.go
  10. 1 0
      model/message.go

+ 3 - 0
README.md

@@ -165,6 +165,9 @@ proxy_send_timeout 300s;
       11. `none`:仅保存到数据库,不做推送。
    5. `token`:如果你在后台设置了推送 token,则此项必填。另外可以通过设置 HTTP `Authorization` 头部设置此项。
    6. `url`:选填,如果不填则系统自动为消息生成 URL,其内容为消息详情。
+   7. `to`:选填,推送给指定用户,如果不填则默认推送给自己,受限于具体的消息推送方式,有些推送方式不支持此项。
+      1. `@all`:推送给所有用户。
+      2. `user1|user2|user3`:推送给多个用户,用户之间使用 `|` 分隔。
 3. `POST` 请求方式:字段与上面 `GET` 请求方式保持一致。
    + 注意:请求体编码格式为 `application/json`,`v0.3.2` 版本起支持 Post Form。
 

+ 6 - 1
channel/corp.go

@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"message-pusher/model"
 	"net/http"
+	"strings"
 )
 
 type corpMessageRequest struct {
@@ -17,6 +18,7 @@ type corpMessageRequest struct {
 	Markdown struct {
 		Content string `json:"content"`
 	} `json:"markdown"`
+	MentionedList []string `json:"mentioned_list"`
 }
 
 type corpMessageResponse struct {
@@ -25,6 +27,7 @@ type corpMessageResponse struct {
 }
 
 func SendCorpMessage(message *model.Message, user *model.User) error {
+	// https://developer.work.weixin.qq.com/document/path/91770
 	if user.CorpWebhookURL == "" {
 		return errors.New("未配置企业微信群机器人消息推送方式")
 	}
@@ -38,7 +41,9 @@ func SendCorpMessage(message *model.Message, user *model.User) error {
 		messageRequest.MessageType = "markdown"
 		messageRequest.Markdown.Content = message.Content
 	}
-
+	if message.To != "" {
+		messageRequest.MentionedList = strings.Split(message.To, "|")
+	}
 	jsonData, err := json.Marshal(messageRequest)
 	if err != nil {
 		return err

+ 13 - 0
channel/ding.go

@@ -11,6 +11,7 @@ import (
 	"message-pusher/model"
 	"net/http"
 	"net/url"
+	"strings"
 	"time"
 )
 
@@ -23,6 +24,10 @@ type dingMessageRequest struct {
 		Title string `json:"title"`
 		Text  string `json:"text"`
 	} `json:"markdown"`
+	At struct {
+		AtUserIds []string `json:"atUserIds"`
+		IsAtAll   bool     `json:"isAtAll"`
+	}
 }
 
 type dingMessageResponse struct {
@@ -31,6 +36,7 @@ type dingMessageResponse struct {
 }
 
 func SendDingMessage(message *model.Message, user *model.User) error {
+	// https://open.dingtalk.com/document/robots/custom-robot-access#title-72m-8ag-pqw
 	if user.DingWebhookURL == "" {
 		return errors.New("未配置钉钉群机器人消息推送方式")
 	}
@@ -45,6 +51,13 @@ func SendDingMessage(message *model.Message, user *model.User) error {
 		messageRequest.Markdown.Title = message.Title
 		messageRequest.Markdown.Text = message.Content
 	}
+	if message.To != "" {
+		if message.To == "@all" {
+			messageRequest.At.IsAtAll = true
+		} else {
+			messageRequest.At.AtUserIds = strings.Split(message.To, "|")
+		}
+	}
 
 	timestamp := time.Now().UnixMilli()
 	sign, err := dingSign(user.DingWebhookSecret, timestamp)

+ 10 - 0
channel/discord.go

@@ -6,6 +6,7 @@ import (
 	"errors"
 	"message-pusher/model"
 	"net/http"
+	"strings"
 )
 
 type discordMessageRequest struct {
@@ -27,6 +28,15 @@ func SendDiscordMessage(message *model.Message, user *model.User) error {
 	messageRequest := discordMessageRequest{
 		Content: message.Content,
 	}
+	// https://discord.com/developers/docs/reference#message-formatting
+	if message.To != "" {
+		messageRequest.Content = ""
+		ids := strings.Split(message.To, "|")
+		for _, id := range ids {
+			messageRequest.Content = "<@" + id + "> " + messageRequest.Content
+		}
+		messageRequest.Content = messageRequest.Content + message.Content
+	}
 
 	jsonData, err := json.Marshal(messageRequest)
 	if err != nil {

+ 1 - 0
channel/email.go

@@ -21,5 +21,6 @@ func SendEmailMessage(message *model.Message, user *model.User) error {
 			common.SysLog(err.Error())
 		}
 	}
+	// TODO: support message.To
 	return common.SendEmail(subject, user.Email, message.HTMLContent)
 }

+ 15 - 2
channel/lark.go

@@ -11,6 +11,7 @@ import (
 	"message-pusher/model"
 	"net/http"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -46,15 +47,27 @@ type larkMessageResponse struct {
 }
 
 func SendLarkMessage(message *model.Message, user *model.User) error {
+	// https://open.feishu.cn/document/ukTMukTMukTM/ucTM5YjL3ETO24yNxkjN#e1cdee9f
 	if user.LarkWebhookURL == "" {
 		return errors.New("未配置飞书群机器人消息推送方式")
 	}
 	messageRequest := larkMessageRequest{
 		MessageType: "text",
 	}
+	atPrefix := ""
+	if message.To != "" {
+		if message.To == "@all" {
+			atPrefix = "<at user_id=\"all\">所有人</at>"
+		} else {
+			ids := strings.Split(message.To, "|")
+			for _, id := range ids {
+				atPrefix += fmt.Sprintf("<at user_id=\"%s\"> </at>", id)
+			}
+		}
+	}
 	if message.Content == "" {
 		messageRequest.MessageType = "text"
-		messageRequest.Content.Text = message.Description
+		messageRequest.Content.Text = atPrefix + message.Description
 	} else {
 		messageRequest.MessageType = "interactive"
 		messageRequest.Card.Config.WideScreenMode = true
@@ -62,7 +75,7 @@ func SendLarkMessage(message *model.Message, user *model.User) error {
 		messageRequest.Card.Elements = append(messageRequest.Card.Elements, larkMessageRequestCardElement{
 			Tag: "div",
 			Text: larkMessageRequestCardElementText{
-				Content: message.Content,
+				Content: atPrefix + message.Content,
 				Tag:     "lark_md",
 			},
 		})

+ 1 - 0
channel/telegram.go

@@ -21,6 +21,7 @@ type telegramMessageResponse struct {
 }
 
 func SendTelegramMessage(message *model.Message, user *model.User) error {
+	// https://core.telegram.org/bots/api#sendmessage
 	if user.TelegramBotToken == "" || user.TelegramChatId == "" {
 		return errors.New("未配置 Telegram 机器人消息推送方式")
 	}

+ 3 - 0
channel/wechat-corp-account.go

@@ -104,6 +104,9 @@ func SendWeChatCorpMessage(message *model.Message, user *model.User) error {
 		ToUser:  user.WeChatCorpAccountUserId,
 		AgentId: user.WeChatCorpAccountAgentId,
 	}
+	if message.To != "" {
+		messageRequest.ToUser = message.To
+	}
 	if message.Content == "" {
 		if message.Title == "" {
 			messageRequest.MessageType = "text"

+ 2 - 0
controller/message.go

@@ -20,6 +20,7 @@ func GetPushMessage(c *gin.Context) {
 		URL:         c.Query("url"),
 		Channel:     c.Query("channel"),
 		Token:       c.Query("token"),
+		To:          c.Query("to"),
 	}
 	if message.Description == "" {
 		// Keep compatible with ServerChan
@@ -41,6 +42,7 @@ func PostPushMessage(c *gin.Context) {
 		Channel:     c.PostForm("channel"),
 		Token:       c.PostForm("token"),
 		Desp:        c.PostForm("desp"),
+		To:          c.PostForm("to"),
 	}
 	if message == (model.Message{}) {
 		// Looks like the user is using JSON

+ 1 - 0
model/message.go

@@ -19,6 +19,7 @@ type Message struct {
 	HTMLContent string `json:"html_content"  gorm:"-:all"`
 	Timestamp   int64  `json:"timestamp" gorm:"type:int64"`
 	Link        string `json:"link" gorm:"unique;index"`
+	To          string `json:"to" gorm:"column:to"` // if specified, will send to this user(s)
 }
 
 func GetMessageById(id int, userId int) (*Message, error) {