summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/matterbridge/gozulipbot/message.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/matterbridge/gozulipbot/message.go')
-rw-r--r--vendor/github.com/matterbridge/gozulipbot/message.go263
1 files changed, 263 insertions, 0 deletions
diff --git a/vendor/github.com/matterbridge/gozulipbot/message.go b/vendor/github.com/matterbridge/gozulipbot/message.go
new file mode 100644
index 00000000..df963f43
--- /dev/null
+++ b/vendor/github.com/matterbridge/gozulipbot/message.go
@@ -0,0 +1,263 @@
+package gozulipbot
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+)
+
+// A Message is all of the necessary metadata to post on Zulip.
+// It can be either a public message, where Topic is set, or a private message,
+// where there is at least one element in Emails.
+//
+// If the length of Emails is not 0, functions will always assume it is a private message.
+type Message struct {
+ Stream string
+ Topic string
+ Emails []string
+ Content string
+}
+
+type EventMessage struct {
+ AvatarURL string `json:"avatar_url"`
+ Client string `json:"client"`
+ Content string `json:"content"`
+ ContentType string `json:"content_type"`
+ DisplayRecipient DisplayRecipient `json:"display_recipient"`
+ GravatarHash string `json:"gravatar_hash"`
+ ID int `json:"id"`
+ RecipientID int `json:"recipient_id"`
+ SenderDomain string `json:"sender_domain"`
+ SenderEmail string `json:"sender_email"`
+ SenderFullName string `json:"sender_full_name"`
+ SenderID int `json:"sender_id"`
+ SenderShortName string `json:"sender_short_name"`
+ Subject string `json:"subject"`
+ SubjectLinks []interface{} `json:"subject_links"`
+ StreamID int `json:"stream_id"`
+ Timestamp int `json:"timestamp"`
+ Type string `json:"type"`
+ Queue *Queue `json:"-"`
+}
+
+type DisplayRecipient struct {
+ Users []User `json:"users,omitempty"`
+ Topic string `json:"topic,omitempty"`
+}
+
+type User struct {
+ Domain string `json:"domain"`
+ Email string `json:"email"`
+ FullName string `json:"full_name"`
+ ID int `json:"id"`
+ IsMirrorDummy bool `json:"is_mirror_dummy"`
+ ShortName string `json:"short_name"`
+}
+
+func (d *DisplayRecipient) UnmarshalJSON(b []byte) (err error) {
+ topic, users := "", make([]User, 1)
+ if err = json.Unmarshal(b, &topic); err == nil {
+ d.Topic = topic
+ return
+ }
+ if err = json.Unmarshal(b, &users); err == nil {
+ d.Users = users
+ return
+ }
+ return
+}
+
+// Message posts a message to Zulip. If any emails have been set on the message,
+// the message will be re-routed to the PrivateMessage function.
+func (b *Bot) Message(m Message) (*http.Response, error) {
+ if m.Content == "" {
+ return nil, fmt.Errorf("content cannot be empty")
+ }
+
+ // if any emails are set, this is a private message
+ if len(m.Emails) != 0 {
+ return b.PrivateMessage(m)
+ }
+
+ // otherwise it's a stream message
+ if m.Stream == "" {
+ return nil, fmt.Errorf("stream cannot be empty")
+ }
+ if m.Topic == "" {
+ return nil, fmt.Errorf("topic cannot be empty")
+ }
+ req, err := b.constructMessageRequest(m)
+ if err != nil {
+ return nil, err
+ }
+ return b.Client.Do(req)
+}
+
+// PrivateMessage sends a message to the users in the message email slice.
+func (b *Bot) PrivateMessage(m Message) (*http.Response, error) {
+ if len(m.Emails) == 0 {
+ return nil, fmt.Errorf("there must be at least one recipient")
+ }
+ req, err := b.constructMessageRequest(m)
+ if err != nil {
+ return nil, err
+ }
+ return b.Client.Do(req)
+}
+
+// Respond sends a given message as a response to whatever context from which
+// an EventMessage was received.
+func (b *Bot) Respond(e EventMessage, response string) (*http.Response, error) {
+ if response == "" {
+ return nil, fmt.Errorf("Message response cannot be blank")
+ }
+ m := Message{
+ Stream: e.DisplayRecipient.Topic,
+ Topic: e.Subject,
+ Content: response,
+ }
+ if m.Topic != "" {
+ return b.Message(m)
+ }
+ // private message
+ if m.Stream == "" {
+ emails, err := b.privateResponseList(e)
+ if err != nil {
+ return nil, err
+ }
+ m.Emails = emails
+ return b.Message(m)
+ }
+ return nil, fmt.Errorf("EventMessage is not understood: %v\n", e)
+}
+
+// privateResponseList gets the list of other users in a private multiple
+// message conversation.
+func (b *Bot) privateResponseList(e EventMessage) ([]string, error) {
+ var out []string
+ for _, u := range e.DisplayRecipient.Users {
+ if u.Email != b.Email {
+ out = append(out, u.Email)
+ }
+ }
+ if len(out) == 0 {
+ return nil, fmt.Errorf("EventMessage had no Users within the DisplayRecipient")
+ }
+ return out, nil
+}
+
+// constructMessageRequest is a helper for simplifying sending a message.
+func (b *Bot) constructMessageRequest(m Message) (*http.Request, error) {
+ to := m.Stream
+ mtype := "stream"
+
+ le := len(m.Emails)
+ if le != 0 {
+ mtype = "private"
+ }
+ if le == 1 {
+ to = m.Emails[0]
+ }
+ if le > 1 {
+ to = ""
+ for i, e := range m.Emails {
+ to += e
+ if i != le-1 {
+ to += ","
+ }
+ }
+ }
+
+ values := url.Values{}
+ values.Set("type", mtype)
+ values.Set("to", to)
+ values.Set("content", m.Content)
+ if mtype == "stream" {
+ values.Set("subject", m.Topic)
+ }
+
+ return b.constructRequest("POST", "messages", values.Encode())
+}
+
+func (b *Bot) UpdateMessage(id string, content string) (*http.Response, error) {
+ //mid, _ := strconv.Atoi(id)
+ values := url.Values{}
+ values.Set("content", content)
+ req, err := b.constructRequest("PATCH", "messages/"+id, values.Encode())
+ if err != nil {
+ return nil, err
+ }
+ return b.Client.Do(req)
+}
+
+// React adds an emoji reaction to an EventMessage.
+func (b *Bot) React(e EventMessage, emoji string) (*http.Response, error) {
+ url := fmt.Sprintf("messages/%d/emoji_reactions/%s", e.ID, emoji)
+ req, err := b.constructRequest("PUT", url, "")
+ if err != nil {
+ return nil, err
+ }
+ return b.Client.Do(req)
+}
+
+// Unreact removes an emoji reaction from an EventMessage.
+func (b *Bot) Unreact(e EventMessage, emoji string) (*http.Response, error) {
+ url := fmt.Sprintf("messages/%d/emoji_reactions/%s", e.ID, emoji)
+ req, err := b.constructRequest("DELETE", url, "")
+ if err != nil {
+ return nil, err
+ }
+ return b.Client.Do(req)
+}
+
+type Emoji struct {
+ Author string `json:"author"`
+ DisplayURL string `json:"display_url"`
+ SourceURL string `json:"source_url"`
+}
+
+type EmojiResponse struct {
+ Emoji map[string]*Emoji `json:"emoji"`
+ Msg string `json:"msg"`
+ Result string `json:"result"`
+}
+
+// RealmEmoji gets the custom emoji information for the Zulip instance.
+func (b *Bot) RealmEmoji() (map[string]*Emoji, error) {
+ req, err := b.constructRequest("GET", "realm/emoji", "")
+ if err != nil {
+ return nil, err
+ }
+ resp, err := b.Client.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ defer resp.Body.Close()
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ var emjResp EmojiResponse
+ err = json.Unmarshal(body, &emjResp)
+ if err != nil {
+ return nil, err
+ }
+ return emjResp.Emoji, nil
+}
+
+// RealmEmojiSet makes a set of the names of the custom emoji in the Zulip instance.
+func (b *Bot) RealmEmojiSet() (map[string]struct{}, error) {
+ emj, err := b.RealmEmoji()
+ if err != nil {
+ return nil, nil
+ }
+ out := map[string]struct{}{}
+ for k, _ := range emj {
+ out[k] = struct{}{}
+ }
+ return out, nil
+}