forked from lug/matterbridge
		
	Compare commits
	
		
			63 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | ac3c65a0cc | ||
|   | df74df475b | ||
|   | a61e2db7cb | ||
|   | 7aabe12acf | ||
|   | c4b75e5754 | ||
|   | 6a7adb20a8 | ||
|   | b49fb2b69c | ||
|   | 4bda29cb38 | ||
|   | 5f14141ec9 | ||
|   | c088e45d85 | ||
|   | d59c51a94b | ||
|   | 47b7fae61b | ||
|   | 1a40b0c1e9 | ||
|   | 27d886826c | ||
|   | 18981cb636 | ||
|   | ffa8f65aa8 | ||
|   | 82588b00c5 | ||
|   | 603449e850 | ||
|   | 248d88c849 | ||
|   | d19535fa21 | ||
|   | 49204cafcc | ||
|   | 812db2d267 | ||
|   | 14490bea9f | ||
|   | 0352970051 | ||
|   | ed01820722 | ||
|   | 90a61f15cc | ||
|   | 86cd7f1ba6 | ||
|   | d6ee55e35f | ||
|   | aef64eec32 | ||
|   | c4193d5ccd | ||
|   | 0c94186818 | ||
|   | 9039720013 | ||
|   | a3470f8aec | ||
|   | 01badde21d | ||
|   | a37b232dd9 | ||
|   | 579ee48385 | ||
|   | dd985d1dad | ||
|   | d2caea70a2 | ||
|   | 21143cf5ee | ||
|   | dc2aed698d | ||
|   | 37c350f19f | ||
|   | 9e03fcf162 | ||
|   | 8d4521c1df | ||
|   | 9226252336 | ||
|   | f4fb83e787 | ||
|   | e7fcb25107 | ||
|   | 5a85258f74 | ||
|   | 2f7df2df43 | ||
|   | ad3a753718 | ||
|   | e45c551880 | ||
|   | e59d338d4e | ||
|   | 7a86044f7a | ||
|   | 8b98f605bc | ||
|   | 7c773ebae0 | ||
|   | e84417430d | ||
|   | 5a8d7b5f6d | ||
|   | cfb8107138 | ||
|   | 43bd779fb7 | ||
|   | 7f9a400776 | ||
|   | ce1c5873ac | ||
|   | 85ff1995fd | ||
|   | b963f83c6a | ||
|   | f6297ebbb0 | 
| @@ -1,7 +1,7 @@ | ||||
| language: go | ||||
| go: | ||||
|     #- 1.7.x | ||||
|     - 1.8.x | ||||
|     - 1.9.x | ||||
|       # - tip | ||||
|  | ||||
| # we have everything vendored | ||||
|   | ||||
| @@ -29,14 +29,15 @@ Has a REST API. | ||||
| # Features | ||||
| * Relays public channel messages between multiple mattermost, IRC, XMPP, Gitter, Slack, Discord, Telegram, Rocket.Chat, Hipchat (via xmpp), Matrix and Steam.  | ||||
|   Pick and mix. | ||||
| * Matterbridge can also work with private groups on your mattermost/slack. | ||||
| * Support private groups on your mattermost/slack. | ||||
| * Allow for bridging the same bridges, which means you can eg bridge between multiple mattermosts. | ||||
| * The bridge is now a gateway which has support multiple in and out bridges. (and supports multiple gateways). | ||||
| * Edits and delete messages across bridges that support it (mattermost,slack,discord,gitter,telegram) | ||||
| * REST API to read/post messages to bridges (WIP). | ||||
|  | ||||
| # Requirements | ||||
| Accounts to one of the supported bridges | ||||
| * [Mattermost](https://github.com/mattermost/platform/) 3.5.x - 3.10.x, 4.0.x | ||||
| * [Mattermost](https://github.com/mattermost/platform/) 3.8.x - 3.10.x, 4.0.x - 4.2.x | ||||
| * [IRC](http://www.mirc.com/servers.html) | ||||
| * [XMPP](https://jabber.org) | ||||
| * [Gitter](https://gitter.im) | ||||
| @@ -53,7 +54,7 @@ See https://github.com/42wim/matterbridge/wiki | ||||
|  | ||||
| # Installing | ||||
| ## Binaries | ||||
| * Latest stable release [v1.0.1](https://github.com/42wim/matterbridge/releases/latest) | ||||
| * Latest stable release [v1.3.0](https://github.com/42wim/matterbridge/releases/latest) | ||||
| * Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/)   | ||||
|  | ||||
| ## Building | ||||
|   | ||||
| @@ -66,11 +66,15 @@ func (b *Api) JoinChannel(channel config.ChannelInfo) error { | ||||
|  | ||||
| } | ||||
|  | ||||
| func (b *Api) Send(msg config.Message) error { | ||||
| func (b *Api) Send(msg config.Message) (string, error) { | ||||
| 	b.Lock() | ||||
| 	defer b.Unlock() | ||||
| 	// ignore delete messages | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	b.Messages.Enqueue(&msg) | ||||
| 	return nil | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Api) handlePostMessage(c echo.Context) error { | ||||
|   | ||||
| @@ -19,7 +19,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| type Bridger interface { | ||||
| 	Send(msg config.Message) error | ||||
| 	Send(msg config.Message) (string, error) | ||||
| 	Connect() error | ||||
| 	JoinChannel(channel config.ChannelInfo) error | ||||
| 	Disconnect() error | ||||
|   | ||||
| @@ -14,6 +14,7 @@ const ( | ||||
| 	EVENT_FAILURE         = "failure" | ||||
| 	EVENT_REJOIN_CHANNELS = "rejoin_channels" | ||||
| 	EVENT_USER_ACTION     = "user_action" | ||||
| 	EVENT_MSG_DELETE      = "msg_delete" | ||||
| ) | ||||
|  | ||||
| type Message struct { | ||||
| @@ -27,6 +28,13 @@ type Message struct { | ||||
| 	Protocol  string    `json:"protocol"` | ||||
| 	Gateway   string    `json:"gateway"` | ||||
| 	Timestamp time.Time `json:"timestamp"` | ||||
| 	ID        string    `json:"id"` | ||||
| 	Extra     map[string][]interface{} | ||||
| } | ||||
|  | ||||
| type FileInfo struct { | ||||
| 	Name string | ||||
| 	Data *[]byte | ||||
| } | ||||
|  | ||||
| type ChannelInfo struct { | ||||
| @@ -42,6 +50,7 @@ type Protocol struct { | ||||
| 	AuthCode               string // steam | ||||
| 	BindAddress            string // mattermost, slack // DEPRECATED | ||||
| 	Buffer                 int    // api | ||||
| 	Charset                string // irc | ||||
| 	EditSuffix             string // mattermost, slack, discord, telegram, gitter | ||||
| 	EditDisable            bool   // mattermost, slack, discord, telegram, gitter | ||||
| 	IconURL                string // mattermost, slack | ||||
| @@ -54,6 +63,7 @@ type Protocol struct { | ||||
| 	Nick                   string // all protocols | ||||
| 	NickFormatter          string // mattermost, slack | ||||
| 	NickServNick           string // IRC | ||||
| 	NickServUsername       string // IRC | ||||
| 	NickServPassword       string // IRC | ||||
| 	NicksPerRow            int    // mattermost, slack | ||||
| 	NoHomeServerSuffix     bool   // matrix | ||||
|   | ||||
| @@ -66,6 +66,7 @@ func (b *bdiscord) Connect() error { | ||||
| 	b.c.AddHandler(b.messageCreate) | ||||
| 	b.c.AddHandler(b.memberUpdate) | ||||
| 	b.c.AddHandler(b.messageUpdate) | ||||
| 	b.c.AddHandler(b.messageDelete) | ||||
| 	err = b.c.Open() | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| @@ -108,12 +109,12 @@ func (b *bdiscord) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) Send(msg config.Message) error { | ||||
| func (b *bdiscord) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	channelID := b.getChannelID(msg.Channel) | ||||
| 	if channelID == "" { | ||||
| 		flog.Errorf("Could not find channelID for %v", msg.Channel) | ||||
| 		return nil | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	if msg.Event == config.EVENT_USER_ACTION { | ||||
| 		msg.Text = "_" + msg.Text + "_" | ||||
| @@ -129,20 +130,45 @@ func (b *bdiscord) Send(msg config.Message) error { | ||||
|  | ||||
| 	if wID == "" { | ||||
| 		flog.Debugf("Broadcasting using token (API)") | ||||
| 		b.c.ChannelMessageSend(channelID, msg.Username+msg.Text) | ||||
| 	} else { | ||||
| 		flog.Debugf("Broadcasting using Webhook") | ||||
| 		b.c.WebhookExecute( | ||||
| 			wID, | ||||
| 			wToken, | ||||
| 			true, | ||||
| 			&discordgo.WebhookParams{ | ||||
| 				Content:   msg.Text, | ||||
| 				Username:  msg.Username, | ||||
| 				AvatarURL: msg.Avatar, | ||||
| 			}) | ||||
| 		if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 			if msg.ID == "" { | ||||
| 				return "", nil | ||||
| 			} | ||||
| 			err := b.c.ChannelMessageDelete(channelID, msg.ID) | ||||
| 			return "", err | ||||
| 		} | ||||
| 		if msg.ID != "" { | ||||
| 			_, err := b.c.ChannelMessageEdit(channelID, msg.ID, msg.Username+msg.Text) | ||||
| 			return msg.ID, err | ||||
| 		} | ||||
| 		res, err := b.c.ChannelMessageSend(channelID, msg.Username+msg.Text) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return res.ID, err | ||||
| 	} | ||||
| 	return nil | ||||
| 	flog.Debugf("Broadcasting using Webhook") | ||||
| 	err := b.c.WebhookExecute( | ||||
| 		wID, | ||||
| 		wToken, | ||||
| 		true, | ||||
| 		&discordgo.WebhookParams{ | ||||
| 			Content:   msg.Text, | ||||
| 			Username:  msg.Username, | ||||
| 			AvatarURL: msg.Avatar, | ||||
| 		}) | ||||
| 	return "", err | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) messageDelete(s *discordgo.Session, m *discordgo.MessageDelete) { | ||||
| 	rmsg := config.Message{Account: b.Account, ID: m.ID, Event: config.EVENT_MSG_DELETE, Text: config.EVENT_MSG_DELETE} | ||||
| 	rmsg.Channel = b.getChannelName(m.ChannelID) | ||||
| 	if b.UseChannelID { | ||||
| 		rmsg.Channel = "ID:" + m.ChannelID | ||||
| 	} | ||||
| 	flog.Debugf("Sending message from %s to gateway", b.Account) | ||||
| 	flog.Debugf("Message is %#v", rmsg) | ||||
| 	b.Remote <- rmsg | ||||
| } | ||||
|  | ||||
| func (b *bdiscord) messageUpdate(s *discordgo.Session, m *discordgo.MessageUpdate) { | ||||
| @@ -185,7 +211,7 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat | ||||
| 	} | ||||
|  | ||||
| 	rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg", | ||||
| 		UserID: m.Author.ID} | ||||
| 		UserID: m.Author.ID, ID: m.ID} | ||||
|  | ||||
| 	rmsg.Channel = b.getChannelName(m.ChannelID) | ||||
| 	if b.UseChannelID { | ||||
| @@ -216,6 +242,7 @@ func (b *bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat | ||||
|  | ||||
| 	rmsg.Text = text | ||||
| 	flog.Debugf("Sending message from %s on %s to gateway", m.Author.Username, b.Account) | ||||
| 	flog.Debugf("Message is %#v", rmsg) | ||||
| 	b.Remote <- rmsg | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -2,9 +2,9 @@ package bgitter | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/42wim/go-gitter" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/sromku/go-gitter" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| @@ -13,6 +13,7 @@ type Bgitter struct { | ||||
| 	Config  *config.Protocol | ||||
| 	Remote  chan config.Message | ||||
| 	Account string | ||||
| 	User    *gitter.User | ||||
| 	Users   []gitter.User | ||||
| 	Rooms   []gitter.Room | ||||
| } | ||||
| @@ -36,7 +37,7 @@ func (b *Bgitter) Connect() error { | ||||
| 	var err error | ||||
| 	flog.Info("Connecting") | ||||
| 	b.c = gitter.New(b.Config.Token) | ||||
| 	_, err = b.c.GetUser() | ||||
| 	b.User, err = b.c.GetUser() | ||||
| 	if err != nil { | ||||
| 		flog.Debugf("%#v", err) | ||||
| 		return err | ||||
| @@ -78,15 +79,16 @@ func (b *Bgitter) JoinChannel(channel config.ChannelInfo) error { | ||||
| 		for event := range stream.Event { | ||||
| 			switch ev := event.Data.(type) { | ||||
| 			case *gitter.MessageReceived: | ||||
| 				// check for ZWSP to see if it's not an echo | ||||
| 				if !strings.HasSuffix(ev.Message.Text, "") { | ||||
| 				if ev.Message.From.ID != b.User.ID { | ||||
| 					flog.Debugf("Sending message from %s on %s to gateway", ev.Message.From.Username, b.Account) | ||||
| 					rmsg := config.Message{Username: ev.Message.From.Username, Text: ev.Message.Text, Channel: room, | ||||
| 						Account: b.Account, Avatar: b.getAvatar(ev.Message.From.Username), UserID: ev.Message.From.ID} | ||||
| 						Account: b.Account, Avatar: b.getAvatar(ev.Message.From.Username), UserID: ev.Message.From.ID, | ||||
| 						ID: ev.Message.ID} | ||||
| 					if strings.HasPrefix(ev.Message.Text, "@"+ev.Message.From.Username) { | ||||
| 						rmsg.Event = config.EVENT_USER_ACTION | ||||
| 						rmsg.Text = strings.Replace(rmsg.Text, "@"+ev.Message.From.Username+" ", "", -1) | ||||
| 					} | ||||
| 					flog.Debugf("Message is %#v", rmsg) | ||||
| 					b.Remote <- rmsg | ||||
| 				} | ||||
| 			case *gitter.GitterConnectionClosed: | ||||
| @@ -97,15 +99,37 @@ func (b *Bgitter) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bgitter) Send(msg config.Message) error { | ||||
| func (b *Bgitter) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	roomID := b.getRoomID(msg.Channel) | ||||
| 	if roomID == "" { | ||||
| 		flog.Errorf("Could not find roomID for %v", msg.Channel) | ||||
| 		return nil | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	// add ZWSP because gitter echoes our own messages | ||||
| 	return b.c.SendMessage(roomID, msg.Username+msg.Text+" ") | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		// gitter has no delete message api | ||||
| 		_, err := b.c.UpdateMessage(roomID, msg.ID, "") | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	if msg.ID != "" { | ||||
| 		flog.Debugf("updating message with id %s", msg.ID) | ||||
| 		_, err := b.c.UpdateMessage(roomID, msg.ID, msg.Username+msg.Text) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	resp, err := b.c.SendMessage(roomID, msg.Username+msg.Text) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return resp.ID, nil | ||||
| } | ||||
|  | ||||
| func (b *Bgitter) getRoomID(channel string) string { | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package birc | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"crypto/tls" | ||||
| 	"fmt" | ||||
| 	"github.com/42wim/go-ircevent" | ||||
| @@ -87,6 +88,7 @@ func (b *Birc) Connect() error { | ||||
| 		i.Password = b.Config.Password | ||||
| 	} | ||||
| 	i.AddCallback(ircm.RPL_WELCOME, b.handleNewConnection) | ||||
| 	i.AddCallback(ircm.RPL_ENDOFMOTD, b.handleOtherAuth) | ||||
| 	err := i.Connect(b.Config.Server) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @@ -127,11 +129,28 @@ func (b *Birc) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Birc) Send(msg config.Message) error { | ||||
| func (b *Birc) Send(msg config.Message) (string, error) { | ||||
| 	// ignore delete messages | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	if strings.HasPrefix(msg.Text, "!") { | ||||
| 		b.Command(&msg) | ||||
| 	} | ||||
|  | ||||
| 	if b.Config.Charset != "" { | ||||
| 		buf := new(bytes.Buffer) | ||||
| 		w, err := charset.NewWriter(b.Config.Charset, buf) | ||||
| 		if err != nil { | ||||
| 			flog.Errorf("charset from utf-8 conversion failed: %s", err) | ||||
| 			return "", err | ||||
| 		} | ||||
| 		fmt.Fprintf(w, msg.Text) | ||||
| 		w.Close() | ||||
| 		msg.Text = buf.String() | ||||
| 	} | ||||
|  | ||||
| 	for _, text := range strings.Split(msg.Text, "\n") { | ||||
| 		if len(text) > b.Config.MessageLength { | ||||
| 			text = text[:b.Config.MessageLength] + " <message clipped>" | ||||
| @@ -145,7 +164,7 @@ func (b *Birc) Send(msg config.Message) error { | ||||
| 			flog.Debugf("flooding, dropping message (queue at %d)", len(b.Local)) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Birc) doSend() { | ||||
| @@ -239,6 +258,13 @@ func (b *Birc) handleOther(event *irc.Event) { | ||||
| 	flog.Debugf("%#v", event.Raw) | ||||
| } | ||||
|  | ||||
| func (b *Birc) handleOtherAuth(event *irc.Event) { | ||||
| 	if strings.EqualFold(b.Config.NickServNick, "Q@CServe.quakenet.org") { | ||||
| 		flog.Debugf("Authenticating %s against %s", b.Config.NickServUsername, b.Config.NickServNick) | ||||
| 		b.i.Privmsg(b.Config.NickServNick, "AUTH "+b.Config.NickServUsername+" "+b.Config.NickServPassword) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Birc) handlePrivMsg(event *irc.Event) { | ||||
| 	b.Nick = b.i.GetNick() | ||||
| 	// freenode doesn't send 001 as first reply | ||||
| @@ -265,20 +291,25 @@ func (b *Birc) handlePrivMsg(event *irc.Event) { | ||||
| 	re := regexp.MustCompile(`[[:cntrl:]](\d+,|)\d+`) | ||||
| 	msg = re.ReplaceAllString(msg, "") | ||||
|  | ||||
| 	// detect what were sending so that we convert it to utf-8 | ||||
| 	detector := chardet.NewTextDetector() | ||||
| 	result, err := detector.DetectBest([]byte(msg)) | ||||
| 	if err != nil { | ||||
| 		flog.Infof("detection failed for msg: %#v", msg) | ||||
| 		return | ||||
| 	} | ||||
| 	flog.Debugf("detected %s confidence %#v", result.Charset, result.Confidence) | ||||
| 	var r io.Reader | ||||
| 	r, err = charset.NewReader(result.Charset, strings.NewReader(msg)) | ||||
| 	// if we're not sure, just pick ISO-8859-1 | ||||
| 	if result.Confidence < 80 { | ||||
| 		r, err = charset.NewReader("ISO-8859-1", strings.NewReader(msg)) | ||||
| 	var err error | ||||
| 	mycharset := b.Config.Charset | ||||
| 	if mycharset == "" { | ||||
| 		// detect what were sending so that we convert it to utf-8 | ||||
| 		detector := chardet.NewTextDetector() | ||||
| 		result, err := detector.DetectBest([]byte(msg)) | ||||
| 		if err != nil { | ||||
| 			flog.Infof("detection failed for msg: %#v", msg) | ||||
| 			return | ||||
| 		} | ||||
| 		flog.Debugf("detected %s confidence %#v", result.Charset, result.Confidence) | ||||
| 		mycharset = result.Charset | ||||
| 		// if we're not sure, just pick ISO-8859-1 | ||||
| 		if result.Confidence < 80 { | ||||
| 			mycharset = "ISO-8859-1" | ||||
| 		} | ||||
| 	} | ||||
| 	r, err = charset.NewReader(mycharset, strings.NewReader(msg)) | ||||
| 	if err != nil { | ||||
| 		flog.Errorf("charset to utf-8 conversion failed: %s", err) | ||||
| 		return | ||||
|   | ||||
| @@ -74,17 +74,21 @@ func (b *Bmatrix) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (b *Bmatrix) Send(msg config.Message) error { | ||||
| func (b *Bmatrix) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	// ignore delete messages | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	channel := b.getRoomID(msg.Channel) | ||||
| 	flog.Debugf("Sending to channel %s", channel) | ||||
| 	if msg.Event == config.EVENT_USER_ACTION { | ||||
| 		b.mc.SendMessageEvent(channel, "m.room.message", | ||||
| 			matrix.TextMessage{"m.emote", msg.Username + msg.Text}) | ||||
| 		return nil | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	b.mc.SendText(channel, msg.Username+msg.Text) | ||||
| 	return nil | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Bmatrix) getRoomID(channel string) string { | ||||
| @@ -100,7 +104,7 @@ func (b *Bmatrix) getRoomID(channel string) string { | ||||
| func (b *Bmatrix) handlematrix() error { | ||||
| 	syncer := b.mc.Syncer.(*matrix.DefaultSyncer) | ||||
| 	syncer.OnEventType("m.room.message", func(ev *matrix.Event) { | ||||
| 		if (ev.Content["msgtype"].(string) == "m.text" || ev.Content["msgtype"].(string) == "m.emote") && ev.Sender != b.UserID { | ||||
| 		if (ev.Content["msgtype"].(string) == "m.text" || ev.Content["msgtype"].(string) == "m.notice" || ev.Content["msgtype"].(string) == "m.emote") && ev.Sender != b.UserID { | ||||
| 			b.RLock() | ||||
| 			channel, ok := b.RoomMap[ev.RoomID] | ||||
| 			b.RUnlock() | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package bmattermost | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/matterclient" | ||||
| 	"github.com/42wim/matterbridge/matterhook" | ||||
| @@ -23,6 +24,9 @@ type MMMessage struct { | ||||
| 	Channel  string | ||||
| 	Username string | ||||
| 	UserID   string | ||||
| 	ID       string | ||||
| 	Event    string | ||||
| 	Extra    map[string][]interface{} | ||||
| } | ||||
|  | ||||
| type Bmattermost struct { | ||||
| @@ -61,6 +65,12 @@ func (b *Bmattermost) Connect() error { | ||||
| 			b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 				matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 					BindAddress: b.Config.WebhookBindAddress}) | ||||
| 		} else if b.Config.Token != "" { | ||||
| 			flog.Info("Connecting using token (sending)") | ||||
| 			err := b.apiLogin() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} else if b.Config.Login != "" { | ||||
| 			flog.Info("Connecting using login/password (sending)") | ||||
| 			err := b.apiLogin() | ||||
| @@ -81,7 +91,14 @@ func (b *Bmattermost) Connect() error { | ||||
| 		b.mh = matterhook.New(b.Config.WebhookURL, | ||||
| 			matterhook.Config{InsecureSkipVerify: b.Config.SkipTLSVerify, | ||||
| 				DisableServer: true}) | ||||
| 		if b.Config.Login != "" { | ||||
| 		if b.Config.Token != "" { | ||||
| 			flog.Info("Connecting using token (receiving)") | ||||
| 			err := b.apiLogin() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			go b.handleMatter() | ||||
| 		} else if b.Config.Login != "" { | ||||
| 			flog.Info("Connecting using login/password (receiving)") | ||||
| 			err := b.apiLogin() | ||||
| 			if err != nil { | ||||
| @@ -90,6 +107,13 @@ func (b *Bmattermost) Connect() error { | ||||
| 			go b.handleMatter() | ||||
| 		} | ||||
| 		return nil | ||||
| 	} else if b.Config.Token != "" { | ||||
| 		flog.Info("Connecting using token (sending and receiving)") | ||||
| 		err := b.apiLogin() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		go b.handleMatter() | ||||
| 	} else if b.Config.Login != "" { | ||||
| 		flog.Info("Connecting using login/password (sending and receiving)") | ||||
| 		err := b.apiLogin() | ||||
| @@ -98,8 +122,8 @@ func (b *Bmattermost) Connect() error { | ||||
| 		} | ||||
| 		go b.handleMatter() | ||||
| 	} | ||||
| 	if b.Config.WebhookBindAddress == "" && b.Config.WebhookURL == "" && b.Config.Login == "" { | ||||
| 		return errors.New("No connection method found. See that you have WebhookBindAddress, WebhookURL or Login/Password/Server/Team configured.") | ||||
| 	if b.Config.WebhookBindAddress == "" && b.Config.WebhookURL == "" && b.Config.Login == "" && b.Config.Token == "" { | ||||
| 		return errors.New("No connection method found. See that you have WebhookBindAddress, WebhookURL or Token/Login/Password/Server/Team configured.") | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -111,12 +135,16 @@ func (b *Bmattermost) Disconnect() error { | ||||
| func (b *Bmattermost) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	// we can only join channels using the API | ||||
| 	if b.Config.WebhookURL == "" && b.Config.WebhookBindAddress == "" { | ||||
| 		return b.mc.JoinChannel(b.mc.GetChannelId(channel.Name, "")) | ||||
| 		id := b.mc.GetChannelId(channel.Name, "") | ||||
| 		if id == "" { | ||||
| 			return fmt.Errorf("Could not find channel ID for channel %s", channel.Name) | ||||
| 		} | ||||
| 		return b.mc.JoinChannel(id) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) Send(msg config.Message) error { | ||||
| func (b *Bmattermost) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	if msg.Event == config.EVENT_USER_ACTION { | ||||
| 		msg.Text = "*" + msg.Text + "*" | ||||
| @@ -135,15 +163,46 @@ func (b *Bmattermost) Send(msg config.Message) error { | ||||
| 		matterMessage.UserName = nick | ||||
| 		matterMessage.Type = "" | ||||
| 		matterMessage.Text = message | ||||
| 		matterMessage.Text = message | ||||
| 		matterMessage.Props = make(map[string]interface{}) | ||||
| 		matterMessage.Props["matterbridge"] = true | ||||
| 		err := b.mh.Send(matterMessage) | ||||
| 		if err != nil { | ||||
| 			flog.Info(err) | ||||
| 			return err | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return nil | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	b.mc.PostMessage(b.mc.GetChannelId(channel, ""), message) | ||||
| 	return nil | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		return msg.ID, b.mc.DeleteMessage(msg.ID) | ||||
| 	} | ||||
| 	if msg.Extra != nil { | ||||
| 		if len(msg.Extra["file"]) > 0 { | ||||
| 			var err error | ||||
| 			var res, id string | ||||
| 			for _, f := range msg.Extra["file"] { | ||||
| 				fi := f.(config.FileInfo) | ||||
| 				id, err = b.mc.UploadFile(*fi.Data, b.mc.GetChannelId(channel, ""), fi.Name) | ||||
| 				if err != nil { | ||||
| 					flog.Debugf("ERROR %#v", err) | ||||
| 					return "", err | ||||
| 				} | ||||
| 				message = "uploaded a file: " + fi.Name | ||||
| 				if b.Config.PrefixMessagesWithNick { | ||||
| 					message = nick + "uploaded a file: " + fi.Name | ||||
| 				} | ||||
| 				res, err = b.mc.PostMessageWithFiles(b.mc.GetChannelId(channel, ""), message, []string{id}) | ||||
| 			} | ||||
| 			return res, err | ||||
| 		} | ||||
| 	} | ||||
| 	if msg.ID != "" { | ||||
| 		return b.mc.EditMessage(msg.ID, message) | ||||
| 	} | ||||
| 	return b.mc.PostMessage(b.mc.GetChannelId(channel, ""), message) | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) handleMatter() { | ||||
| @@ -152,17 +211,22 @@ func (b *Bmattermost) handleMatter() { | ||||
| 		flog.Debugf("Choosing webhooks based receiving") | ||||
| 		go b.handleMatterHook(mchan) | ||||
| 	} else { | ||||
| 		flog.Debugf("Choosing login/password based receiving") | ||||
| 		if b.Config.Token != "" { | ||||
| 			flog.Debugf("Choosing token based receiving") | ||||
| 		} else { | ||||
| 			flog.Debugf("Choosing login/password based receiving") | ||||
| 		} | ||||
| 		go b.handleMatterClient(mchan) | ||||
| 	} | ||||
| 	for message := range mchan { | ||||
| 		rmsg := config.Message{Username: message.Username, Channel: message.Channel, Account: b.Account, UserID: message.UserID} | ||||
| 		rmsg := config.Message{Username: message.Username, Channel: message.Channel, Account: b.Account, UserID: message.UserID, ID: message.ID, Event: message.Event, Extra: message.Extra} | ||||
| 		text, ok := b.replaceAction(message.Text) | ||||
| 		if ok { | ||||
| 			rmsg.Event = config.EVENT_USER_ACTION | ||||
| 		} | ||||
| 		rmsg.Text = text | ||||
| 		flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account) | ||||
| 		flog.Debugf("Message is %#v", rmsg) | ||||
| 		b.Remote <- rmsg | ||||
| 	} | ||||
| } | ||||
| @@ -180,23 +244,42 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) { | ||||
| 		if (message.Raw.Event == "post_edited") && b.Config.EditDisable { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		m := &MMMessage{Extra: make(map[string][]interface{})} | ||||
|  | ||||
| 		props := message.Post.Props | ||||
| 		if props != nil { | ||||
| 			if _, ok := props["matterbridge"].(bool); ok { | ||||
| 				flog.Debugf("sent by matterbridge, ignoring") | ||||
| 				continue | ||||
| 			} | ||||
| 			if _, ok := props["override_username"].(string); ok { | ||||
| 				message.Username = props["override_username"].(string) | ||||
| 			} | ||||
| 			if _, ok := props["attachments"].([]interface{}); ok { | ||||
| 				m.Extra["attachments"] = props["attachments"].([]interface{}) | ||||
| 			} | ||||
| 		} | ||||
| 		// do not post our own messages back to irc | ||||
| 		// only listen to message from our team | ||||
| 		if (message.Raw.Event == "posted" || message.Raw.Event == "post_edited") && | ||||
| 		if (message.Raw.Event == "posted" || message.Raw.Event == "post_edited" || message.Raw.Event == "post_deleted") && | ||||
| 			b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId { | ||||
| 			// if the message has reactions don't repost it (for now, until we can correlate reaction with message) | ||||
| 			if message.Post.HasReactions { | ||||
| 				continue | ||||
| 			} | ||||
| 			flog.Debugf("Receiving from matterclient %#v", message) | ||||
| 			m := &MMMessage{} | ||||
| 			m.UserID = message.UserID | ||||
| 			m.Username = message.Username | ||||
| 			m.Channel = message.Channel | ||||
| 			m.Text = message.Text | ||||
| 			m.ID = message.Post.Id | ||||
| 			if message.Raw.Event == "post_edited" && !b.Config.EditDisable { | ||||
| 				m.Text = message.Text + b.Config.EditSuffix | ||||
| 			} | ||||
| 			if message.Raw.Event == "post_deleted" { | ||||
| 				m.Event = config.EVENT_MSG_DELETE | ||||
| 			} | ||||
| 			if len(message.Post.FileIds) > 0 { | ||||
| 				for _, link := range b.mc.GetFileLinks(message.Post.FileIds) { | ||||
| 					m.Text = m.Text + "\n" + link | ||||
| @@ -221,7 +304,12 @@ func (b *Bmattermost) handleMatterHook(mchan chan *MMMessage) { | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) apiLogin() error { | ||||
| 	b.mc = matterclient.New(b.Config.Login, b.Config.Password, | ||||
| 	password := b.Config.Password | ||||
| 	if b.Config.Token != "" { | ||||
| 		password = "MMAUTHTOKEN=" + b.Config.Token | ||||
| 	} | ||||
|  | ||||
| 	b.mc = matterclient.New(b.Config.Login, password, | ||||
| 		b.Config.Team, b.Config.Server) | ||||
| 	b.mc.SkipTLSVerify = b.Config.SkipTLSVerify | ||||
| 	b.mc.NoTLS = b.Config.NoTLS | ||||
|   | ||||
| @@ -57,7 +57,11 @@ func (b *Brocketchat) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Brocketchat) Send(msg config.Message) error { | ||||
| func (b *Brocketchat) Send(msg config.Message) (string, error) { | ||||
| 	// ignore delete messages | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	matterMessage := matterhook.OMessage{IconURL: b.Config.IconURL} | ||||
| 	matterMessage.Channel = msg.Channel | ||||
| @@ -67,9 +71,9 @@ func (b *Brocketchat) Send(msg config.Message) error { | ||||
| 	err := b.mh.Send(matterMessage) | ||||
| 	if err != nil { | ||||
| 		flog.Info(err) | ||||
| 		return err | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return nil | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Brocketchat) handleRocketHook() { | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package bslack | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| @@ -8,6 +9,8 @@ import ( | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/nlopes/slack" | ||||
| 	"html" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| @@ -125,7 +128,7 @@ func (b *Bslack) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bslack) Send(msg config.Message) error { | ||||
| func (b *Bslack) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	if msg.Event == config.EVENT_USER_ACTION { | ||||
| 		msg.Text = "_" + msg.Text + "_" | ||||
| @@ -145,13 +148,13 @@ func (b *Bslack) Send(msg config.Message) error { | ||||
| 		err := b.mh.Send(matterMessage) | ||||
| 		if err != nil { | ||||
| 			flog.Info(err) | ||||
| 			return err | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return nil | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	schannel, err := b.getChannelByName(channel) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		return "", err | ||||
| 	} | ||||
| 	np := slack.NewPostMessageParameters() | ||||
| 	if b.Config.PrefixMessagesWithNick { | ||||
| @@ -163,14 +166,32 @@ func (b *Bslack) Send(msg config.Message) error { | ||||
| 		np.IconURL = msg.Avatar | ||||
| 	} | ||||
| 	np.Attachments = append(np.Attachments, slack.Attachment{CallbackID: "matterbridge"}) | ||||
| 	b.sc.PostMessage(schannel.ID, message, np) | ||||
| 	np.Attachments = append(np.Attachments, b.createAttach(msg.Extra)...) | ||||
|  | ||||
| 	/* | ||||
| 	   newmsg := b.rtm.NewOutgoingMessage(message, schannel.ID) | ||||
| 	   b.rtm.SendMessage(newmsg) | ||||
| 	*/ | ||||
| 	// replace mentions | ||||
| 	np.LinkNames = 1 | ||||
|  | ||||
| 	return nil | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		// some protocols echo deletes, but with empty ID | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		// we get a "slack <ID>", split it | ||||
| 		ts := strings.Fields(msg.ID) | ||||
| 		b.sc.DeleteMessage(schannel.ID, ts[1]) | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	// if we have no ID it means we're creating a new message, not updating an existing one | ||||
| 	if msg.ID != "" { | ||||
| 		ts := strings.Fields(msg.ID) | ||||
| 		b.sc.UpdateMessage(schannel.ID, ts[1], message) | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	_, id, err := b.sc.PostMessage(schannel.ID, message, np) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return "slack " + id, nil | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getAvatar(user string) string { | ||||
| @@ -225,83 +246,109 @@ func (b *Bslack) handleSlack() { | ||||
| 		if b.Config.WebhookURL == "" && b.Config.WebhookBindAddress == "" && message.Username == b.si.User.Name { | ||||
| 			continue | ||||
| 		} | ||||
| 		if message.Text == "" || message.Username == "" { | ||||
| 		if (message.Text == "" || message.Username == "") && message.Raw.SubType != "message_deleted" { | ||||
| 			continue | ||||
| 		} | ||||
| 		texts := strings.Split(message.Text, "\n") | ||||
| 		for _, text := range texts { | ||||
| 			text = b.replaceURL(text) | ||||
| 			text = html.UnescapeString(text) | ||||
| 			flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account) | ||||
| 			msg := config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID} | ||||
| 			if message.Raw.SubType == "me_message" { | ||||
| 				msg.Event = config.EVENT_USER_ACTION | ||||
| 			} | ||||
| 			b.Remote <- msg | ||||
| 		text := message.Text | ||||
| 		text = b.replaceURL(text) | ||||
| 		text = html.UnescapeString(text) | ||||
| 		flog.Debugf("Sending message from %s on %s to gateway", message.Username, b.Account) | ||||
| 		msg := config.Message{Text: text, Username: message.Username, Channel: message.Channel, Account: b.Account, Avatar: b.getAvatar(message.Username), UserID: message.UserID, ID: "slack " + message.Raw.Timestamp, Extra: make(map[string][]interface{})} | ||||
| 		if message.Raw.SubType == "me_message" { | ||||
| 			msg.Event = config.EVENT_USER_ACTION | ||||
| 		} | ||||
| 		if message.Raw.SubType == "channel_leave" || message.Raw.SubType == "channel_join" { | ||||
| 			msg.Username = "system" | ||||
| 			msg.Event = config.EVENT_JOIN_LEAVE | ||||
| 		} | ||||
| 		// edited messages have a submessage, use this timestamp | ||||
| 		if message.Raw.SubMessage != nil { | ||||
| 			msg.ID = "slack " + message.Raw.SubMessage.Timestamp | ||||
| 		} | ||||
| 		if message.Raw.SubType == "message_deleted" { | ||||
| 			msg.Text = config.EVENT_MSG_DELETE | ||||
| 			msg.Event = config.EVENT_MSG_DELETE | ||||
| 			msg.ID = "slack " + message.Raw.DeletedTimestamp | ||||
| 		} | ||||
|  | ||||
| 		// if we have a file attached, download it (in memory) and put a pointer to it in msg.Extra | ||||
| 		if message.Raw.File != nil { | ||||
| 			// limit to 1MB for now | ||||
| 			if message.Raw.File.Size <= 1000000 { | ||||
| 				data, err := b.downloadFile(message.Raw.File.URLPrivateDownload) | ||||
| 				if err != nil { | ||||
| 					flog.Errorf("download %s failed %#v", message.Raw.File.URLPrivateDownload, err) | ||||
| 				} else { | ||||
| 					msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{Name: message.Raw.File.Name, Data: data}) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		flog.Debugf("Message is %#v", msg) | ||||
| 		b.Remote <- msg | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bslack) handleSlackClient(mchan chan *MMMessage) { | ||||
| 	count := 0 | ||||
| 	for msg := range b.rtm.IncomingEvents { | ||||
| 		switch ev := msg.Data.(type) { | ||||
| 		case *slack.MessageEvent: | ||||
| 			// ignore first message | ||||
| 			if count > 0 { | ||||
| 				flog.Debugf("Receiving from slackclient %#v", ev) | ||||
| 				if len(ev.Attachments) > 0 { | ||||
| 					// skip messages we made ourselves | ||||
| 					if ev.Attachments[0].CallbackID == "matterbridge" { | ||||
| 						continue | ||||
| 					} | ||||
| 			flog.Debugf("Receiving from slackclient %#v", ev) | ||||
| 			if len(ev.Attachments) > 0 { | ||||
| 				// skip messages we made ourselves | ||||
| 				if ev.Attachments[0].CallbackID == "matterbridge" { | ||||
| 					continue | ||||
| 				} | ||||
| 				if !b.Config.EditDisable && ev.SubMessage != nil && ev.SubMessage.ThreadTimestamp != ev.SubMessage.Timestamp { | ||||
| 					flog.Debugf("SubMessage %#v", ev.SubMessage) | ||||
| 					ev.User = ev.SubMessage.User | ||||
| 					ev.Text = ev.SubMessage.Text + b.Config.EditSuffix | ||||
| 			} | ||||
| 			if !b.Config.EditDisable && ev.SubMessage != nil && ev.SubMessage.ThreadTimestamp != ev.SubMessage.Timestamp { | ||||
| 				flog.Debugf("SubMessage %#v", ev.SubMessage) | ||||
| 				ev.User = ev.SubMessage.User | ||||
| 				ev.Text = ev.SubMessage.Text + b.Config.EditSuffix | ||||
|  | ||||
| 				// it seems ev.SubMessage.Edited == nil when slack unfurls | ||||
| 				// do not forward these messages #266 | ||||
| 				if ev.SubMessage.Edited == nil { | ||||
| 					continue | ||||
| 				} | ||||
| 				// use our own func because rtm.GetChannelInfo doesn't work for private channels | ||||
| 				channel, err := b.getChannelByID(ev.Channel) | ||||
| 			} | ||||
| 			// use our own func because rtm.GetChannelInfo doesn't work for private channels | ||||
| 			channel, err := b.getChannelByID(ev.Channel) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			m := &MMMessage{} | ||||
| 			if ev.BotID == "" && ev.SubType != "message_deleted" { | ||||
| 				user, err := b.rtm.GetUserInfo(ev.User) | ||||
| 				if err != nil { | ||||
| 					continue | ||||
| 				} | ||||
| 				m := &MMMessage{} | ||||
| 				if ev.BotID == "" { | ||||
| 					user, err := b.rtm.GetUserInfo(ev.User) | ||||
| 					if err != nil { | ||||
| 						continue | ||||
| 					} | ||||
| 					m.UserID = user.ID | ||||
| 					m.Username = user.Name | ||||
| 				} | ||||
| 				m.Channel = channel.Name | ||||
| 				m.Text = ev.Text | ||||
| 				if m.Text == "" { | ||||
| 					for _, attach := range ev.Attachments { | ||||
| 						if attach.Text != "" { | ||||
| 							m.Text = attach.Text | ||||
| 						} else { | ||||
| 							m.Text = attach.Fallback | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				m.Raw = ev | ||||
| 				m.Text = b.replaceMention(m.Text) | ||||
| 				// when using webhookURL we can't check if it's our webhook or not for now | ||||
| 				if ev.BotID != "" && b.Config.WebhookURL == "" { | ||||
| 					bot, err := b.rtm.GetBotInfo(ev.BotID) | ||||
| 					if err != nil { | ||||
| 						continue | ||||
| 					} | ||||
| 					if bot.Name != "" { | ||||
| 						m.Username = bot.Name | ||||
| 						m.UserID = bot.ID | ||||
| 					} | ||||
| 				} | ||||
| 				mchan <- m | ||||
| 				m.UserID = user.ID | ||||
| 				m.Username = user.Name | ||||
| 			} | ||||
| 			count++ | ||||
| 			m.Channel = channel.Name | ||||
| 			m.Text = ev.Text | ||||
| 			if m.Text == "" { | ||||
| 				for _, attach := range ev.Attachments { | ||||
| 					if attach.Text != "" { | ||||
| 						m.Text = attach.Text | ||||
| 					} else { | ||||
| 						m.Text = attach.Fallback | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			m.Raw = ev | ||||
| 			m.Text = b.replaceMention(m.Text) | ||||
| 			// when using webhookURL we can't check if it's our webhook or not for now | ||||
| 			if ev.BotID != "" && b.Config.WebhookURL == "" { | ||||
| 				bot, err := b.rtm.GetBotInfo(ev.BotID) | ||||
| 				if err != nil { | ||||
| 					continue | ||||
| 				} | ||||
| 				if bot.Name != "" { | ||||
| 					m.Username = bot.Name | ||||
| 					m.UserID = bot.ID | ||||
| 				} | ||||
| 			} | ||||
| 			mchan <- m | ||||
| 		case *slack.OutgoingErrorEvent: | ||||
| 			flog.Debugf("%#v", ev.Error()) | ||||
| 		case *slack.ChannelJoinedEvent: | ||||
| @@ -366,3 +413,47 @@ func (b *Bslack) replaceURL(text string) string { | ||||
| 	} | ||||
| 	return text | ||||
| } | ||||
|  | ||||
| func (b *Bslack) createAttach(extra map[string][]interface{}) []slack.Attachment { | ||||
| 	var attachs []slack.Attachment | ||||
| 	for _, v := range extra["attachments"] { | ||||
| 		entry := v.(map[string]interface{}) | ||||
| 		s := slack.Attachment{} | ||||
| 		s.Fallback = entry["fallback"].(string) | ||||
| 		s.Color = entry["color"].(string) | ||||
| 		s.Pretext = entry["pretext"].(string) | ||||
| 		s.AuthorName = entry["author_name"].(string) | ||||
| 		s.AuthorLink = entry["author_link"].(string) | ||||
| 		s.AuthorIcon = entry["author_icon"].(string) | ||||
| 		s.Title = entry["title"].(string) | ||||
| 		s.TitleLink = entry["title_link"].(string) | ||||
| 		s.Text = entry["text"].(string) | ||||
| 		s.ImageURL = entry["image_url"].(string) | ||||
| 		s.ThumbURL = entry["thumb_url"].(string) | ||||
| 		s.Footer = entry["footer"].(string) | ||||
| 		s.FooterIcon = entry["footer_icon"].(string) | ||||
| 		attachs = append(attachs, s) | ||||
| 	} | ||||
| 	return attachs | ||||
| } | ||||
|  | ||||
| func (b *Bslack) downloadFile(url string) (*[]byte, error) { | ||||
| 	var buf bytes.Buffer | ||||
| 	client := &http.Client{ | ||||
| 		Timeout: time.Second * 5, | ||||
| 	} | ||||
| 	req, err := http.NewRequest("GET", url, nil) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	req.Header.Add("Authorization", "Bearer "+b.Config.Token) | ||||
| 	resp, err := client.Do(req) | ||||
| 	if err != nil { | ||||
| 		resp.Body.Close() | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	io.Copy(&buf, resp.Body) | ||||
| 	data := buf.Bytes() | ||||
| 	resp.Body.Close() | ||||
| 	return &data, nil | ||||
| } | ||||
|   | ||||
| @@ -69,13 +69,17 @@ func (b *Bsteam) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bsteam) Send(msg config.Message) error { | ||||
| func (b *Bsteam) Send(msg config.Message) (string, error) { | ||||
| 	// ignore delete messages | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	id, err := steamid.NewId(msg.Channel) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		return "", err | ||||
| 	} | ||||
| 	b.c.Social.SendMessage(id, steamlang.EChatEntryType_ChatMsg, msg.Username+msg.Text) | ||||
| 	return nil | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Bsteam) getNick(id steamid.SteamId) string { | ||||
|   | ||||
| @@ -57,22 +57,53 @@ func (b *Btelegram) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) Send(msg config.Message) error { | ||||
| func (b *Btelegram) Send(msg config.Message) (string, error) { | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	chatid, err := strconv.ParseInt(msg.Channel, 10, 64) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	if b.Config.MessageFormat == "HTML" { | ||||
| 		msg.Text = makeHTML(msg.Text) | ||||
| 	} | ||||
|  | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
| 		msgid, err := strconv.Atoi(msg.ID) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		_, err = b.c.DeleteMessage(tgbotapi.DeleteMessageConfig{ChatID: chatid, MessageID: msgid}) | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	// edit the message if we have a msg ID | ||||
| 	if msg.ID != "" { | ||||
| 		msgid, err := strconv.Atoi(msg.ID) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		m := tgbotapi.NewEditMessageText(chatid, msgid, msg.Username+msg.Text) | ||||
| 		_, err = b.c.Send(m) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	m := tgbotapi.NewMessage(chatid, msg.Username+msg.Text) | ||||
| 	if b.Config.MessageFormat == "HTML" { | ||||
| 		m.ParseMode = tgbotapi.ModeHTML | ||||
| 	} | ||||
| 	_, err = b.c.Send(m) | ||||
| 	return err | ||||
| 	res, err := b.c.Send(m) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return strconv.Itoa(res.MessageID), nil | ||||
|  | ||||
| } | ||||
|  | ||||
| func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| @@ -129,9 +160,32 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| 		if message.Document != nil && b.Config.UseInsecureURL { | ||||
| 			text = text + " " + message.Document.FileName + " : " + b.getFileDirectURL(message.Document.FileID) | ||||
| 		} | ||||
|  | ||||
| 		// quote the previous message | ||||
| 		if message.ReplyToMessage != nil { | ||||
| 			usernameReply := "" | ||||
| 			if message.ReplyToMessage.From != nil { | ||||
| 				if b.Config.UseFirstName { | ||||
| 					usernameReply = message.ReplyToMessage.From.FirstName | ||||
| 				} | ||||
| 				if usernameReply == "" { | ||||
| 					usernameReply = message.ReplyToMessage.From.UserName | ||||
| 					if usernameReply == "" { | ||||
| 						usernameReply = message.ReplyToMessage.From.FirstName | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			if usernameReply == "" { | ||||
| 				usernameReply = "unknown" | ||||
| 			} | ||||
| 			text = text + " (re @" + usernameReply + ":" + message.ReplyToMessage.Text + ")" | ||||
| 		} | ||||
|  | ||||
| 		if text != "" { | ||||
| 			flog.Debugf("Sending message from %s on %s to gateway", username, b.Account) | ||||
| 			b.Remote <- config.Message{Username: username, Text: text, Channel: channel, Account: b.Account, UserID: strconv.Itoa(message.From.ID)} | ||||
| 			msg := config.Message{Username: username, Text: text, Channel: channel, Account: b.Account, UserID: strconv.Itoa(message.From.ID), ID: strconv.Itoa(message.MessageID)} | ||||
| 			flog.Debugf("Message is %#v", msg) | ||||
| 			b.Remote <- msg | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -79,10 +79,14 @@ func (b *Bxmpp) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bxmpp) Send(msg config.Message) error { | ||||
| func (b *Bxmpp) Send(msg config.Message) (string, error) { | ||||
| 	// ignore delete messages | ||||
| 	if msg.Event == config.EVENT_MSG_DELETE { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	flog.Debugf("Receiving %#v", msg) | ||||
| 	b.xc.Send(xmpp.Chat{Type: "groupchat", Remote: msg.Channel + "@" + b.Config.Muc, Text: msg.Username + msg.Text}) | ||||
| 	return nil | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Bxmpp) createXMPP() (*xmpp.Client, error) { | ||||
|   | ||||
							
								
								
									
										59
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,10 +1,65 @@ | ||||
| # v1.3.0 | ||||
| ## New features | ||||
| * Relay slack_attachments from mattermost to slack (slack). Closes #260 | ||||
| * Add support for quoting previous message when replying (telegram). #237 | ||||
| * Add support for Quakenet auth (irc). Closes #263 | ||||
| * Download files (max size 1MB) from slack and reupload to mattermost (slack/mattermost). Closes #255 | ||||
|  | ||||
| ## Enhancements | ||||
| * Backoff for 60 seconds when reconnecting too fast (irc) #267 | ||||
| * Use override username if specified (mattermost). #260 | ||||
|  | ||||
| ## Bugfix | ||||
| * Try to not forward slack unfurls. Closes #266 | ||||
|  | ||||
| # v1.2.0 | ||||
| ## Breaking changes | ||||
| * If you're running a discord bridge, update to this release before 16 october otherwise | ||||
| it will stop working. (see https://discordapp.com/developers/docs/reference) | ||||
|  | ||||
| ## New features | ||||
| * general: Add delete support. (actually delete the messages on bridges that support it) | ||||
|     (mattermost,discord,gitter,slack,telegram) | ||||
|  | ||||
| ## Bugfix | ||||
| * Do not break messages on newline (slack). Closes #258  | ||||
| * Update telegram library | ||||
| * Update discord library (supports v6 API now). Old API is deprecated on 16 October | ||||
|  | ||||
| # v1.1.2 | ||||
| ## New features | ||||
| * general: also build darwin binaries | ||||
| * mattermost: add support for mattermost 4.2.x | ||||
|  | ||||
| ## Bugfix  | ||||
| * mattermost: Send images when text is empty regression. (mattermost). Closes #254 | ||||
| * slack: also send the first messsage after connect. #252 | ||||
|  | ||||
| # v1.1.1 | ||||
| ## Bugfix | ||||
| * mattermost: fix public links | ||||
|  | ||||
| # v1.1.0 | ||||
| ## New features | ||||
| * general: Add better editing support. (actually edit the messages on bridges that support it) | ||||
| 	(mattermost,discord,gitter,slack,telegram) | ||||
| * mattermost: use API v4 (removes support for mattermost < 3.8) | ||||
| * mattermost: add support for personal access tokens (since mattermost 4.1) | ||||
| 	Use ```Token="yourtoken"``` in mattermost config | ||||
| 	See https://docs.mattermost.com/developer/personal-access-tokens.html for more info | ||||
| * matrix: Relay notices (matrix). Closes #243 | ||||
| * irc: Add a charset option. Closes #247 | ||||
|  | ||||
| ## Bugfix | ||||
| * slack: Handle leave/join events (slack). Closes #246 | ||||
| * slack: Replace mentions from other bridges. (slack). Closes #233 | ||||
| * gitter: remove ZWSP after messages | ||||
|  | ||||
| # v1.0.1 | ||||
| ## New features | ||||
| * mattermost: add support for mattermost 4.1.x | ||||
| * discord: allow a webhookURL per channel #239 | ||||
|  | ||||
| ## Bugfix | ||||
|  | ||||
| # v1.0.0 | ||||
| ## New features | ||||
| * general: Add action support for slack,mattermost,irc,gitter,matrix,xmpp,discord. #199 | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| #!/bin/bash | ||||
| go version |grep go1.8 || exit | ||||
| go version |grep go1.9 || exit | ||||
| VERSION=$(git describe --tags) | ||||
| mkdir ci/binaries | ||||
| GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-win64.exe | ||||
| GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-linux64 | ||||
| GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-windows-amd64.exe | ||||
| GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-linux-amd64 | ||||
| GOOS=linux GOARCH=arm go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-linux-arm | ||||
| GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o ci/binaries/matterbridge-$VERSION-darwin-amd64 | ||||
| cd ci | ||||
| cat > deploy.json <<EOF | ||||
| { | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import ( | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	//	"github.com/davecgh/go-spew/spew" | ||||
| 	"github.com/hashicorp/golang-lru" | ||||
| 	"github.com/peterhellberg/emojilib" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| @@ -21,11 +22,19 @@ type Gateway struct { | ||||
| 	ChannelOptions map[string]config.ChannelOptions | ||||
| 	Message        chan config.Message | ||||
| 	Name           string | ||||
| 	Messages       *lru.Cache | ||||
| } | ||||
|  | ||||
| type BrMsgID struct { | ||||
| 	br *bridge.Bridge | ||||
| 	ID string | ||||
| } | ||||
|  | ||||
| func New(cfg config.Gateway, r *Router) *Gateway { | ||||
| 	gw := &Gateway{Channels: make(map[string]*config.ChannelInfo), Message: r.Message, | ||||
| 		Router: r, Bridges: make(map[string]*bridge.Bridge), Config: r.Config} | ||||
| 	cache, _ := lru.New(5000) | ||||
| 	gw.Messages = cache | ||||
| 	gw.AddConfig(&cfg) | ||||
| 	return gw | ||||
| } | ||||
| @@ -136,15 +145,27 @@ func (gw *Gateway) getDestChannel(msg *config.Message, dest bridge.Bridge) []con | ||||
| 	return channels | ||||
| } | ||||
|  | ||||
| func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) { | ||||
| func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) []*BrMsgID { | ||||
| 	var brMsgIDs []*BrMsgID | ||||
|  | ||||
| 	// TODO refactor | ||||
| 	// only slack now, check will have to be done in the different bridges. | ||||
| 	// we need to check if we can't use fallback or text in other bridges | ||||
| 	if msg.Extra != nil { | ||||
| 		if dest.Protocol != "slack" { | ||||
| 			if msg.Text == "" { | ||||
| 				return brMsgIDs | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	// only relay join/part when configged | ||||
| 	if msg.Event == config.EVENT_JOIN_LEAVE && !gw.Bridges[dest.Account].Config.ShowJoinPart { | ||||
| 		return | ||||
| 		return brMsgIDs | ||||
| 	} | ||||
| 	// broadcast to every out channel (irc QUIT) | ||||
| 	if msg.Channel == "" && msg.Event != config.EVENT_JOIN_LEAVE { | ||||
| 		log.Debug("empty channel") | ||||
| 		return | ||||
| 		return brMsgIDs | ||||
| 	} | ||||
| 	originchannel := msg.Channel | ||||
| 	origmsg := msg | ||||
| @@ -158,15 +179,29 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) { | ||||
| 		msg.Channel = channel.Name | ||||
| 		msg.Avatar = gw.modifyAvatar(origmsg, dest) | ||||
| 		msg.Username = gw.modifyUsername(origmsg, dest) | ||||
| 		msg.ID = "" | ||||
| 		if res, ok := gw.Messages.Get(origmsg.ID); ok { | ||||
| 			IDs := res.([]*BrMsgID) | ||||
| 			for _, id := range IDs { | ||||
| 				if dest.Protocol == id.br.Protocol { | ||||
| 					msg.ID = id.ID | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		// for api we need originchannel as channel | ||||
| 		if dest.Protocol == "api" { | ||||
| 			msg.Channel = originchannel | ||||
| 		} | ||||
| 		err := dest.Send(msg) | ||||
| 		mID, err := dest.Send(msg) | ||||
| 		if err != nil { | ||||
| 			fmt.Println(err) | ||||
| 		} | ||||
| 		// append the message ID (mID) from this bridge (dest) to our brMsgIDs slice | ||||
| 		if mID != "" { | ||||
| 			brMsgIDs = append(brMsgIDs, &BrMsgID{dest, mID}) | ||||
| 		} | ||||
| 	} | ||||
| 	return brMsgIDs | ||||
| } | ||||
|  | ||||
| func (gw *Gateway) ignoreMessage(msg *config.Message) bool { | ||||
| @@ -175,6 +210,10 @@ func (gw *Gateway) ignoreMessage(msg *config.Message) bool { | ||||
| 		return true | ||||
| 	} | ||||
| 	if msg.Text == "" { | ||||
| 		// we have an attachment | ||||
| 		if msg.Extra != nil && msg.Extra["attachments"] != nil { | ||||
| 			return false | ||||
| 		} | ||||
| 		log.Debugf("ignoring empty message %#v from %s", msg, msg.Account) | ||||
| 		return true | ||||
| 	} | ||||
|   | ||||
| @@ -94,11 +94,17 @@ func (r *Router) handleReceive() { | ||||
| 			} | ||||
| 		} | ||||
| 		for _, gw := range r.Gateways { | ||||
| 			// record all the message ID's of the different bridges | ||||
| 			var msgIDs []*BrMsgID | ||||
| 			if !gw.ignoreMessage(&msg) { | ||||
| 				msg.Timestamp = time.Now() | ||||
| 				gw.modifyMessage(&msg) | ||||
| 				for _, br := range gw.Bridges { | ||||
| 					gw.handleMessage(msg, br) | ||||
| 					msgIDs = append(msgIDs, gw.handleMessage(msg, br)...) | ||||
| 				} | ||||
| 				// only add the message ID if it doesn't already exists | ||||
| 				if _, ok := gw.Messages.Get(msg.ID); !ok && msg.ID != "" { | ||||
| 					gw.Messages.Add(msg.ID, msgIDs) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -11,7 +11,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	version = "1.0.1" | ||||
| 	version = "1.3.0" | ||||
| 	githash string | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -32,16 +32,38 @@ UseSASL=false | ||||
| #OPTIONAL (default false) | ||||
| SkipTLSVerify=true | ||||
|  | ||||
| #If you know your charset, you can specify it manually.  | ||||
| #Otherwise it tries to detect this automatically. Select one below | ||||
| # "iso-8859-2:1987", "iso-8859-9:1989", "866", "latin9", "iso-8859-10:1992", "iso-ir-109", "hebrew",  | ||||
| # "cp932", "iso-8859-15", "cp437", "utf-16be", "iso-8859-3:1988", "windows-1251", "utf16", "latin6",  | ||||
| # "latin3", "iso-8859-1:1987", "iso-8859-9", "utf-16le", "big5", "cp819", "asmo-708", "utf-8",  | ||||
| # "ibm437", "iso-ir-157", "iso-ir-144", "latin4", "850", "iso-8859-5", "iso-8859-5:1988", "l3",  | ||||
| # "windows-31j", "utf8", "iso-8859-3", "437", "greek", "iso-8859-8", "l6", "l9-iso-8859-15",  | ||||
| # "iso-8859-2", "latin2", "iso-ir-100", "iso-8859-6", "arabic", "iso-ir-148", "us-ascii", "x-sjis",  | ||||
| # "utf16be", "iso-8859-8:1988", "utf16le", "l4", "utf-16", "iso-ir-138", "iso-8859-7", "iso-8859-7:1987",  | ||||
| # "windows-1252", "l2", "koi8-r", "iso8859-1", "latin1", "ecma-114", "iso-ir-110", "elot-928",  | ||||
| # "iso-ir-126", "iso-8859-1", "iso-ir-127", "cp850", "cyrillic", "greek8", "windows-1250", "iso-latin-1",  | ||||
| # "l5", "ibm866", "cp866", "ms-kanji", "ibm850", "ecma-118", "iso-ir-101", "ibm819", "l1", "iso-8859-6:1987",  | ||||
| # "latin5", "ascii", "sjis", "iso-8859-10", "iso-8859-4", "iso-8859-4:1988", "shift-jis | ||||
| # The select charset will be converted to utf-8 when sent to other bridges. | ||||
| #OPTIONAL (default "") | ||||
| Charset="" | ||||
|  | ||||
| #Your nick on irc.  | ||||
| #REQUIRED | ||||
| Nick="matterbot" | ||||
|  | ||||
| #If you registered your bot with a service like Nickserv on freenode.  | ||||
| #Also being used when UseSASL=true | ||||
| # | ||||
| #Note: if you want do to quakenet auth, set NickServNick="Q@CServe.quakenet.org" | ||||
| #OPTIONAL | ||||
| NickServNick="nickserv" | ||||
| NickServPassword="secret" | ||||
|  | ||||
| #OPTIONAL only used for quakenet auth | ||||
| NickServUsername="username" | ||||
|  | ||||
| #Flood control | ||||
| #Delay in milliseconds between each message send to the IRC server | ||||
| #OPTIONAL (default 1300) | ||||
| @@ -213,6 +235,11 @@ Team="yourteam" | ||||
| Login="yourlogin" | ||||
| Password="yourpass" | ||||
|  | ||||
| #personal access token of the bot. | ||||
| #new feature since mattermost 4.1. See https://docs.mattermost.com/developer/personal-access-tokens.html | ||||
| #OPTIONAL (you can use token instead of login/password) | ||||
| #Token="abcdefghijklm" | ||||
|  | ||||
| #Enable this to make a http connection (instead of https) to your mattermost.  | ||||
| #OPTIONAL (default false) | ||||
| NoTLS=false | ||||
| @@ -361,7 +388,6 @@ WebhookURL="https://hooks.slack.com/services/yourhook" | ||||
| #AND DEDICATED BOT USER WHEN POSSIBLE! | ||||
| #Address to listen on for outgoing webhook requests from slack | ||||
| #See account settings - integrations - outgoing webhooks on slack | ||||
| #This setting will not be used when useAPI is eanbled | ||||
| #webhooks | ||||
| #OPTIONAL | ||||
| WebhookBindAddress="0.0.0.0:9999" | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
|  | ||||
| [mattermost] | ||||
|     [mattermost.work] | ||||
|     useAPI=true | ||||
|     #do not prefix it wit http:// or https:// | ||||
|     Server="yourmattermostserver.domain"  | ||||
|     Team="yourteam" | ||||
|   | ||||
| @@ -9,7 +9,6 @@ import ( | ||||
| 	"net/http" | ||||
| 	"net/http/cookiejar" | ||||
| 	"net/url" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| @@ -45,8 +44,8 @@ type Message struct { | ||||
| type Team struct { | ||||
| 	Team         *model.Team | ||||
| 	Id           string | ||||
| 	Channels     *model.ChannelList | ||||
| 	MoreChannels *model.ChannelList | ||||
| 	Channels     []*model.Channel | ||||
| 	MoreChannels []*model.Channel | ||||
| 	Users        map[string]*model.User | ||||
| } | ||||
|  | ||||
| @@ -55,7 +54,7 @@ type MMClient struct { | ||||
| 	*Credentials | ||||
| 	Team          *Team | ||||
| 	OtherTeams    []*Team | ||||
| 	Client        *model.Client | ||||
| 	Client        *model.Client4 | ||||
| 	User          *model.User | ||||
| 	Users         map[string]*model.User | ||||
| 	MessageChan   chan *Message | ||||
| @@ -109,21 +108,21 @@ func (m *MMClient) Login() error { | ||||
| 		uriScheme = "http://" | ||||
| 	} | ||||
| 	// login to mattermost | ||||
| 	m.Client = model.NewClient(uriScheme + m.Credentials.Server) | ||||
| 	m.Client = model.NewAPIv4Client(uriScheme + m.Credentials.Server) | ||||
| 	m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}, Proxy: http.ProxyFromEnvironment} | ||||
| 	m.Client.HttpClient.Timeout = time.Second * 10 | ||||
|  | ||||
| 	for { | ||||
| 		d := b.Duration() | ||||
| 		// bogus call to get the serverversion | ||||
| 		_, err := m.Client.GetClientProperties() | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("%#v", err.Error()) | ||||
| 		_, resp := m.Client.Logout() | ||||
| 		if resp.Error != nil { | ||||
| 			return fmt.Errorf("%#v", resp.Error.Error()) | ||||
| 		} | ||||
| 		if firstConnection && !supportedVersion(m.Client.ServerVersion) { | ||||
| 			return fmt.Errorf("unsupported mattermost version: %s", m.Client.ServerVersion) | ||||
| 		if firstConnection && !supportedVersion(resp.ServerVersion) { | ||||
| 			return fmt.Errorf("unsupported mattermost version: %s", resp.ServerVersion) | ||||
| 		} | ||||
| 		m.ServerVersion = m.Client.ServerVersion | ||||
| 		m.ServerVersion = resp.ServerVersion | ||||
| 		if m.ServerVersion == "" { | ||||
| 			m.log.Debugf("Server not up yet, reconnecting in %s", d) | ||||
| 			time.Sleep(d) | ||||
| @@ -134,30 +133,33 @@ func (m *MMClient) Login() error { | ||||
| 	} | ||||
| 	b.Reset() | ||||
|  | ||||
| 	var myinfo *model.Result | ||||
| 	var resp *model.Response | ||||
| 	//var myinfo *model.Result | ||||
| 	var appErr *model.AppError | ||||
| 	var logmsg = "trying login" | ||||
| 	for { | ||||
| 		m.log.Debugf("%s %s %s %s", logmsg, m.Credentials.Team, m.Credentials.Login, m.Credentials.Server) | ||||
| 		if strings.Contains(m.Credentials.Pass, model.SESSION_COOKIE_TOKEN) { | ||||
| 			m.log.Debugf(logmsg+" with %s", model.SESSION_COOKIE_TOKEN) | ||||
| 			m.log.Debugf(logmsg + " with token") | ||||
| 			token := strings.Split(m.Credentials.Pass, model.SESSION_COOKIE_TOKEN+"=") | ||||
| 			if len(token) != 2 { | ||||
| 				return errors.New("incorrect MMAUTHTOKEN. valid input is MMAUTHTOKEN=yourtoken") | ||||
| 			} | ||||
| 			m.Client.HttpClient.Jar = m.createCookieJar(token[1]) | ||||
| 			m.Client.MockSession(token[1]) | ||||
| 			myinfo, appErr = m.Client.GetMe("") | ||||
| 			if appErr != nil { | ||||
| 				return errors.New(appErr.DetailedError) | ||||
| 			m.Client.AuthToken = token[1] | ||||
| 			m.Client.AuthType = model.HEADER_BEARER | ||||
| 			m.User, resp = m.Client.GetMe("") | ||||
| 			if resp.Error != nil { | ||||
| 				return resp.Error | ||||
| 			} | ||||
| 			if myinfo.Data.(*model.User) == nil { | ||||
| 			if m.User == nil { | ||||
| 				m.log.Errorf("LOGIN TOKEN: %s is invalid", m.Credentials.Pass) | ||||
| 				return errors.New("invalid " + model.SESSION_COOKIE_TOKEN) | ||||
| 			} | ||||
| 		} else { | ||||
| 			_, appErr = m.Client.Login(m.Credentials.Login, m.Credentials.Pass) | ||||
| 			m.User, resp = m.Client.Login(m.Credentials.Login, m.Credentials.Pass) | ||||
| 		} | ||||
| 		appErr = resp.Error | ||||
| 		if appErr != nil { | ||||
| 			d := b.Duration() | ||||
| 			m.log.Debug(appErr.DetailedError) | ||||
| @@ -185,8 +187,6 @@ func (m *MMClient) Login() error { | ||||
| 	if m.Team == nil { | ||||
| 		return errors.New("team not found") | ||||
| 	} | ||||
| 	// set our team id as default route | ||||
| 	m.Client.SetTeamId(m.Team.Id) | ||||
|  | ||||
| 	m.wsConnect() | ||||
|  | ||||
| @@ -207,7 +207,7 @@ func (m *MMClient) wsConnect() { | ||||
| 	} | ||||
|  | ||||
| 	// setup websocket connection | ||||
| 	wsurl := wsScheme + m.Credentials.Server + model.API_URL_SUFFIX_V3 + "/users/websocket" | ||||
| 	wsurl := wsScheme + m.Credentials.Server + model.API_URL_SUFFIX_V4 + "/websocket" | ||||
| 	header := http.Header{} | ||||
| 	header.Set(model.HEADER_AUTH, "BEARER "+m.Client.AuthToken) | ||||
|  | ||||
| @@ -241,9 +241,9 @@ func (m *MMClient) Logout() error { | ||||
| 		m.log.Debug("Not invalidating session in logout, credential is a token") | ||||
| 		return nil | ||||
| 	} | ||||
| 	_, err := m.Client.Logout() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	_, resp := m.Client.Logout() | ||||
| 	if resp.Error != nil { | ||||
| 		return resp.Error | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| @@ -277,6 +277,13 @@ func (m *MMClient) WsReceiver() { | ||||
| 			// check if we didn't empty the message | ||||
| 			if msg.Text != "" { | ||||
| 				m.MessageChan <- msg | ||||
| 				continue | ||||
| 			} | ||||
| 			// if we have file attached but the message is empty, also send it | ||||
| 			if msg.Post != nil { | ||||
| 				if msg.Text != "" || len(msg.Post.FileIds) > 0 || msg.Post.Type == "slack_attachment" { | ||||
| 					m.MessageChan <- msg | ||||
| 				} | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| @@ -292,7 +299,7 @@ func (m *MMClient) WsReceiver() { | ||||
|  | ||||
| func (m *MMClient) parseMessage(rmsg *Message) { | ||||
| 	switch rmsg.Raw.Event { | ||||
| 	case model.WEBSOCKET_EVENT_POSTED, model.WEBSOCKET_EVENT_POST_EDITED: | ||||
| 	case model.WEBSOCKET_EVENT_POSTED, model.WEBSOCKET_EVENT_POST_EDITED, model.WEBSOCKET_EVENT_POST_DELETED: | ||||
| 		m.parseActionPost(rmsg) | ||||
| 		/* | ||||
| 			case model.ACTION_USER_REMOVED: | ||||
| @@ -349,33 +356,34 @@ func (m *MMClient) parseActionPost(rmsg *Message) { | ||||
| } | ||||
|  | ||||
| func (m *MMClient) UpdateUsers() error { | ||||
| 	mmusers, err := m.Client.GetProfiles(0, 50000, "") | ||||
| 	if err != nil { | ||||
| 		return errors.New(err.DetailedError) | ||||
| 	mmusers, resp := m.Client.GetUsers(0, 50000, "") | ||||
| 	if resp.Error != nil { | ||||
| 		return errors.New(resp.Error.DetailedError) | ||||
| 	} | ||||
| 	m.Lock() | ||||
| 	m.Users = mmusers.Data.(map[string]*model.User) | ||||
| 	for _, user := range mmusers { | ||||
| 		m.Users[user.Id] = user | ||||
| 	} | ||||
| 	m.Unlock() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) UpdateChannels() error { | ||||
| 	mmchannels, err := m.Client.GetChannels("") | ||||
| 	if err != nil { | ||||
| 		return errors.New(err.DetailedError) | ||||
| 	} | ||||
| 	var mmchannels2 *model.Result | ||||
| 	if m.mmVersion() >= 3.08 { | ||||
| 		mmchannels2, err = m.Client.GetMoreChannelsPage(0, 5000) | ||||
| 	} else { | ||||
| 		mmchannels2, err = m.Client.GetMoreChannels("") | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return errors.New(err.DetailedError) | ||||
| 	mmchannels, resp := m.Client.GetChannelsForTeamForUser(m.Team.Id, m.User.Id, "") | ||||
| 	if resp.Error != nil { | ||||
| 		return errors.New(resp.Error.DetailedError) | ||||
| 	} | ||||
| 	m.Lock() | ||||
| 	m.Team.Channels = mmchannels.Data.(*model.ChannelList) | ||||
| 	m.Team.MoreChannels = mmchannels2.Data.(*model.ChannelList) | ||||
| 	m.Team.Channels = mmchannels | ||||
| 	m.Unlock() | ||||
|  | ||||
| 	mmchannels, resp = m.Client.GetPublicChannelsForTeam(m.Team.Id, 0, 5000, "") | ||||
| 	if resp.Error != nil { | ||||
| 		return errors.New(resp.Error.DetailedError) | ||||
| 	} | ||||
|  | ||||
| 	m.Lock() | ||||
| 	m.Team.MoreChannels = mmchannels | ||||
| 	m.Unlock() | ||||
| 	return nil | ||||
| } | ||||
| @@ -388,14 +396,14 @@ func (m *MMClient) GetChannelName(channelId string) string { | ||||
| 			continue | ||||
| 		} | ||||
| 		if t.Channels != nil { | ||||
| 			for _, channel := range *t.Channels { | ||||
| 			for _, channel := range t.Channels { | ||||
| 				if channel.Id == channelId { | ||||
| 					return channel.Name | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		if t.MoreChannels != nil { | ||||
| 			for _, channel := range *t.MoreChannels { | ||||
| 			for _, channel := range t.MoreChannels { | ||||
| 				if channel.Id == channelId { | ||||
| 					return channel.Name | ||||
| 				} | ||||
| @@ -413,7 +421,7 @@ func (m *MMClient) GetChannelId(name string, teamId string) string { | ||||
| 	} | ||||
| 	for _, t := range m.OtherTeams { | ||||
| 		if t.Id == teamId { | ||||
| 			for _, channel := range append(*t.Channels, *t.MoreChannels...) { | ||||
| 			for _, channel := range append(t.Channels, t.MoreChannels...) { | ||||
| 				if channel.Name == name { | ||||
| 					return channel.Id | ||||
| 				} | ||||
| @@ -427,7 +435,7 @@ func (m *MMClient) GetChannelTeamId(id string) string { | ||||
| 	m.RLock() | ||||
| 	defer m.RUnlock() | ||||
| 	for _, t := range append(m.OtherTeams, m.Team) { | ||||
| 		for _, channel := range append(*t.Channels, *t.MoreChannels...) { | ||||
| 		for _, channel := range append(t.Channels, t.MoreChannels...) { | ||||
| 			if channel.Id == id { | ||||
| 				return channel.TeamId | ||||
| 			} | ||||
| @@ -440,7 +448,7 @@ func (m *MMClient) GetChannelHeader(channelId string) string { | ||||
| 	m.RLock() | ||||
| 	defer m.RUnlock() | ||||
| 	for _, t := range m.OtherTeams { | ||||
| 		for _, channel := range append(*t.Channels, *t.MoreChannels...) { | ||||
| 		for _, channel := range append(t.Channels, t.MoreChannels...) { | ||||
| 			if channel.Id == channelId { | ||||
| 				return channel.Header | ||||
| 			} | ||||
| @@ -450,55 +458,85 @@ func (m *MMClient) GetChannelHeader(channelId string) string { | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (m *MMClient) PostMessage(channelId string, text string) { | ||||
| func (m *MMClient) PostMessage(channelId string, text string) (string, error) { | ||||
| 	post := &model.Post{ChannelId: channelId, Message: text} | ||||
| 	m.Client.CreatePost(post) | ||||
| 	res, resp := m.Client.CreatePost(post) | ||||
| 	if resp.Error != nil { | ||||
| 		return "", resp.Error | ||||
| 	} | ||||
| 	return res.Id, nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) PostMessageWithFiles(channelId string, text string, fileIds []string) (string, error) { | ||||
| 	post := &model.Post{ChannelId: channelId, Message: text, FileIds: fileIds} | ||||
| 	res, resp := m.Client.CreatePost(post) | ||||
| 	if resp.Error != nil { | ||||
| 		return "", resp.Error | ||||
| 	} | ||||
| 	return res.Id, nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) EditMessage(postId string, text string) (string, error) { | ||||
| 	post := &model.Post{Message: text} | ||||
| 	res, resp := m.Client.UpdatePost(postId, post) | ||||
| 	if resp.Error != nil { | ||||
| 		return "", resp.Error | ||||
| 	} | ||||
| 	return res.Id, nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) DeleteMessage(postId string) error { | ||||
| 	_, resp := m.Client.DeletePost(postId) | ||||
| 	if resp.Error != nil { | ||||
| 		return resp.Error | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) JoinChannel(channelId string) error { | ||||
| 	m.RLock() | ||||
| 	defer m.RUnlock() | ||||
| 	for _, c := range *m.Team.Channels { | ||||
| 	for _, c := range m.Team.Channels { | ||||
| 		if c.Id == channelId { | ||||
| 			m.log.Debug("Not joining ", channelId, " already joined.") | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| 	m.log.Debug("Joining ", channelId) | ||||
| 	_, err := m.Client.JoinChannel(channelId) | ||||
| 	if err != nil { | ||||
| 		return errors.New("failed to join") | ||||
| 	_, resp := m.Client.AddChannelMember(channelId, m.User.Id) | ||||
| 	if resp.Error != nil { | ||||
| 		return resp.Error | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetPostsSince(channelId string, time int64) *model.PostList { | ||||
| 	res, err := m.Client.GetPostsSince(channelId, time) | ||||
| 	if err != nil { | ||||
| 	res, resp := m.Client.GetPostsSince(channelId, time) | ||||
| 	if resp.Error != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return res.Data.(*model.PostList) | ||||
| 	return res | ||||
| } | ||||
|  | ||||
| func (m *MMClient) SearchPosts(query string) *model.PostList { | ||||
| 	res, err := m.Client.SearchPosts(query, false) | ||||
| 	if err != nil { | ||||
| 	res, resp := m.Client.SearchPosts(m.Team.Id, query, false) | ||||
| 	if resp.Error != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return res.Data.(*model.PostList) | ||||
| 	return res | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetPosts(channelId string, limit int) *model.PostList { | ||||
| 	res, err := m.Client.GetPosts(channelId, 0, limit, "") | ||||
| 	if err != nil { | ||||
| 	res, resp := m.Client.GetPostsForChannel(channelId, 0, limit, "") | ||||
| 	if resp.Error != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return res.Data.(*model.PostList) | ||||
| 	return res | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetPublicLink(filename string) string { | ||||
| 	res, err := m.Client.GetPublicLink(filename) | ||||
| 	if err != nil { | ||||
| 	res, resp := m.Client.GetFileLink(filename) | ||||
| 	if resp.Error != nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return res | ||||
| @@ -507,8 +545,8 @@ func (m *MMClient) GetPublicLink(filename string) string { | ||||
| func (m *MMClient) GetPublicLinks(filenames []string) []string { | ||||
| 	var output []string | ||||
| 	for _, f := range filenames { | ||||
| 		res, err := m.Client.GetPublicLink(f) | ||||
| 		if err != nil { | ||||
| 		res, resp := m.Client.GetFileLink(f) | ||||
| 		if resp.Error != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		output = append(output, res) | ||||
| @@ -524,8 +562,8 @@ func (m *MMClient) GetFileLinks(filenames []string) []string { | ||||
|  | ||||
| 	var output []string | ||||
| 	for _, f := range filenames { | ||||
| 		res, err := m.Client.GetPublicLink(f) | ||||
| 		if err != nil { | ||||
| 		res, resp := m.Client.GetFileLink(f) | ||||
| 		if resp.Error != nil { | ||||
| 			// public links is probably disabled, create the link ourselves | ||||
| 			output = append(output, uriScheme+m.Credentials.Server+model.API_URL_SUFFIX_V3+"/files/"+f+"/get") | ||||
| 			continue | ||||
| @@ -536,42 +574,43 @@ func (m *MMClient) GetFileLinks(filenames []string) []string { | ||||
| } | ||||
|  | ||||
| func (m *MMClient) UpdateChannelHeader(channelId string, header string) { | ||||
| 	data := make(map[string]string) | ||||
| 	data["channel_id"] = channelId | ||||
| 	data["channel_header"] = header | ||||
| 	channel := &model.Channel{Id: channelId, Header: header} | ||||
| 	m.log.Debugf("updating channelheader %#v, %#v", channelId, header) | ||||
| 	_, err := m.Client.UpdateChannelHeader(data) | ||||
| 	if err != nil { | ||||
| 		log.Error(err) | ||||
| 	_, resp := m.Client.UpdateChannel(channel) | ||||
| 	if resp.Error != nil { | ||||
| 		log.Error(resp.Error) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *MMClient) UpdateLastViewed(channelId string) { | ||||
| 	m.log.Debugf("posting lastview %#v", channelId) | ||||
| 	if m.mmVersion() >= 3.08 { | ||||
| 		view := model.ChannelView{ChannelId: channelId} | ||||
| 		res, _ := m.Client.ViewChannel(view) | ||||
| 		if !res { | ||||
| 			m.log.Errorf("ChannelView update for %s failed", channelId) | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	_, err := m.Client.UpdateLastViewedAt(channelId, true) | ||||
| 	if err != nil { | ||||
| 		m.log.Error(err) | ||||
| 	view := &model.ChannelView{ChannelId: channelId} | ||||
| 	res, _ := m.Client.ViewChannel(m.User.Id, view) | ||||
| 	if !res { | ||||
| 		m.log.Errorf("ChannelView update for %s failed", channelId) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (m *MMClient) UpdateUserNick(nick string) error { | ||||
| 	user := m.User | ||||
| 	user.Nickname = nick | ||||
| 	_, resp := m.Client.UpdateUser(user) | ||||
| 	if resp.Error != nil { | ||||
| 		return resp.Error | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) UsernamesInChannel(channelId string) []string { | ||||
| 	res, err := m.Client.GetProfilesInChannel(channelId, 0, 50000, "") | ||||
| 	if err != nil { | ||||
| 		m.log.Errorf("UsernamesInChannel(%s) failed: %s", channelId, err) | ||||
| 	res, resp := m.Client.GetChannelMembers(channelId, 0, 50000, "") | ||||
| 	if resp.Error != nil { | ||||
| 		m.log.Errorf("UsernamesInChannel(%s) failed: %s", channelId, resp.Error) | ||||
| 		return []string{} | ||||
| 	} | ||||
| 	members := res.Data.(map[string]*model.User) | ||||
| 	allusers := m.GetUsers() | ||||
| 	result := []string{} | ||||
| 	for _, member := range members { | ||||
| 		result = append(result, member.Nickname) | ||||
| 	for _, member := range *res { | ||||
| 		result = append(result, allusers[member.UserId].Nickname) | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
| @@ -595,22 +634,15 @@ func (m *MMClient) createCookieJar(token string) *cookiejar.Jar { | ||||
| func (m *MMClient) SendDirectMessage(toUserId string, msg string) { | ||||
| 	m.log.Debugf("SendDirectMessage to %s, msg %s", toUserId, msg) | ||||
| 	// create DM channel (only happens on first message) | ||||
| 	_, err := m.Client.CreateDirectChannel(toUserId) | ||||
| 	if err != nil { | ||||
| 		m.log.Debugf("SendDirectMessage to %#v failed: %s", toUserId, err) | ||||
| 	_, resp := m.Client.CreateDirectChannel(m.User.Id, toUserId) | ||||
| 	if resp.Error != nil { | ||||
| 		m.log.Debugf("SendDirectMessage to %#v failed: %s", toUserId, resp.Error) | ||||
| 		return | ||||
| 	} | ||||
| 	channelName := model.GetDMNameFromIds(toUserId, m.User.Id) | ||||
|  | ||||
| 	// update our channels | ||||
| 	mmchannels, err := m.Client.GetChannels("") | ||||
| 	if err != nil { | ||||
| 		m.log.Debug("SendDirectMessage: Couldn't update channels") | ||||
| 		return | ||||
| 	} | ||||
| 	m.Lock() | ||||
| 	m.Team.Channels = mmchannels.Data.(*model.ChannelList) | ||||
| 	m.Unlock() | ||||
| 	m.UpdateChannels() | ||||
|  | ||||
| 	// build & send the message | ||||
| 	msg = strings.Replace(msg, "\r", "", -1) | ||||
| @@ -636,10 +668,10 @@ func (m *MMClient) GetChannels() []*model.Channel { | ||||
| 	defer m.RUnlock() | ||||
| 	var channels []*model.Channel | ||||
| 	// our primary team channels first | ||||
| 	channels = append(channels, *m.Team.Channels...) | ||||
| 	channels = append(channels, m.Team.Channels...) | ||||
| 	for _, t := range m.OtherTeams { | ||||
| 		if t.Id != m.Team.Id { | ||||
| 			channels = append(channels, *t.Channels...) | ||||
| 			channels = append(channels, t.Channels...) | ||||
| 		} | ||||
| 	} | ||||
| 	return channels | ||||
| @@ -651,7 +683,7 @@ func (m *MMClient) GetMoreChannels() []*model.Channel { | ||||
| 	defer m.RUnlock() | ||||
| 	var channels []*model.Channel | ||||
| 	for _, t := range m.OtherTeams { | ||||
| 		channels = append(channels, *t.MoreChannels...) | ||||
| 		channels = append(channels, t.MoreChannels...) | ||||
| 	} | ||||
| 	return channels | ||||
| } | ||||
| @@ -662,9 +694,9 @@ func (m *MMClient) GetTeamFromChannel(channelId string) string { | ||||
| 	defer m.RUnlock() | ||||
| 	var channels []*model.Channel | ||||
| 	for _, t := range m.OtherTeams { | ||||
| 		channels = append(channels, *t.Channels...) | ||||
| 		channels = append(channels, t.Channels...) | ||||
| 		if t.MoreChannels != nil { | ||||
| 			channels = append(channels, *t.MoreChannels...) | ||||
| 			channels = append(channels, t.MoreChannels...) | ||||
| 		} | ||||
| 		for _, c := range channels { | ||||
| 			if c.Id == channelId { | ||||
| @@ -678,12 +710,11 @@ func (m *MMClient) GetTeamFromChannel(channelId string) string { | ||||
| func (m *MMClient) GetLastViewedAt(channelId string) int64 { | ||||
| 	m.RLock() | ||||
| 	defer m.RUnlock() | ||||
| 	res, err := m.Client.GetChannel(channelId, "") | ||||
| 	if err != nil { | ||||
| 	res, resp := m.Client.GetChannelMember(channelId, m.User.Id, "") | ||||
| 	if resp.Error != nil { | ||||
| 		return model.GetMillis() | ||||
| 	} | ||||
| 	data := res.Data.(*model.ChannelData) | ||||
| 	return data.Member.LastViewedAt | ||||
| 	return res.LastViewedAt | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetUsers() map[string]*model.User { | ||||
| @@ -701,12 +732,11 @@ func (m *MMClient) GetUser(userId string) *model.User { | ||||
| 	defer m.Unlock() | ||||
| 	_, ok := m.Users[userId] | ||||
| 	if !ok { | ||||
| 		res, err := m.Client.GetProfilesByIds([]string{userId}) | ||||
| 		if err != nil { | ||||
| 		res, resp := m.Client.GetUser(userId, "") | ||||
| 		if resp.Error != nil { | ||||
| 			return nil | ||||
| 		} | ||||
| 		u := res.Data.(map[string]*model.User)[userId] | ||||
| 		m.Users[userId] = u | ||||
| 		m.Users[userId] = res | ||||
| 	} | ||||
| 	return m.Users[userId] | ||||
| } | ||||
| @@ -720,36 +750,36 @@ func (m *MMClient) GetUserName(userId string) string { | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetStatus(userId string) string { | ||||
| 	res, err := m.Client.GetStatusesByIds([]string{userId}) | ||||
| 	if err != nil { | ||||
| 	res, resp := m.Client.GetUserStatus(userId, "") | ||||
| 	if resp.Error != nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	status := res.Data.(map[string]string) | ||||
| 	if status[userId] == model.STATUS_AWAY { | ||||
| 	if res.Status == model.STATUS_AWAY { | ||||
| 		return "away" | ||||
| 	} | ||||
| 	if status[userId] == model.STATUS_ONLINE { | ||||
| 	if res.Status == model.STATUS_ONLINE { | ||||
| 		return "online" | ||||
| 	} | ||||
| 	return "offline" | ||||
| } | ||||
|  | ||||
| func (m *MMClient) GetStatuses() map[string]string { | ||||
| 	var ok bool | ||||
| 	var ids []string | ||||
| 	statuses := make(map[string]string) | ||||
| 	res, err := m.Client.GetStatuses() | ||||
| 	if err != nil { | ||||
| 	for id := range m.Users { | ||||
| 		ids = append(ids, id) | ||||
| 	} | ||||
| 	res, resp := m.Client.GetUsersStatusesByIds(ids) | ||||
| 	if resp.Error != nil { | ||||
| 		return statuses | ||||
| 	} | ||||
| 	if statuses, ok = res.Data.(map[string]string); ok { | ||||
| 		for userId, status := range statuses { | ||||
| 			statuses[userId] = "offline" | ||||
| 			if status == model.STATUS_AWAY { | ||||
| 				statuses[userId] = "away" | ||||
| 			} | ||||
| 			if status == model.STATUS_ONLINE { | ||||
| 				statuses[userId] = "online" | ||||
| 			} | ||||
| 	for _, status := range res { | ||||
| 		statuses[status.UserId] = "offline" | ||||
| 		if status.Status == model.STATUS_AWAY { | ||||
| 			statuses[status.UserId] = "away" | ||||
| 		} | ||||
| 		if status.Status == model.STATUS_ONLINE { | ||||
| 			statuses[status.UserId] = "online" | ||||
| 		} | ||||
| 	} | ||||
| 	return statuses | ||||
| @@ -759,6 +789,14 @@ func (m *MMClient) GetTeamId() string { | ||||
| 	return m.Team.Id | ||||
| } | ||||
|  | ||||
| func (m *MMClient) UploadFile(data []byte, channelId string, filename string) (string, error) { | ||||
| 	f, resp := m.Client.UploadFile(data, channelId, filename) | ||||
| 	if resp.Error != nil { | ||||
| 		return "", resp.Error | ||||
| 	} | ||||
| 	return f.FileInfos[0].Id, nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) StatusLoop() { | ||||
| 	retries := 0 | ||||
| 	backoff := time.Second * 60 | ||||
| @@ -800,40 +838,39 @@ func (m *MMClient) StatusLoop() { | ||||
| func (m *MMClient) initUser() error { | ||||
| 	m.Lock() | ||||
| 	defer m.Unlock() | ||||
| 	initLoad, err := m.Client.GetInitialLoad() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	initData := initLoad.Data.(*model.InitialLoad) | ||||
| 	m.User = initData.User | ||||
| 	// we only load all team data on initial login. | ||||
| 	// all other updates are for channels from our (primary) team only. | ||||
| 	//m.log.Debug("initUser(): loading all team data") | ||||
| 	for _, v := range initData.Teams { | ||||
| 		m.Client.SetTeamId(v.Id) | ||||
| 		mmusers, err := m.Client.GetProfiles(0, 50000, "") | ||||
| 		if err != nil { | ||||
| 			return errors.New(err.DetailedError) | ||||
| 	teams, resp := m.Client.GetTeamsForUser(m.User.Id, "") | ||||
| 	if resp.Error != nil { | ||||
| 		return resp.Error | ||||
| 	} | ||||
| 	for _, team := range teams { | ||||
| 		mmusers, resp := m.Client.GetUsersInTeam(team.Id, 0, 50000, "") | ||||
| 		if resp.Error != nil { | ||||
| 			return errors.New(resp.Error.DetailedError) | ||||
| 		} | ||||
| 		t := &Team{Team: v, Users: mmusers.Data.(map[string]*model.User), Id: v.Id} | ||||
| 		mmchannels, err := m.Client.GetChannels("") | ||||
| 		if err != nil { | ||||
| 			return errors.New(err.DetailedError) | ||||
| 		usermap := make(map[string]*model.User) | ||||
| 		for _, user := range mmusers { | ||||
| 			usermap[user.Id] = user | ||||
| 		} | ||||
| 		t.Channels = mmchannels.Data.(*model.ChannelList) | ||||
| 		if m.mmVersion() >= 3.08 { | ||||
| 			mmchannels, err = m.Client.GetMoreChannelsPage(0, 5000) | ||||
| 		} else { | ||||
| 			mmchannels, err = m.Client.GetMoreChannels("") | ||||
|  | ||||
| 		t := &Team{Team: team, Users: usermap, Id: team.Id} | ||||
|  | ||||
| 		mmchannels, resp := m.Client.GetChannelsForTeamForUser(team.Id, m.User.Id, "") | ||||
| 		if resp.Error != nil { | ||||
| 			return resp.Error | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return errors.New(err.DetailedError) | ||||
| 		t.Channels = mmchannels | ||||
| 		mmchannels, resp = m.Client.GetPublicChannelsForTeam(team.Id, 0, 5000, "") | ||||
| 		if resp.Error != nil { | ||||
| 			return resp.Error | ||||
| 		} | ||||
| 		t.MoreChannels = mmchannels.Data.(*model.ChannelList) | ||||
| 		t.MoreChannels = mmchannels | ||||
| 		m.OtherTeams = append(m.OtherTeams, t) | ||||
| 		if v.Name == m.Credentials.Team { | ||||
| 		if team.Name == m.Credentials.Team { | ||||
| 			m.Team = t | ||||
| 			m.log.Debugf("initUser(): found our team %s (id: %s)", v.Name, v.Id) | ||||
| 			m.log.Debugf("initUser(): found our team %s (id: %s)", team.Name, team.Id) | ||||
| 		} | ||||
| 		// add all users | ||||
| 		for k, v := range t.Users { | ||||
| @@ -854,23 +891,13 @@ func (m *MMClient) sendWSRequest(action string, data map[string]interface{}) err | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *MMClient) mmVersion() float64 { | ||||
| 	v, _ := strconv.ParseFloat(string(m.ServerVersion[0:2])+"0"+string(m.ServerVersion[2]), 64) | ||||
| 	if string(m.ServerVersion[4]) == "." { | ||||
| 		v, _ = strconv.ParseFloat(m.ServerVersion[0:4], 64) | ||||
| 	} | ||||
| 	return v | ||||
| } | ||||
|  | ||||
| func supportedVersion(version string) bool { | ||||
| 	if strings.HasPrefix(version, "3.5.0") || | ||||
| 		strings.HasPrefix(version, "3.6.0") || | ||||
| 		strings.HasPrefix(version, "3.7.0") || | ||||
| 		strings.HasPrefix(version, "3.8.0") || | ||||
| 	if strings.HasPrefix(version, "3.8.0") || | ||||
| 		strings.HasPrefix(version, "3.9.0") || | ||||
| 		strings.HasPrefix(version, "3.10.0") || | ||||
| 		strings.HasPrefix(version, "4.0") || | ||||
| 		strings.HasPrefix(version, "4.1") { | ||||
| 		strings.HasPrefix(version, "4.1") || | ||||
| 		strings.HasPrefix(version, "4.2") { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
|   | ||||
| @@ -17,13 +17,14 @@ import ( | ||||
|  | ||||
| // OMessage for mattermost incoming webhook. (send to mattermost) | ||||
| type OMessage struct { | ||||
| 	Channel     string      `json:"channel,omitempty"` | ||||
| 	IconURL     string      `json:"icon_url,omitempty"` | ||||
| 	IconEmoji   string      `json:"icon_emoji,omitempty"` | ||||
| 	UserName    string      `json:"username,omitempty"` | ||||
| 	Text        string      `json:"text"` | ||||
| 	Attachments interface{} `json:"attachments,omitempty"` | ||||
| 	Type        string      `json:"type,omitempty"` | ||||
| 	Channel     string                 `json:"channel,omitempty"` | ||||
| 	IconURL     string                 `json:"icon_url,omitempty"` | ||||
| 	IconEmoji   string                 `json:"icon_emoji,omitempty"` | ||||
| 	UserName    string                 `json:"username,omitempty"` | ||||
| 	Text        string                 `json:"text"` | ||||
| 	Attachments interface{}            `json:"attachments,omitempty"` | ||||
| 	Type        string                 `json:"type,omitempty"` | ||||
| 	Props       map[string]interface{} `json:"props"` | ||||
| } | ||||
|  | ||||
| // IMessage for mattermost outgoing webhook. (received from mattermost) | ||||
|   | ||||
| @@ -205,17 +205,43 @@ func (gitter *Gitter) GetMessage(roomID, messageID string) (*Message, error) { | ||||
| } | ||||
| 
 | ||||
| // SendMessage sends a message to a room | ||||
| func (gitter *Gitter) SendMessage(roomID, text string) error { | ||||
| func (gitter *Gitter) SendMessage(roomID, text string) (*Message, error) { | ||||
| 
 | ||||
| 	message := Message{Text: text} | ||||
| 	body, _ := json.Marshal(message) | ||||
| 	_, err := gitter.post(gitter.config.apiBaseURL+"rooms/"+roomID+"/chatMessages", body) | ||||
| 	response, err := gitter.post(gitter.config.apiBaseURL+"rooms/"+roomID+"/chatMessages", body) | ||||
| 	if err != nil { | ||||
| 		gitter.log(err) | ||||
| 		return err | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| 	err = json.Unmarshal(response, &message) | ||||
| 	if err != nil { | ||||
| 		gitter.log(err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return &message, nil | ||||
| } | ||||
| 
 | ||||
| // UpdateMessage updates a message in a room | ||||
| func (gitter *Gitter) UpdateMessage(roomID, msgID, text string) (*Message, error) { | ||||
| 
 | ||||
| 	message := Message{Text: text} | ||||
| 	body, _ := json.Marshal(message) | ||||
| 	response, err := gitter.put(gitter.config.apiBaseURL+"rooms/"+roomID+"/chatMessages/"+msgID, body) | ||||
| 	if err != nil { | ||||
| 		gitter.log(err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	err = json.Unmarshal(response, &message) | ||||
| 	if err != nil { | ||||
| 		gitter.log(err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return &message, nil | ||||
| } | ||||
| 
 | ||||
| // JoinRoom joins a room | ||||
| @@ -265,7 +291,7 @@ func (gitter *Gitter) SearchRooms(room string) ([]Room, error) { | ||||
| 		Results []Room `json:"results"` | ||||
| 	} | ||||
| 
 | ||||
| 	response, err := gitter.get(gitter.config.apiBaseURL + "rooms?q=" + room ) | ||||
| 	response, err := gitter.get(gitter.config.apiBaseURL + "rooms?q=" + room) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		gitter.log(err) | ||||
| @@ -414,6 +440,39 @@ func (gitter *Gitter) post(url string, body []byte) ([]byte, error) { | ||||
| 	return result, nil | ||||
| } | ||||
| 
 | ||||
| func (gitter *Gitter) put(url string, body []byte) ([]byte, error) { | ||||
| 	r, err := http.NewRequest("PUT", url, bytes.NewBuffer(body)) | ||||
| 	if err != nil { | ||||
| 		gitter.log(err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	r.Header.Set("Content-Type", "application/json") | ||||
| 	r.Header.Set("Accept", "application/json") | ||||
| 	r.Header.Set("Authorization", "Bearer "+gitter.config.token) | ||||
| 
 | ||||
| 	resp, err := gitter.config.client.Do(r) | ||||
| 	if err != nil { | ||||
| 		gitter.log(err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
| 
 | ||||
| 	if resp.StatusCode != http.StatusOK { | ||||
| 		err = APIError{What: fmt.Sprintf("Status code: %v", resp.StatusCode)} | ||||
| 		gitter.log(err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	result, err := ioutil.ReadAll(resp.Body) | ||||
| 	if err != nil { | ||||
| 		gitter.log(err) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return result, nil | ||||
| } | ||||
| 
 | ||||
| func (gitter *Gitter) delete(url string) ([]byte, error) { | ||||
| 	r, err := http.NewRequest("delete", url, nil) | ||||
| 	if err != nil { | ||||
							
								
								
									
										6
									
								
								vendor/github.com/42wim/go-ircevent/irc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/42wim/go-ircevent/irc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -227,12 +227,17 @@ func (irc *Connection) isQuitting() bool { | ||||
| // Main loop to control the connection. | ||||
| func (irc *Connection) Loop() { | ||||
| 	errChan := irc.ErrorChan() | ||||
| 	connTime := time.Now() | ||||
| 	for !irc.isQuitting() { | ||||
| 		err := <-errChan | ||||
| 		close(irc.end) | ||||
| 		irc.Wait() | ||||
| 		for !irc.isQuitting() { | ||||
| 			irc.Log.Printf("Error, disconnected: %s\n", err) | ||||
| 			if time.Now().Sub(connTime) < time.Second*5 { | ||||
| 				irc.Log.Println("Rreconnecting too fast, sleeping 60 seconds") | ||||
| 				time.Sleep(60 * time.Second) | ||||
| 			} | ||||
| 			if err = irc.Reconnect(); err != nil { | ||||
| 				irc.Log.Printf("Error while reconnecting: %s\n", err) | ||||
| 				time.Sleep(60 * time.Second) | ||||
| @@ -241,6 +246,7 @@ func (irc *Connection) Loop() { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		connTime = time.Now() | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/bwmarrin/discordgo/discord.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/bwmarrin/discordgo/discord.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -21,7 +21,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| // VERSION of DiscordGo, follows Semantic Versioning. (http://semver.org/) | ||||
| const VERSION = "0.16.0" | ||||
| const VERSION = "0.17.0" | ||||
|  | ||||
| // ErrMFA will be risen by New when the user has 2FA. | ||||
| var ErrMFA = errors.New("account has 2FA enabled") | ||||
| @@ -59,6 +59,7 @@ func New(args ...interface{}) (s *Session, err error) { | ||||
| 		MaxRestRetries:         3, | ||||
| 		Client:                 &http.Client{Timeout: (20 * time.Second)}, | ||||
| 		sequence:               new(int64), | ||||
| 		LastHeartbeatAck:       time.Now().UTC(), | ||||
| 	} | ||||
|  | ||||
| 	// If no arguments are passed return the empty Session interface. | ||||
|   | ||||
							
								
								
									
										42
									
								
								vendor/github.com/bwmarrin/discordgo/endpoints.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								vendor/github.com/bwmarrin/discordgo/endpoints.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -11,6 +11,9 @@ | ||||
|  | ||||
| package discordgo | ||||
|  | ||||
| // APIVersion is the Discord API version used for the REST and Websocket API. | ||||
| var APIVersion = "6" | ||||
|  | ||||
| // Known Discord API Endpoints. | ||||
| var ( | ||||
| 	EndpointStatus     = "https://status.discordapp.com/api/v2/" | ||||
| @@ -18,13 +21,14 @@ var ( | ||||
| 	EndpointSmActive   = EndpointSm + "active.json" | ||||
| 	EndpointSmUpcoming = EndpointSm + "upcoming.json" | ||||
|  | ||||
| 	EndpointDiscord  = "https://discordapp.com/" | ||||
| 	EndpointAPI      = EndpointDiscord + "api/" | ||||
| 	EndpointGuilds   = EndpointAPI + "guilds/" | ||||
| 	EndpointChannels = EndpointAPI + "channels/" | ||||
| 	EndpointUsers    = EndpointAPI + "users/" | ||||
| 	EndpointGateway  = EndpointAPI + "gateway" | ||||
| 	EndpointWebhooks = EndpointAPI + "webhooks/" | ||||
| 	EndpointDiscord    = "https://discordapp.com/" | ||||
| 	EndpointAPI        = EndpointDiscord + "api/v" + APIVersion + "/" | ||||
| 	EndpointGuilds     = EndpointAPI + "guilds/" | ||||
| 	EndpointChannels   = EndpointAPI + "channels/" | ||||
| 	EndpointUsers      = EndpointAPI + "users/" | ||||
| 	EndpointGateway    = EndpointAPI + "gateway" | ||||
| 	EndpointGatewayBot = EndpointGateway + "/bot" | ||||
| 	EndpointWebhooks   = EndpointAPI + "webhooks/" | ||||
|  | ||||
| 	EndpointCDN             = "https://cdn.discordapp.com/" | ||||
| 	EndpointCDNAttachments  = EndpointCDN + "attachments/" | ||||
| @@ -54,16 +58,17 @@ var ( | ||||
| 	EndpointReport       = EndpointAPI + "report" | ||||
| 	EndpointIntegrations = EndpointAPI + "integrations" | ||||
|  | ||||
| 	EndpointUser              = func(uID string) string { return EndpointUsers + uID } | ||||
| 	EndpointUserAvatar        = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" } | ||||
| 	EndpointUserSettings      = func(uID string) string { return EndpointUsers + uID + "/settings" } | ||||
| 	EndpointUserGuilds        = func(uID string) string { return EndpointUsers + uID + "/guilds" } | ||||
| 	EndpointUserGuild         = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID } | ||||
| 	EndpointUserGuildSettings = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID + "/settings" } | ||||
| 	EndpointUserChannels      = func(uID string) string { return EndpointUsers + uID + "/channels" } | ||||
| 	EndpointUserDevices       = func(uID string) string { return EndpointUsers + uID + "/devices" } | ||||
| 	EndpointUserConnections   = func(uID string) string { return EndpointUsers + uID + "/connections" } | ||||
| 	EndpointUserNotes         = func(uID string) string { return EndpointUsers + "@me/notes/" + uID } | ||||
| 	EndpointUser               = func(uID string) string { return EndpointUsers + uID } | ||||
| 	EndpointUserAvatar         = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".png" } | ||||
| 	EndpointUserAvatarAnimated = func(uID, aID string) string { return EndpointCDNAvatars + uID + "/" + aID + ".gif" } | ||||
| 	EndpointUserSettings       = func(uID string) string { return EndpointUsers + uID + "/settings" } | ||||
| 	EndpointUserGuilds         = func(uID string) string { return EndpointUsers + uID + "/guilds" } | ||||
| 	EndpointUserGuild          = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID } | ||||
| 	EndpointUserGuildSettings  = func(uID, gID string) string { return EndpointUsers + uID + "/guilds/" + gID + "/settings" } | ||||
| 	EndpointUserChannels       = func(uID string) string { return EndpointUsers + uID + "/channels" } | ||||
| 	EndpointUserDevices        = func(uID string) string { return EndpointUsers + uID + "/devices" } | ||||
| 	EndpointUserConnections    = func(uID string) string { return EndpointUsers + uID + "/connections" } | ||||
| 	EndpointUserNotes          = func(uID string) string { return EndpointUsers + "@me/notes/" + uID } | ||||
|  | ||||
| 	EndpointGuild                = func(gID string) string { return EndpointGuilds + gID } | ||||
| 	EndpointGuildInivtes         = func(gID string) string { return EndpointGuilds + gID + "/invites" } | ||||
| @@ -103,6 +108,9 @@ var ( | ||||
| 	EndpointWebhook         = func(wID string) string { return EndpointWebhooks + wID } | ||||
| 	EndpointWebhookToken    = func(wID, token string) string { return EndpointWebhooks + wID + "/" + token } | ||||
|  | ||||
| 	EndpointMessageReactionsAll = func(cID, mID string) string { | ||||
| 		return EndpointChannelMessage(cID, mID) + "/reactions" | ||||
| 	} | ||||
| 	EndpointMessageReactions = func(cID, mID, eID string) string { | ||||
| 		return EndpointChannelMessage(cID, mID) + "/reactions/" + eID | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/github.com/bwmarrin/discordgo/event.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/bwmarrin/discordgo/event.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -156,12 +156,20 @@ func (s *Session) removeEventHandlerInstance(t string, ehi *eventHandlerInstance | ||||
| // Handles calling permanent and once handlers for an event type. | ||||
| func (s *Session) handle(t string, i interface{}) { | ||||
| 	for _, eh := range s.handlers[t] { | ||||
| 		go eh.eventHandler.Handle(s, i) | ||||
| 		if s.SyncEvents { | ||||
| 			eh.eventHandler.Handle(s, i) | ||||
| 		} else { | ||||
| 			go eh.eventHandler.Handle(s, i) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(s.onceHandlers[t]) > 0 { | ||||
| 		for _, eh := range s.onceHandlers[t] { | ||||
| 			go eh.eventHandler.Handle(s, i) | ||||
| 			if s.SyncEvents { | ||||
| 				eh.eventHandler.Handle(s, i) | ||||
| 			} else { | ||||
| 				go eh.eventHandler.Handle(s, i) | ||||
| 			} | ||||
| 		} | ||||
| 		s.onceHandlers[t] = nil | ||||
| 	} | ||||
| @@ -216,7 +224,7 @@ func (s *Session) onInterface(i interface{}) { | ||||
| 	case *VoiceStateUpdate: | ||||
| 		go s.onVoiceStateUpdate(t) | ||||
| 	} | ||||
| 	err := s.State.onInterface(s, i) | ||||
| 	err := s.State.OnInterface(s, i) | ||||
| 	if err != nil { | ||||
| 		s.log(LogDebug, "error dispatching internal event, %s", err) | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										94
									
								
								vendor/github.com/bwmarrin/discordgo/message.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										94
									
								
								vendor/github.com/bwmarrin/discordgo/message.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -10,9 +10,24 @@ | ||||
| package discordgo | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // MessageType is the type of Message | ||||
| type MessageType int | ||||
|  | ||||
| // Block contains the valid known MessageType values | ||||
| const ( | ||||
| 	MessageTypeDefault MessageType = iota | ||||
| 	MessageTypeRecipientAdd | ||||
| 	MessageTypeRecipientRemove | ||||
| 	MessageTypeCall | ||||
| 	MessageTypeChannelNameChange | ||||
| 	MessageTypeChannelIconChange | ||||
| 	MessageTypeChannelPinnedMessage | ||||
| 	MessageTypeGuildMemberJoin | ||||
| ) | ||||
|  | ||||
| // A Message stores all data related to a specific Discord message. | ||||
| @@ -30,12 +45,14 @@ type Message struct { | ||||
| 	Embeds          []*MessageEmbed      `json:"embeds"` | ||||
| 	Mentions        []*User              `json:"mentions"` | ||||
| 	Reactions       []*MessageReactions  `json:"reactions"` | ||||
| 	Type            MessageType          `json:"type"` | ||||
| } | ||||
|  | ||||
| // File stores info about files you e.g. send in messages. | ||||
| type File struct { | ||||
| 	Name   string | ||||
| 	Reader io.Reader | ||||
| 	Name        string | ||||
| 	ContentType string | ||||
| 	Reader      io.Reader | ||||
| } | ||||
|  | ||||
| // MessageSend stores all parameters you can send with ChannelMessageSendComplex. | ||||
| @@ -43,7 +60,10 @@ type MessageSend struct { | ||||
| 	Content string        `json:"content,omitempty"` | ||||
| 	Embed   *MessageEmbed `json:"embed,omitempty"` | ||||
| 	Tts     bool          `json:"tts"` | ||||
| 	File    *File         `json:"file"` | ||||
| 	Files   []*File       `json:"-"` | ||||
|  | ||||
| 	// TODO: Remove this when compatibility is not required. | ||||
| 	File *File `json:"-"` | ||||
| } | ||||
|  | ||||
| // MessageEdit is used to chain parameters via ChannelMessageEditComplex, which | ||||
| @@ -168,13 +188,65 @@ type MessageReactions struct { | ||||
|  | ||||
| // ContentWithMentionsReplaced will replace all @<id> mentions with the | ||||
| // username of the mention. | ||||
| func (m *Message) ContentWithMentionsReplaced() string { | ||||
| 	if m.Mentions == nil { | ||||
| 		return m.Content | ||||
| 	} | ||||
| 	content := m.Content | ||||
| func (m *Message) ContentWithMentionsReplaced() (content string) { | ||||
| 	content = m.Content | ||||
|  | ||||
| 	for _, user := range m.Mentions { | ||||
| 		content = regexp.MustCompile(fmt.Sprintf("<@!?(%s)>", user.ID)).ReplaceAllString(content, "@"+user.Username) | ||||
| 		content = strings.NewReplacer( | ||||
| 			"<@"+user.ID+">", "@"+user.Username, | ||||
| 			"<@!"+user.ID+">", "@"+user.Username, | ||||
| 		).Replace(content) | ||||
| 	} | ||||
| 	return content | ||||
| 	return | ||||
| } | ||||
|  | ||||
| var patternChannels = regexp.MustCompile("<#[^>]*>") | ||||
|  | ||||
| // ContentWithMoreMentionsReplaced will replace all @<id> mentions with the | ||||
| // username of the mention, but also role IDs and more. | ||||
| func (m *Message) ContentWithMoreMentionsReplaced(s *Session) (content string, err error) { | ||||
| 	content = m.Content | ||||
|  | ||||
| 	if !s.StateEnabled { | ||||
| 		content = m.ContentWithMentionsReplaced() | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	channel, err := s.State.Channel(m.ChannelID) | ||||
| 	if err != nil { | ||||
| 		content = m.ContentWithMentionsReplaced() | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	for _, user := range m.Mentions { | ||||
| 		nick := user.Username | ||||
|  | ||||
| 		member, err := s.State.Member(channel.GuildID, user.ID) | ||||
| 		if err == nil && member.Nick != "" { | ||||
| 			nick = member.Nick | ||||
| 		} | ||||
|  | ||||
| 		content = strings.NewReplacer( | ||||
| 			"<@"+user.ID+">", "@"+user.Username, | ||||
| 			"<@!"+user.ID+">", "@"+nick, | ||||
| 		).Replace(content) | ||||
| 	} | ||||
| 	for _, roleID := range m.MentionRoles { | ||||
| 		role, err := s.State.Role(channel.GuildID, roleID) | ||||
| 		if err != nil || !role.Mentionable { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		content = strings.Replace(content, "<&"+role.ID+">", "@"+role.Name, -1) | ||||
| 	} | ||||
|  | ||||
| 	content = patternChannels.ReplaceAllStringFunc(content, func(mention string) string { | ||||
| 		channel, err := s.State.Channel(mention[2 : len(mention)-1]) | ||||
| 		if err != nil || channel.Type == ChannelTypeGuildVoice { | ||||
| 			return mention | ||||
| 		} | ||||
|  | ||||
| 		return "#" + channel.Name | ||||
| 	}) | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										47
									
								
								vendor/github.com/bwmarrin/discordgo/ratelimit.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								vendor/github.com/bwmarrin/discordgo/ratelimit.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,17 +3,26 @@ package discordgo | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // customRateLimit holds information for defining a custom rate limit | ||||
| type customRateLimit struct { | ||||
| 	suffix   string | ||||
| 	requests int | ||||
| 	reset    time.Duration | ||||
| } | ||||
|  | ||||
| // RateLimiter holds all ratelimit buckets | ||||
| type RateLimiter struct { | ||||
| 	sync.Mutex | ||||
| 	global          *int64 | ||||
| 	buckets         map[string]*Bucket | ||||
| 	globalRateLimit time.Duration | ||||
| 	global           *int64 | ||||
| 	buckets          map[string]*Bucket | ||||
| 	globalRateLimit  time.Duration | ||||
| 	customRateLimits []*customRateLimit | ||||
| } | ||||
|  | ||||
| // NewRatelimiter returns a new RateLimiter | ||||
| @@ -22,6 +31,13 @@ func NewRatelimiter() *RateLimiter { | ||||
| 	return &RateLimiter{ | ||||
| 		buckets: make(map[string]*Bucket), | ||||
| 		global:  new(int64), | ||||
| 		customRateLimits: []*customRateLimit{ | ||||
| 			&customRateLimit{ | ||||
| 				suffix:   "//reactions//", | ||||
| 				requests: 1, | ||||
| 				reset:    200 * time.Millisecond, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -40,6 +56,14 @@ func (r *RateLimiter) getBucket(key string) *Bucket { | ||||
| 		global:    r.global, | ||||
| 	} | ||||
|  | ||||
| 	// Check if there is a custom ratelimit set for this bucket ID. | ||||
| 	for _, rl := range r.customRateLimits { | ||||
| 		if strings.HasSuffix(b.Key, rl.suffix) { | ||||
| 			b.customRateLimit = rl | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	r.buckets[key] = b | ||||
| 	return b | ||||
| } | ||||
| @@ -76,13 +100,28 @@ type Bucket struct { | ||||
| 	limit     int | ||||
| 	reset     time.Time | ||||
| 	global    *int64 | ||||
|  | ||||
| 	lastReset       time.Time | ||||
| 	customRateLimit *customRateLimit | ||||
| } | ||||
|  | ||||
| // Release unlocks the bucket and reads the headers to update the buckets ratelimit info | ||||
| // and locks up the whole thing in case if there's a global ratelimit. | ||||
| func (b *Bucket) Release(headers http.Header) error { | ||||
|  | ||||
| 	defer b.Unlock() | ||||
|  | ||||
| 	// Check if the bucket uses a custom ratelimiter | ||||
| 	if rl := b.customRateLimit; rl != nil { | ||||
| 		if time.Now().Sub(b.lastReset) >= rl.reset { | ||||
| 			b.remaining = rl.requests - 1 | ||||
| 			b.lastReset = time.Now() | ||||
| 		} | ||||
| 		if b.remaining < 1 { | ||||
| 			b.reset = time.Now().Add(rl.reset) | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if headers == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										138
									
								
								vendor/github.com/bwmarrin/discordgo/restapi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										138
									
								
								vendor/github.com/bwmarrin/discordgo/restapi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -23,6 +23,7 @@ import ( | ||||
| 	"log" | ||||
| 	"mime/multipart" | ||||
| 	"net/http" | ||||
| 	"net/textproto" | ||||
| 	"net/url" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| @@ -309,8 +310,8 @@ func (s *Session) UserUpdate(email, password, username, avatar, newPassword stri | ||||
| 	// If left blank, avatar will be set to null/blank | ||||
|  | ||||
| 	data := struct { | ||||
| 		Email       string `json:"email"` | ||||
| 		Password    string `json:"password"` | ||||
| 		Email       string `json:"email,omitempty"` | ||||
| 		Password    string `json:"password,omitempty"` | ||||
| 		Username    string `json:"username,omitempty"` | ||||
| 		Avatar      string `json:"avatar,omitempty"` | ||||
| 		NewPassword string `json:"new_password,omitempty"` | ||||
| @@ -763,7 +764,21 @@ func (s *Session) GuildMember(guildID, userID string) (st *Member, err error) { | ||||
| // userID    : The ID of a User | ||||
| func (s *Session) GuildMemberDelete(guildID, userID string) (err error) { | ||||
|  | ||||
| 	_, err = s.RequestWithBucketID("DELETE", EndpointGuildMember(guildID, userID), nil, EndpointGuildMember(guildID, "")) | ||||
| 	return s.GuildMemberDeleteWithReason(guildID, userID, "") | ||||
| } | ||||
|  | ||||
| // GuildMemberDeleteWithReason removes the given user from the given guild. | ||||
| // guildID   : The ID of a Guild. | ||||
| // userID    : The ID of a User | ||||
| // reason    : The reason for the kick | ||||
| func (s *Session) GuildMemberDeleteWithReason(guildID, userID, reason string) (err error) { | ||||
|  | ||||
| 	uri := EndpointGuildMember(guildID, userID) | ||||
| 	if reason != "" { | ||||
| 		uri += "?reason=" + url.QueryEscape(reason) | ||||
| 	} | ||||
|  | ||||
| 	_, err = s.RequestWithBucketID("DELETE", uri, nil, EndpointGuildMember(guildID, "")) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @@ -1316,6 +1331,8 @@ func (s *Session) ChannelMessageSend(channelID string, content string) (*Message | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") | ||||
|  | ||||
| // ChannelMessageSendComplex sends a message to the given channel. | ||||
| // channelID : The ID of a Channel. | ||||
| // data      : The message struct to send. | ||||
| @@ -1326,48 +1343,62 @@ func (s *Session) ChannelMessageSendComplex(channelID string, data *MessageSend) | ||||
|  | ||||
| 	endpoint := EndpointChannelMessages(channelID) | ||||
|  | ||||
| 	var response []byte | ||||
| 	// TODO: Remove this when compatibility is not required. | ||||
| 	files := data.Files | ||||
| 	if data.File != nil { | ||||
| 		if files == nil { | ||||
| 			files = []*File{data.File} | ||||
| 		} else { | ||||
| 			err = fmt.Errorf("cannot specify both File and Files") | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var response []byte | ||||
| 	if len(files) > 0 { | ||||
| 		body := &bytes.Buffer{} | ||||
| 		bodywriter := multipart.NewWriter(body) | ||||
|  | ||||
| 		// What's a better way of doing this? Reflect? Generator? I'm open to suggestions | ||||
|  | ||||
| 		if data.Content != "" { | ||||
| 			if err = bodywriter.WriteField("content", data.Content); err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if data.Embed != nil { | ||||
| 			var embed []byte | ||||
| 			embed, err = json.Marshal(data.Embed) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 			err = bodywriter.WriteField("embed", string(embed)) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if data.Tts { | ||||
| 			if err = bodywriter.WriteField("tts", "true"); err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		var writer io.Writer | ||||
| 		writer, err = bodywriter.CreateFormFile("file", data.File.Name) | ||||
| 		var payload []byte | ||||
| 		payload, err = json.Marshal(data) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		_, err = io.Copy(writer, data.File.Reader) | ||||
| 		var p io.Writer | ||||
|  | ||||
| 		h := make(textproto.MIMEHeader) | ||||
| 		h.Set("Content-Disposition", `form-data; name="payload_json"`) | ||||
| 		h.Set("Content-Type", "application/json") | ||||
|  | ||||
| 		p, err = bodywriter.CreatePart(h) | ||||
| 		if err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		if _, err = p.Write(payload); err != nil { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		for i, file := range files { | ||||
| 			h := make(textproto.MIMEHeader) | ||||
| 			h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file%d"; filename="%s"`, i, quoteEscaper.Replace(file.Name))) | ||||
| 			contentType := file.ContentType | ||||
| 			if contentType == "" { | ||||
| 				contentType = "application/octet-stream" | ||||
| 			} | ||||
| 			h.Set("Content-Type", contentType) | ||||
|  | ||||
| 			p, err = bodywriter.CreatePart(h) | ||||
| 			if err != nil { | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			if _, err = io.Copy(p, file.Reader); err != nil { | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		err = bodywriter.Close() | ||||
| 		if err != nil { | ||||
| 			return | ||||
| @@ -1685,6 +1716,28 @@ func (s *Session) Gateway() (gateway string, err error) { | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // GatewayBot returns the websocket Gateway address and the recommended number of shards | ||||
| func (s *Session) GatewayBot() (st *GatewayBotResponse, err error) { | ||||
|  | ||||
| 	response, err := s.RequestWithBucketID("GET", EndpointGatewayBot, nil, EndpointGatewayBot) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	err = unmarshal(response, &st) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Ensure the gateway always has a trailing slash. | ||||
| 	// MacOS will fail to connect if we add query params without a trailing slash on the base domain. | ||||
| 	if !strings.HasSuffix(st.URL, "/") { | ||||
| 		st.URL += "/" | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Functions specific to Webhooks | ||||
|  | ||||
| // WebhookCreate returns a new Webhook. | ||||
| @@ -1810,14 +1863,9 @@ func (s *Session) WebhookEditWithToken(webhookID, token, name, avatar string) (s | ||||
|  | ||||
| // WebhookDelete deletes a webhook for a given ID | ||||
| // webhookID: The ID of a webhook. | ||||
| func (s *Session) WebhookDelete(webhookID string) (st *Webhook, err error) { | ||||
| func (s *Session) WebhookDelete(webhookID string) (err error) { | ||||
|  | ||||
| 	body, err := s.RequestWithBucketID("DELETE", EndpointWebhook(webhookID), nil, EndpointWebhooks) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	err = unmarshal(body, &st) | ||||
| 	_, err = s.RequestWithBucketID("DELETE", EndpointWebhook(webhookID), nil, EndpointWebhooks) | ||||
|  | ||||
| 	return | ||||
| } | ||||
| @@ -1875,6 +1923,16 @@ func (s *Session) MessageReactionRemove(channelID, messageID, emojiID, userID st | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // MessageReactionsRemoveAll deletes all reactions from a message | ||||
| // channelID : The channel ID | ||||
| // messageID : The message ID. | ||||
| func (s *Session) MessageReactionsRemoveAll(channelID, messageID string) error { | ||||
|  | ||||
| 	_, err := s.RequestWithBucketID("DELETE", EndpointMessageReactionsAll(channelID, messageID), nil, EndpointMessageReactionsAll(channelID, messageID)) | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // MessageReactions gets all the users reactions for a specific emoji. | ||||
| // channelID : The channel ID. | ||||
| // messageID : The message ID. | ||||
|   | ||||
							
								
								
									
										72
									
								
								vendor/github.com/bwmarrin/discordgo/state.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										72
									
								
								vendor/github.com/bwmarrin/discordgo/state.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -42,6 +42,7 @@ type State struct { | ||||
|  | ||||
| 	guildMap   map[string]*Guild | ||||
| 	channelMap map[string]*Channel | ||||
| 	memberMap  map[string]map[string]*Member | ||||
| } | ||||
|  | ||||
| // NewState creates an empty state. | ||||
| @@ -59,9 +60,18 @@ func NewState() *State { | ||||
| 		TrackPresences: true, | ||||
| 		guildMap:       make(map[string]*Guild), | ||||
| 		channelMap:     make(map[string]*Channel), | ||||
| 		memberMap:      make(map[string]map[string]*Member), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *State) createMemberMap(guild *Guild) { | ||||
| 	members := make(map[string]*Member) | ||||
| 	for _, m := range guild.Members { | ||||
| 		members[m.User.ID] = m | ||||
| 	} | ||||
| 	s.memberMap[guild.ID] = members | ||||
| } | ||||
|  | ||||
| // GuildAdd adds a guild to the current world state, or | ||||
| // updates it if it already exists. | ||||
| func (s *State) GuildAdd(guild *Guild) error { | ||||
| @@ -77,6 +87,14 @@ func (s *State) GuildAdd(guild *Guild) error { | ||||
| 		s.channelMap[c.ID] = c | ||||
| 	} | ||||
|  | ||||
| 	// If this guild contains a new member slice, we must regenerate the member map so the pointers stay valid | ||||
| 	if guild.Members != nil { | ||||
| 		s.createMemberMap(guild) | ||||
| 	} else if _, ok := s.memberMap[guild.ID]; !ok { | ||||
| 		// Even if we have no new member slice, we still initialize the member map for this guild if it doesn't exist | ||||
| 		s.memberMap[guild.ID] = make(map[string]*Member) | ||||
| 	} | ||||
|  | ||||
| 	if g, ok := s.guildMap[guild.ID]; ok { | ||||
| 		// We are about to replace `g` in the state with `guild`, but first we need to | ||||
| 		// make sure we preserve any fields that the `guild` doesn't contain from `g`. | ||||
| @@ -271,14 +289,19 @@ func (s *State) MemberAdd(member *Member) error { | ||||
| 	s.Lock() | ||||
| 	defer s.Unlock() | ||||
|  | ||||
| 	for i, m := range guild.Members { | ||||
| 		if m.User.ID == member.User.ID { | ||||
| 			guild.Members[i] = member | ||||
| 			return nil | ||||
| 		} | ||||
| 	members, ok := s.memberMap[member.GuildID] | ||||
| 	if !ok { | ||||
| 		return ErrStateNotFound | ||||
| 	} | ||||
|  | ||||
| 	m, ok := members[member.User.ID] | ||||
| 	if !ok { | ||||
| 		members[member.User.ID] = member | ||||
| 		guild.Members = append(guild.Members, member) | ||||
| 	} else { | ||||
| 		*m = *member // Update the actual data, which will also update the member pointer in the slice | ||||
| 	} | ||||
|  | ||||
| 	guild.Members = append(guild.Members, member) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -296,6 +319,17 @@ func (s *State) MemberRemove(member *Member) error { | ||||
| 	s.Lock() | ||||
| 	defer s.Unlock() | ||||
|  | ||||
| 	members, ok := s.memberMap[member.GuildID] | ||||
| 	if !ok { | ||||
| 		return ErrStateNotFound | ||||
| 	} | ||||
|  | ||||
| 	_, ok = members[member.User.ID] | ||||
| 	if !ok { | ||||
| 		return ErrStateNotFound | ||||
| 	} | ||||
| 	delete(members, member.User.ID) | ||||
|  | ||||
| 	for i, m := range guild.Members { | ||||
| 		if m.User.ID == member.User.ID { | ||||
| 			guild.Members = append(guild.Members[:i], guild.Members[i+1:]...) | ||||
| @@ -312,18 +346,17 @@ func (s *State) Member(guildID, userID string) (*Member, error) { | ||||
| 		return nil, ErrNilState | ||||
| 	} | ||||
|  | ||||
| 	guild, err := s.Guild(guildID) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	s.RLock() | ||||
| 	defer s.RUnlock() | ||||
|  | ||||
| 	for _, m := range guild.Members { | ||||
| 		if m.User.ID == userID { | ||||
| 			return m, nil | ||||
| 		} | ||||
| 	members, ok := s.memberMap[guildID] | ||||
| 	if !ok { | ||||
| 		return nil, ErrStateNotFound | ||||
| 	} | ||||
|  | ||||
| 	m, ok := members[userID] | ||||
| 	if ok { | ||||
| 		return m, nil | ||||
| 	} | ||||
|  | ||||
| 	return nil, ErrStateNotFound | ||||
| @@ -427,7 +460,7 @@ func (s *State) ChannelAdd(channel *Channel) error { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if channel.IsPrivate { | ||||
| 	if channel.Type == ChannelTypeDM || channel.Type == ChannelTypeGroupDM { | ||||
| 		s.PrivateChannels = append(s.PrivateChannels, channel) | ||||
| 	} else { | ||||
| 		guild, ok := s.guildMap[channel.GuildID] | ||||
| @@ -454,7 +487,7 @@ func (s *State) ChannelRemove(channel *Channel) error { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if channel.IsPrivate { | ||||
| 	if channel.Type == ChannelTypeDM || channel.Type == ChannelTypeGroupDM { | ||||
| 		s.Lock() | ||||
| 		defer s.Unlock() | ||||
|  | ||||
| @@ -735,6 +768,7 @@ func (s *State) onReady(se *Session, r *Ready) (err error) { | ||||
|  | ||||
| 	for _, g := range s.Guilds { | ||||
| 		s.guildMap[g.ID] = g | ||||
| 		s.createMemberMap(g) | ||||
|  | ||||
| 		for _, c := range g.Channels { | ||||
| 			s.channelMap[c.ID] = c | ||||
| @@ -748,8 +782,8 @@ func (s *State) onReady(se *Session, r *Ready) (err error) { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // onInterface handles all events related to states. | ||||
| func (s *State) onInterface(se *Session, i interface{}) (err error) { | ||||
| // OnInterface handles all events related to states. | ||||
| func (s *State) OnInterface(se *Session, i interface{}) (err error) { | ||||
| 	if s == nil { | ||||
| 		return ErrNilState | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										87
									
								
								vendor/github.com/bwmarrin/discordgo/structs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										87
									
								
								vendor/github.com/bwmarrin/discordgo/structs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -50,6 +50,10 @@ type Session struct { | ||||
| 	// active guilds and the members of the guilds. | ||||
| 	StateEnabled bool | ||||
|  | ||||
| 	// Whether or not to call event handlers synchronously. | ||||
| 	// e.g false = launch event handlers in their own goroutines. | ||||
| 	SyncEvents bool | ||||
|  | ||||
| 	// Exposed but should not be modified by User. | ||||
|  | ||||
| 	// Whether the Data Websocket is ready | ||||
| @@ -78,6 +82,9 @@ type Session struct { | ||||
| 	// The http client used for REST requests | ||||
| 	Client *http.Client | ||||
|  | ||||
| 	// Stores the last HeartbeatAck that was recieved (in UTC) | ||||
| 	LastHeartbeatAck time.Time | ||||
|  | ||||
| 	// Event handlers | ||||
| 	handlersMu   sync.RWMutex | ||||
| 	handlers     map[string][]*eventHandlerInstance | ||||
| @@ -141,18 +148,30 @@ type Invite struct { | ||||
| 	Temporary bool      `json:"temporary"` | ||||
| } | ||||
|  | ||||
| // ChannelType is the type of a Channel | ||||
| type ChannelType int | ||||
|  | ||||
| // Block contains known ChannelType values | ||||
| const ( | ||||
| 	ChannelTypeGuildText ChannelType = iota | ||||
| 	ChannelTypeDM | ||||
| 	ChannelTypeGuildVoice | ||||
| 	ChannelTypeGroupDM | ||||
| 	ChannelTypeGuildCategory | ||||
| ) | ||||
|  | ||||
| // A Channel holds all data related to an individual Discord channel. | ||||
| type Channel struct { | ||||
| 	ID                   string                 `json:"id"` | ||||
| 	GuildID              string                 `json:"guild_id"` | ||||
| 	Name                 string                 `json:"name"` | ||||
| 	Topic                string                 `json:"topic"` | ||||
| 	Type                 string                 `json:"type"` | ||||
| 	Type                 ChannelType            `json:"type"` | ||||
| 	LastMessageID        string                 `json:"last_message_id"` | ||||
| 	NSFW                 bool                   `json:"nsfw"` | ||||
| 	Position             int                    `json:"position"` | ||||
| 	Bitrate              int                    `json:"bitrate"` | ||||
| 	IsPrivate            bool                   `json:"is_private"` | ||||
| 	Recipient            *User                  `json:"recipient"` | ||||
| 	Recipients           []*User                `json:"recipient"` | ||||
| 	Messages             []*Message             `json:"-"` | ||||
| 	PermissionOverwrites []*PermissionOverwrite `json:"permission_overwrites"` | ||||
| } | ||||
| @@ -292,13 +311,14 @@ type Presence struct { | ||||
| 	Game   *Game    `json:"game"` | ||||
| 	Nick   string   `json:"nick"` | ||||
| 	Roles  []string `json:"roles"` | ||||
| 	Since  *int     `json:"since"` | ||||
| } | ||||
|  | ||||
| // A Game struct holds the name of the "playing .." game for a user | ||||
| type Game struct { | ||||
| 	Name string `json:"name"` | ||||
| 	Type int    `json:"type"` | ||||
| 	URL  string `json:"url"` | ||||
| 	URL  string `json:"url,omitempty"` | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON unmarshals json to Game struct | ||||
| @@ -509,6 +529,12 @@ type MessageReaction struct { | ||||
| 	ChannelID string `json:"channel_id"` | ||||
| } | ||||
|  | ||||
| // GatewayBotResponse stores the data for the gateway/bot response | ||||
| type GatewayBotResponse struct { | ||||
| 	URL    string `json:"url"` | ||||
| 	Shards int    `json:"shards"` | ||||
| } | ||||
|  | ||||
| // Constants for the different bit offsets of text channel permissions | ||||
| const ( | ||||
| 	PermissionReadMessages = 1 << (iota + 10) | ||||
| @@ -579,3 +605,56 @@ const ( | ||||
| 		PermissionManageServer | | ||||
| 		PermissionAdministrator | ||||
| ) | ||||
|  | ||||
| // Block contains Discord JSON Error Response codes | ||||
| const ( | ||||
| 	ErrCodeUnknownAccount     = 10001 | ||||
| 	ErrCodeUnknownApplication = 10002 | ||||
| 	ErrCodeUnknownChannel     = 10003 | ||||
| 	ErrCodeUnknownGuild       = 10004 | ||||
| 	ErrCodeUnknownIntegration = 10005 | ||||
| 	ErrCodeUnknownInvite      = 10006 | ||||
| 	ErrCodeUnknownMember      = 10007 | ||||
| 	ErrCodeUnknownMessage     = 10008 | ||||
| 	ErrCodeUnknownOverwrite   = 10009 | ||||
| 	ErrCodeUnknownProvider    = 10010 | ||||
| 	ErrCodeUnknownRole        = 10011 | ||||
| 	ErrCodeUnknownToken       = 10012 | ||||
| 	ErrCodeUnknownUser        = 10013 | ||||
| 	ErrCodeUnknownEmoji       = 10014 | ||||
|  | ||||
| 	ErrCodeBotsCannotUseEndpoint  = 20001 | ||||
| 	ErrCodeOnlyBotsCanUseEndpoint = 20002 | ||||
|  | ||||
| 	ErrCodeMaximumGuildsReached     = 30001 | ||||
| 	ErrCodeMaximumFriendsReached    = 30002 | ||||
| 	ErrCodeMaximumPinsReached       = 30003 | ||||
| 	ErrCodeMaximumGuildRolesReached = 30005 | ||||
| 	ErrCodeTooManyReactions         = 30010 | ||||
|  | ||||
| 	ErrCodeUnauthorized = 40001 | ||||
|  | ||||
| 	ErrCodeMissingAccess                             = 50001 | ||||
| 	ErrCodeInvalidAccountType                        = 50002 | ||||
| 	ErrCodeCannotExecuteActionOnDMChannel            = 50003 | ||||
| 	ErrCodeEmbedCisabled                             = 50004 | ||||
| 	ErrCodeCannotEditFromAnotherUser                 = 50005 | ||||
| 	ErrCodeCannotSendEmptyMessage                    = 50006 | ||||
| 	ErrCodeCannotSendMessagesToThisUser              = 50007 | ||||
| 	ErrCodeCannotSendMessagesInVoiceChannel          = 50008 | ||||
| 	ErrCodeChannelVerificationLevelTooHigh           = 50009 | ||||
| 	ErrCodeOAuth2ApplicationDoesNotHaveBot           = 50010 | ||||
| 	ErrCodeOAuth2ApplicationLimitReached             = 50011 | ||||
| 	ErrCodeInvalidOAuthState                         = 50012 | ||||
| 	ErrCodeMissingPermissions                        = 50013 | ||||
| 	ErrCodeInvalidAuthenticationToken                = 50014 | ||||
| 	ErrCodeNoteTooLong                               = 50015 | ||||
| 	ErrCodeTooFewOrTooManyMessagesToDelete           = 50016 | ||||
| 	ErrCodeCanOnlyPinMessageToOriginatingChannel     = 50019 | ||||
| 	ErrCodeCannotExecuteActionOnSystemMessage        = 50021 | ||||
| 	ErrCodeMessageProvidedTooOldForBulkDelete        = 50034 | ||||
| 	ErrCodeInvalidFormBody                           = 50035 | ||||
| 	ErrCodeInviteAcceptedToGuildApplicationsBotNotIn = 50036 | ||||
|  | ||||
| 	ErrCodeReactionBlocked = 90001 | ||||
| ) | ||||
|   | ||||
							
								
								
									
										18
									
								
								vendor/github.com/bwmarrin/discordgo/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/bwmarrin/discordgo/user.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,6 +1,9 @@ | ||||
| package discordgo | ||||
|  | ||||
| import "fmt" | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // A User stores all data for an individual Discord user. | ||||
| type User struct { | ||||
| @@ -24,3 +27,16 @@ func (u *User) String() string { | ||||
| func (u *User) Mention() string { | ||||
| 	return fmt.Sprintf("<@%s>", u.ID) | ||||
| } | ||||
|  | ||||
| // AvatarURL returns a URL to the user's avatar. | ||||
| //		size:     The size of the user's avatar as a power of two | ||||
| func (u *User) AvatarURL(size string) string { | ||||
| 	var URL string | ||||
| 	if strings.HasPrefix(u.Avatar, "a_") { | ||||
| 		URL = EndpointUserAvatarAnimated(u.ID, u.Avatar) | ||||
| 	} else { | ||||
| 		URL = EndpointUserAvatar(u.ID, u.Avatar) | ||||
| 	} | ||||
|  | ||||
| 	return URL + "?size=" + size | ||||
| } | ||||
|   | ||||
							
								
								
									
										13
									
								
								vendor/github.com/bwmarrin/discordgo/voice.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/bwmarrin/discordgo/voice.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -796,7 +796,7 @@ func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct | ||||
| 		} | ||||
|  | ||||
| 		// For now, skip anything except audio. | ||||
| 		if rlen < 12 || recvbuf[0] != 0x80 { | ||||
| 		if rlen < 12 || (recvbuf[0] != 0x80 && recvbuf[0] != 0x90) { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| @@ -810,8 +810,17 @@ func (v *VoiceConnection) opusReceiver(udpConn *net.UDPConn, close <-chan struct | ||||
| 		copy(nonce[:], recvbuf[0:12]) | ||||
| 		p.Opus, _ = secretbox.Open(nil, recvbuf[12:rlen], &nonce, &v.op4.SecretKey) | ||||
|  | ||||
| 		if len(p.Opus) > 8 && recvbuf[0] == 0x90 { | ||||
| 			// Extension bit is set, first 8 bytes is the extended header | ||||
| 			p.Opus = p.Opus[8:] | ||||
| 		} | ||||
|  | ||||
| 		if c != nil { | ||||
| 			c <- &p | ||||
| 			select { | ||||
| 			case c <- &p: | ||||
| 			case <-close: | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										58
									
								
								vendor/github.com/bwmarrin/discordgo/wsapi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										58
									
								
								vendor/github.com/bwmarrin/discordgo/wsapi.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -15,7 +15,6 @@ import ( | ||||
| 	"compress/zlib" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"runtime" | ||||
| @@ -87,7 +86,7 @@ func (s *Session) Open() (err error) { | ||||
| 		} | ||||
|  | ||||
| 		// Add the version and encoding to the URL | ||||
| 		s.gateway = fmt.Sprintf("%s?v=5&encoding=json", s.gateway) | ||||
| 		s.gateway = s.gateway + "?v=" + APIVersion + "&encoding=json" | ||||
| 	} | ||||
|  | ||||
| 	header := http.Header{} | ||||
| @@ -131,6 +130,7 @@ func (s *Session) Open() (err error) { | ||||
| 	// lock. | ||||
| 	s.listening = make(chan interface{}) | ||||
| 	go s.listen(s.wsConn, s.listening) | ||||
| 	s.LastHeartbeatAck = time.Now().UTC() | ||||
|  | ||||
| 	s.Unlock() | ||||
|  | ||||
| @@ -199,10 +199,13 @@ type helloOp struct { | ||||
| 	Trace             []string      `json:"_trace"` | ||||
| } | ||||
|  | ||||
| // FailedHeartbeatAcks is the Number of heartbeat intervals to wait until forcing a connection restart. | ||||
| const FailedHeartbeatAcks time.Duration = 5 * time.Millisecond | ||||
|  | ||||
| // heartbeat sends regular heartbeats to Discord so it knows the client | ||||
| // is still connected.  If you do not send these heartbeats Discord will | ||||
| // disconnect the websocket connection after a few seconds. | ||||
| func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, i time.Duration) { | ||||
| func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{}, heartbeatIntervalMsec time.Duration) { | ||||
|  | ||||
| 	s.log(LogInformational, "called") | ||||
|  | ||||
| @@ -211,20 +214,26 @@ func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{} | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	ticker := time.NewTicker(i * time.Millisecond) | ||||
| 	ticker := time.NewTicker(heartbeatIntervalMsec * time.Millisecond) | ||||
| 	defer ticker.Stop() | ||||
|  | ||||
| 	for { | ||||
| 		s.RLock() | ||||
| 		last := s.LastHeartbeatAck | ||||
| 		s.RUnlock() | ||||
| 		sequence := atomic.LoadInt64(s.sequence) | ||||
| 		s.log(LogInformational, "sending gateway websocket heartbeat seq %d", sequence) | ||||
| 		s.wsMutex.Lock() | ||||
| 		err = wsConn.WriteJSON(heartbeatOp{1, sequence}) | ||||
| 		s.wsMutex.Unlock() | ||||
| 		if err != nil { | ||||
| 			s.log(LogError, "error sending heartbeat to gateway %s, %s", s.gateway, err) | ||||
| 			s.Lock() | ||||
| 			s.DataReady = false | ||||
| 			s.Unlock() | ||||
| 		if err != nil || time.Now().UTC().Sub(last) > (heartbeatIntervalMsec*FailedHeartbeatAcks) { | ||||
| 			if err != nil { | ||||
| 				s.log(LogError, "error sending heartbeat to gateway %s, %s", s.gateway, err) | ||||
| 			} else { | ||||
| 				s.log(LogError, "haven't gotten a heartbeat ACK in %v, triggering a reconnection", time.Now().UTC().Sub(last)) | ||||
| 			} | ||||
| 			s.Close() | ||||
| 			s.reconnect() | ||||
| 			return | ||||
| 		} | ||||
| 		s.Lock() | ||||
| @@ -241,8 +250,10 @@ func (s *Session) heartbeat(wsConn *websocket.Conn, listening <-chan interface{} | ||||
| } | ||||
|  | ||||
| type updateStatusData struct { | ||||
| 	IdleSince *int  `json:"idle_since"` | ||||
| 	Game      *Game `json:"game"` | ||||
| 	IdleSince *int   `json:"since"` | ||||
| 	Game      *Game  `json:"game"` | ||||
| 	AFK       bool   `json:"afk"` | ||||
| 	Status    string `json:"status"` | ||||
| } | ||||
|  | ||||
| type updateStatusOp struct { | ||||
| @@ -265,7 +276,10 @@ func (s *Session) UpdateStreamingStatus(idle int, game string, url string) (err | ||||
| 		return ErrWSNotFound | ||||
| 	} | ||||
|  | ||||
| 	var usd updateStatusData | ||||
| 	usd := updateStatusData{ | ||||
| 		Status: "online", | ||||
| 	} | ||||
|  | ||||
| 	if idle > 0 { | ||||
| 		usd.IdleSince = &idle | ||||
| 	} | ||||
| @@ -398,7 +412,10 @@ func (s *Session) onEvent(messageType int, message []byte) { | ||||
| 	// Reconnect | ||||
| 	// Must immediately disconnect from gateway and reconnect to new gateway. | ||||
| 	if e.Operation == 7 { | ||||
| 		// TODO | ||||
| 		s.log(LogInformational, "Closing and reconnecting in response to Op7") | ||||
| 		s.Close() | ||||
| 		s.reconnect() | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Invalid Session | ||||
| @@ -426,6 +443,14 @@ func (s *Session) onEvent(messageType int, message []byte) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if e.Operation == 11 { | ||||
| 		s.Lock() | ||||
| 		s.LastHeartbeatAck = time.Now().UTC() | ||||
| 		s.Unlock() | ||||
| 		s.log(LogInformational, "got heartbeat ACK") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Do not try to Dispatch a non-Dispatch Message | ||||
| 	if e.Operation != 0 { | ||||
| 		// But we probably should be doing something with them. | ||||
| @@ -688,6 +713,13 @@ func (s *Session) reconnect() { | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			// Certain race conditions can call reconnect() twice. If this happens, we | ||||
| 			// just break out of the reconnect loop | ||||
| 			if err == ErrWSAlreadyOpen { | ||||
| 				s.log(LogInformational, "Websocket already exists, no need to reconnect") | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			s.log(LogError, "error reconnecting to gateway, %s", err) | ||||
|  | ||||
| 			<-time.After(wait * time.Second) | ||||
|   | ||||
							
								
								
									
										197
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										197
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -191,7 +191,11 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna | ||||
| 	} | ||||
|  | ||||
| 	var apiResp APIResponse | ||||
| 	json.Unmarshal(bytes, &apiResp) | ||||
|  | ||||
| 	err = json.Unmarshal(bytes, &apiResp) | ||||
| 	if err != nil { | ||||
| 		return APIResponse{}, err | ||||
| 	} | ||||
|  | ||||
| 	if !apiResp.Ok { | ||||
| 		return APIResponse{}, errors.New(apiResp.Description) | ||||
| @@ -438,14 +442,7 @@ func (bot *BotAPI) SetWebhook(config WebhookConfig) (APIResponse, error) { | ||||
| 		return APIResponse{}, err | ||||
| 	} | ||||
|  | ||||
| 	var apiResp APIResponse | ||||
| 	json.Unmarshal(resp.Result, &apiResp) | ||||
|  | ||||
| 	if bot.Debug { | ||||
| 		log.Printf("setWebhook resp: %+v\n", apiResp) | ||||
| 	} | ||||
|  | ||||
| 	return apiResp, nil | ||||
| 	return resp, nil | ||||
| } | ||||
|  | ||||
| // GetWebhookInfo allows you to fetch information about a webhook and if | ||||
| @@ -550,7 +547,7 @@ func (bot *BotAPI) AnswerCallbackQuery(config CallbackConfig) (APIResponse, erro | ||||
| // KickChatMember kicks a user from a chat. Note that this only will work | ||||
| // in supergroups, and requires the bot to be an admin. Also note they | ||||
| // will be unable to rejoin until they are unbanned. | ||||
| func (bot *BotAPI) KickChatMember(config ChatMemberConfig) (APIResponse, error) { | ||||
| func (bot *BotAPI) KickChatMember(config KickChatMemberConfig) (APIResponse, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	if config.SuperGroupUsername == "" { | ||||
| @@ -560,6 +557,10 @@ func (bot *BotAPI) KickChatMember(config ChatMemberConfig) (APIResponse, error) | ||||
| 	} | ||||
| 	v.Add("user_id", strconv.Itoa(config.UserID)) | ||||
|  | ||||
| 	if config.UntilDate != 0 { | ||||
| 		v.Add("until_date", strconv.FormatInt(config.UntilDate, 10)) | ||||
| 	} | ||||
|  | ||||
| 	bot.debugLog("kickChatMember", v, nil) | ||||
|  | ||||
| 	return bot.MakeRequest("kickChatMember", v) | ||||
| @@ -677,14 +678,16 @@ func (bot *BotAPI) GetChatMember(config ChatConfigWithUser) (ChatMember, error) | ||||
| } | ||||
|  | ||||
| // UnbanChatMember unbans a user from a chat. Note that this only will work | ||||
| // in supergroups, and requires the bot to be an admin. | ||||
| // in supergroups and channels, and requires the bot to be an admin. | ||||
| func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	if config.SuperGroupUsername == "" { | ||||
| 		v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) | ||||
| 	} else { | ||||
| 	if config.SuperGroupUsername != "" { | ||||
| 		v.Add("chat_id", config.SuperGroupUsername) | ||||
| 	} else if config.ChannelUsername != "" { | ||||
| 		v.Add("chat_id", config.ChannelUsername) | ||||
| 	} else { | ||||
| 		v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) | ||||
| 	} | ||||
| 	v.Add("user_id", strconv.Itoa(config.UserID)) | ||||
|  | ||||
| @@ -693,6 +696,82 @@ func (bot *BotAPI) UnbanChatMember(config ChatMemberConfig) (APIResponse, error) | ||||
| 	return bot.MakeRequest("unbanChatMember", v) | ||||
| } | ||||
|  | ||||
| // RestrictChatMember to restrict a user in a supergroup. The bot must be an | ||||
| //administrator in the supergroup for this to work and must have the | ||||
| //appropriate admin rights. Pass True for all boolean parameters to lift | ||||
| //restrictions from a user. Returns True on success. | ||||
| func (bot *BotAPI) RestrictChatMember(config RestrictChatMemberConfig) (APIResponse, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	if config.SuperGroupUsername != "" { | ||||
| 		v.Add("chat_id", config.SuperGroupUsername) | ||||
| 	} else if config.ChannelUsername != "" { | ||||
| 		v.Add("chat_id", config.ChannelUsername) | ||||
| 	} else { | ||||
| 		v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) | ||||
| 	} | ||||
| 	v.Add("user_id", strconv.Itoa(config.UserID)) | ||||
|  | ||||
| 	if &config.CanSendMessages != nil { | ||||
| 		v.Add("can_send_messages", strconv.FormatBool(*config.CanSendMessages)) | ||||
| 	} | ||||
| 	if &config.CanSendMediaMessages != nil { | ||||
| 		v.Add("can_send_media_messages", strconv.FormatBool(*config.CanSendMediaMessages)) | ||||
| 	} | ||||
| 	if &config.CanSendOtherMessages != nil { | ||||
| 		v.Add("can_send_other_messages", strconv.FormatBool(*config.CanSendOtherMessages)) | ||||
| 	} | ||||
| 	if &config.CanAddWebPagePreviews != nil { | ||||
| 		v.Add("can_add_web_page_previews", strconv.FormatBool(*config.CanAddWebPagePreviews)) | ||||
| 	} | ||||
|  | ||||
| 	bot.debugLog("restrictChatMember", v, nil) | ||||
|  | ||||
| 	return bot.MakeRequest("restrictChatMember", v) | ||||
| } | ||||
|  | ||||
| func (bot *BotAPI) PromoteChatMember(config PromoteChatMemberConfig) (APIResponse, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	if config.SuperGroupUsername != "" { | ||||
| 		v.Add("chat_id", config.SuperGroupUsername) | ||||
| 	} else if config.ChannelUsername != "" { | ||||
| 		v.Add("chat_id", config.ChannelUsername) | ||||
| 	} else { | ||||
| 		v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) | ||||
| 	} | ||||
| 	v.Add("user_id", strconv.Itoa(config.UserID)) | ||||
|  | ||||
| 	if &config.CanChangeInfo != nil { | ||||
| 		v.Add("can_change_info", strconv.FormatBool(*config.CanChangeInfo)) | ||||
| 	} | ||||
| 	if &config.CanPostMessages != nil { | ||||
| 		v.Add("can_post_messages", strconv.FormatBool(*config.CanPostMessages)) | ||||
| 	} | ||||
| 	if &config.CanEditMessages != nil { | ||||
| 		v.Add("can_edit_messages", strconv.FormatBool(*config.CanEditMessages)) | ||||
| 	} | ||||
| 	if &config.CanDeleteMessages != nil { | ||||
| 		v.Add("can_delete_messages", strconv.FormatBool(*config.CanDeleteMessages)) | ||||
| 	} | ||||
| 	if &config.CanInviteUsers != nil { | ||||
| 		v.Add("can_invite_users", strconv.FormatBool(*config.CanInviteUsers)) | ||||
| 	} | ||||
| 	if &config.CanRestrictMembers != nil { | ||||
| 		v.Add("can_restrict_members", strconv.FormatBool(*config.CanRestrictMembers)) | ||||
| 	} | ||||
| 	if &config.CanPinMessages != nil { | ||||
| 		v.Add("can_pin_messages", strconv.FormatBool(*config.CanPinMessages)) | ||||
| 	} | ||||
| 	if &config.CanPromoteMembers != nil { | ||||
| 		v.Add("can_promote_members", strconv.FormatBool(*config.CanPromoteMembers)) | ||||
| 	} | ||||
|  | ||||
| 	bot.debugLog("promoteChatMember", v, nil) | ||||
|  | ||||
| 	return bot.MakeRequest("promoteChatMember", v) | ||||
| } | ||||
|  | ||||
| // GetGameHighScores allows you to get the high scores for a game. | ||||
| func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) { | ||||
| 	v, _ := config.values() | ||||
| @@ -707,3 +786,93 @@ func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHigh | ||||
|  | ||||
| 	return highScores, err | ||||
| } | ||||
|  | ||||
| // AnswerShippingQuery allows you to reply to Update with shipping_query parameter. | ||||
| func (bot *BotAPI) AnswerShippingQuery(config ShippingConfig) (APIResponse, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	v.Add("shipping_query_id", config.ShippingQueryID) | ||||
| 	v.Add("ok", strconv.FormatBool(config.OK)) | ||||
| 	if config.OK == true { | ||||
| 		data, err := json.Marshal(config.ShippingOptions) | ||||
| 		if err != nil { | ||||
| 			return APIResponse{}, err | ||||
| 		} | ||||
| 		v.Add("shipping_options", string(data)) | ||||
| 	} else { | ||||
| 		v.Add("error_message", config.ErrorMessage) | ||||
| 	} | ||||
|  | ||||
| 	bot.debugLog("answerShippingQuery", v, nil) | ||||
|  | ||||
| 	return bot.MakeRequest("answerShippingQuery", v) | ||||
| } | ||||
|  | ||||
| // AnswerPreCheckoutQuery allows you to reply to Update with pre_checkout_query. | ||||
| func (bot *BotAPI) AnswerPreCheckoutQuery(config PreCheckoutConfig) (APIResponse, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	v.Add("pre_checkout_query_id", config.PreCheckoutQueryID) | ||||
| 	v.Add("ok", strconv.FormatBool(config.OK)) | ||||
| 	if config.OK != true { | ||||
| 		v.Add("error", config.ErrorMessage) | ||||
| 	} | ||||
|  | ||||
| 	bot.debugLog("answerPreCheckoutQuery", v, nil) | ||||
|  | ||||
| 	return bot.MakeRequest("answerPreCheckoutQuery", v) | ||||
| } | ||||
|  | ||||
| // DeleteMessage deletes a message in a chat | ||||
| func (bot *BotAPI) DeleteMessage(config DeleteMessageConfig) (APIResponse, error) { | ||||
| 	v, err := config.values() | ||||
| 	if err != nil { | ||||
| 		return APIResponse{}, err | ||||
| 	} | ||||
|  | ||||
| 	bot.debugLog(config.method(), v, nil) | ||||
|  | ||||
| 	return bot.MakeRequest(config.method(), v) | ||||
| } | ||||
|  | ||||
| // GetInviteLink get InviteLink for a chat | ||||
| func (bot *BotAPI) GetInviteLink(config ChatConfig) (string, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	if config.SuperGroupUsername == "" { | ||||
| 		v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) | ||||
| 	} else { | ||||
| 		v.Add("chat_id", config.SuperGroupUsername) | ||||
| 	} | ||||
|  | ||||
| 	resp, err := bot.MakeRequest("exportChatInviteLink", v) | ||||
|  | ||||
| 	var inviteLink string | ||||
| 	err = json.Unmarshal(resp.Result, &inviteLink) | ||||
|  | ||||
| 	return inviteLink, err | ||||
| } | ||||
|  | ||||
| // Pin message in supergroup | ||||
| func (bot *BotAPI) PinChatMessage(config PinChatMessageConfig) (APIResponse, error) { | ||||
| 	v, err := config.values() | ||||
| 	if err != nil { | ||||
| 		return APIResponse{}, err | ||||
| 	} | ||||
|  | ||||
| 	bot.debugLog(config.method(), v, nil) | ||||
|  | ||||
| 	return bot.MakeRequest(config.method(), v) | ||||
| } | ||||
|  | ||||
| // Unpin message in supergroup | ||||
| func (bot *BotAPI) UnpinChatMessage(config UnpinChatMessageConfig) (APIResponse, error) { | ||||
| 	v, err := config.values() | ||||
| 	if err != nil { | ||||
| 		return APIResponse{}, err | ||||
| 	} | ||||
|  | ||||
| 	bot.debugLog(config.method(), v, nil) | ||||
|  | ||||
| 	return bot.MakeRequest(config.method(), v) | ||||
| } | ||||
							
								
								
									
										243
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										243
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -349,6 +349,7 @@ func (config AudioConfig) method() string { | ||||
| // DocumentConfig contains information about a SendDocument request. | ||||
| type DocumentConfig struct { | ||||
| 	BaseFile | ||||
| 	Caption string | ||||
| } | ||||
|  | ||||
| // values returns a url.Values representation of DocumentConfig. | ||||
| @@ -359,6 +360,9 @@ func (config DocumentConfig) values() (url.Values, error) { | ||||
| 	} | ||||
|  | ||||
| 	v.Add(config.name(), config.FileID) | ||||
| 	if config.Caption != "" { | ||||
| 		v.Add("caption", config.Caption) | ||||
| 	} | ||||
|  | ||||
| 	return v, nil | ||||
| } | ||||
| @@ -367,6 +371,10 @@ func (config DocumentConfig) values() (url.Values, error) { | ||||
| func (config DocumentConfig) params() (map[string]string, error) { | ||||
| 	params, _ := config.BaseFile.params() | ||||
|  | ||||
| 	if config.Caption != "" { | ||||
| 		params["caption"] = config.Caption | ||||
| 	} | ||||
|  | ||||
| 	return params, nil | ||||
| } | ||||
|  | ||||
| @@ -443,6 +451,10 @@ func (config VideoConfig) values() (url.Values, error) { | ||||
| func (config VideoConfig) params() (map[string]string, error) { | ||||
| 	params, _ := config.BaseFile.params() | ||||
|  | ||||
| 	if config.Caption != "" { | ||||
| 		params["caption"] = config.Caption | ||||
| 	} | ||||
|  | ||||
| 	return params, nil | ||||
| } | ||||
|  | ||||
| @@ -456,6 +468,57 @@ func (config VideoConfig) method() string { | ||||
| 	return "sendVideo" | ||||
| } | ||||
|  | ||||
| // VideoNoteConfig contains information about a SendVideoNote request. | ||||
| type VideoNoteConfig struct { | ||||
| 	BaseFile | ||||
| 	Duration int | ||||
| 	Length   int | ||||
| } | ||||
|  | ||||
| // values returns a url.Values representation of VideoNoteConfig. | ||||
| func (config VideoNoteConfig) values() (url.Values, error) { | ||||
| 	v, err := config.BaseChat.values() | ||||
| 	if err != nil { | ||||
| 		return v, err | ||||
| 	} | ||||
|  | ||||
| 	v.Add(config.name(), config.FileID) | ||||
| 	if config.Duration != 0 { | ||||
| 		v.Add("duration", strconv.Itoa(config.Duration)) | ||||
| 	} | ||||
|  | ||||
| 	// Telegram API seems to have a bug, if no length is provided or it is 0, it will send an error response | ||||
| 	if config.Length != 0 { | ||||
| 		v.Add("length", strconv.Itoa(config.Length)) | ||||
| 	} | ||||
|  | ||||
| 	return v, nil | ||||
| } | ||||
|  | ||||
| // params returns a map[string]string representation of VideoNoteConfig. | ||||
| func (config VideoNoteConfig) params() (map[string]string, error) { | ||||
| 	params, _ := config.BaseFile.params() | ||||
|  | ||||
| 	if config.Length != 0 { | ||||
| 		params["length"] = strconv.Itoa(config.Length) | ||||
| 	} | ||||
| 	if config.Duration != 0 { | ||||
| 		params["duration"] = strconv.Itoa(config.Duration) | ||||
| 	} | ||||
|  | ||||
| 	return params, nil | ||||
| } | ||||
|  | ||||
| // name returns the field name for the VideoNote. | ||||
| func (config VideoNoteConfig) name() string { | ||||
| 	return "video_note" | ||||
| } | ||||
|  | ||||
| // method returns Telegram API method name for sending VideoNote. | ||||
| func (config VideoNoteConfig) method() string { | ||||
| 	return "sendVideoNote" | ||||
| } | ||||
|  | ||||
| // VoiceConfig contains information about a SendVoice request. | ||||
| type VoiceConfig struct { | ||||
| 	BaseFile | ||||
| @@ -474,6 +537,9 @@ func (config VoiceConfig) values() (url.Values, error) { | ||||
| 	if config.Duration != 0 { | ||||
| 		v.Add("duration", strconv.Itoa(config.Duration)) | ||||
| 	} | ||||
| 	if config.Caption != "" { | ||||
| 		v.Add("caption", config.Caption) | ||||
| 	} | ||||
|  | ||||
| 	return v, nil | ||||
| } | ||||
| @@ -485,6 +551,9 @@ func (config VoiceConfig) params() (map[string]string, error) { | ||||
| 	if config.Duration != 0 { | ||||
| 		params["duration"] = strconv.Itoa(config.Duration) | ||||
| 	} | ||||
| 	if config.Caption != "" { | ||||
| 		params["caption"] = config.Caption | ||||
| 	} | ||||
|  | ||||
| 	return params, nil | ||||
| } | ||||
| @@ -814,9 +883,39 @@ type CallbackConfig struct { | ||||
| type ChatMemberConfig struct { | ||||
| 	ChatID             int64 | ||||
| 	SuperGroupUsername string | ||||
| 	ChannelUsername    string | ||||
| 	UserID             int | ||||
| } | ||||
|  | ||||
| // KickChatMemberConfig contains extra fields to kick user | ||||
| type KickChatMemberConfig struct { | ||||
| 	ChatMemberConfig | ||||
| 	UntilDate int64 | ||||
| } | ||||
|  | ||||
| // RestrictChatMemberConfig contains fields to restrict members of chat | ||||
| type RestrictChatMemberConfig struct { | ||||
| 	ChatMemberConfig | ||||
| 	UntilDate             int64 | ||||
| 	CanSendMessages       *bool | ||||
| 	CanSendMediaMessages  *bool | ||||
| 	CanSendOtherMessages  *bool | ||||
| 	CanAddWebPagePreviews *bool | ||||
| } | ||||
|  | ||||
| // PromoteChatMemberConfig contains fields to promote members of chat | ||||
| type PromoteChatMemberConfig struct { | ||||
| 	ChatMemberConfig | ||||
| 	CanChangeInfo      *bool | ||||
| 	CanPostMessages    *bool | ||||
| 	CanEditMessages    *bool | ||||
| 	CanDeleteMessages  *bool | ||||
| 	CanInviteUsers     *bool | ||||
| 	CanRestrictMembers *bool | ||||
| 	CanPinMessages     *bool | ||||
| 	CanPromoteMembers  *bool | ||||
| } | ||||
|  | ||||
| // ChatConfig contains information about getting information on a chat. | ||||
| type ChatConfig struct { | ||||
| 	ChatID             int64 | ||||
| @@ -830,3 +929,147 @@ type ChatConfigWithUser struct { | ||||
| 	SuperGroupUsername string | ||||
| 	UserID             int | ||||
| } | ||||
|  | ||||
| // InvoiceConfig contains information for sendInvoice request. | ||||
| type InvoiceConfig struct { | ||||
| 	BaseChat | ||||
| 	Title               string          // required | ||||
| 	Description         string          // required | ||||
| 	Payload             string          // required | ||||
| 	ProviderToken       string          // required | ||||
| 	StartParameter      string          // required | ||||
| 	Currency            string          // required | ||||
| 	Prices              *[]LabeledPrice // required | ||||
| 	PhotoURL            string | ||||
| 	PhotoSize           int | ||||
| 	PhotoWidth          int | ||||
| 	PhotoHeight         int | ||||
| 	NeedName            bool | ||||
| 	NeedPhoneNumber     bool | ||||
| 	NeedEmail           bool | ||||
| 	NeedShippingAddress bool | ||||
| 	IsFlexible          bool | ||||
| } | ||||
|  | ||||
| func (config InvoiceConfig) values() (url.Values, error) { | ||||
| 	v, err := config.BaseChat.values() | ||||
| 	if err != nil { | ||||
| 		return v, err | ||||
| 	} | ||||
| 	v.Add("title", config.Title) | ||||
| 	v.Add("description", config.Description) | ||||
| 	v.Add("payload", config.Payload) | ||||
| 	v.Add("provider_token", config.ProviderToken) | ||||
| 	v.Add("start_parameter", config.StartParameter) | ||||
| 	v.Add("currency", config.Currency) | ||||
| 	data, err := json.Marshal(config.Prices) | ||||
| 	if err != nil { | ||||
| 		return v, err | ||||
| 	} | ||||
| 	v.Add("prices", string(data)) | ||||
| 	if config.PhotoURL != "" { | ||||
| 		v.Add("photo_url", config.PhotoURL) | ||||
| 	} | ||||
| 	if config.PhotoSize != 0 { | ||||
| 		v.Add("photo_size", strconv.Itoa(config.PhotoSize)) | ||||
| 	} | ||||
| 	if config.PhotoWidth != 0 { | ||||
| 		v.Add("photo_width", strconv.Itoa(config.PhotoWidth)) | ||||
| 	} | ||||
| 	if config.PhotoHeight != 0 { | ||||
| 		v.Add("photo_height", strconv.Itoa(config.PhotoHeight)) | ||||
| 	} | ||||
| 	if config.NeedName != false { | ||||
| 		v.Add("need_name", strconv.FormatBool(config.NeedName)) | ||||
| 	} | ||||
| 	if config.NeedPhoneNumber != false { | ||||
| 		v.Add("need_phone_number", strconv.FormatBool(config.NeedPhoneNumber)) | ||||
| 	} | ||||
| 	if config.NeedEmail != false { | ||||
| 		v.Add("need_email", strconv.FormatBool(config.NeedEmail)) | ||||
| 	} | ||||
| 	if config.NeedShippingAddress != false { | ||||
| 		v.Add("need_shipping_address", strconv.FormatBool(config.NeedShippingAddress)) | ||||
| 	} | ||||
| 	if config.IsFlexible != false { | ||||
| 		v.Add("is_flexible", strconv.FormatBool(config.IsFlexible)) | ||||
| 	} | ||||
|  | ||||
| 	return v, nil | ||||
| } | ||||
|  | ||||
| func (config InvoiceConfig) method() string { | ||||
| 	return "sendInvoice" | ||||
| } | ||||
|  | ||||
| // ShippingConfig contains information for answerShippingQuery request. | ||||
| type ShippingConfig struct { | ||||
| 	ShippingQueryID string // required | ||||
| 	OK              bool   // required | ||||
| 	ShippingOptions *[]ShippingOption | ||||
| 	ErrorMessage    string | ||||
| } | ||||
|  | ||||
| // PreCheckoutConfig conatins information for answerPreCheckoutQuery request. | ||||
| type PreCheckoutConfig struct { | ||||
| 	PreCheckoutQueryID string // required | ||||
| 	OK                 bool   // required | ||||
| 	ErrorMessage       string | ||||
| } | ||||
|  | ||||
| // DeleteMessageConfig contains information of a message in a chat to delete. | ||||
| type DeleteMessageConfig struct { | ||||
| 	ChatID    int64 | ||||
| 	MessageID int | ||||
| } | ||||
|  | ||||
| func (config DeleteMessageConfig) method() string { | ||||
| 	return "deleteMessage" | ||||
| } | ||||
|  | ||||
| func (config DeleteMessageConfig) values() (url.Values, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) | ||||
| 	v.Add("message_id", strconv.Itoa(config.MessageID)) | ||||
|  | ||||
| 	return v, nil | ||||
| } | ||||
|  | ||||
| // PinChatMessageConfig contains information of a message in a chat to pin. | ||||
| type PinChatMessageConfig struct { | ||||
| 	ChatID int64 | ||||
| 	MessageID int | ||||
| 	DisableNotification bool | ||||
| } | ||||
|  | ||||
| func (config PinChatMessageConfig) method() string { | ||||
| 	return "pinChatMessage" | ||||
| } | ||||
|  | ||||
| func (config PinChatMessageConfig) values() (url.Values, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) | ||||
| 	v.Add("message_id", strconv.Itoa(config.MessageID)) | ||||
| 	v.Add("disable_notification", strconv.FormatBool(config.DisableNotification)) | ||||
|  | ||||
| 	return v, nil | ||||
| } | ||||
|  | ||||
| // UnpinChatMessageConfig contains information of chat to unpin. | ||||
| type UnpinChatMessageConfig struct { | ||||
| 	ChatID int64 | ||||
| } | ||||
|  | ||||
| func (config UnpinChatMessageConfig) method() string { | ||||
| 	return "unpinChatMessage" | ||||
| } | ||||
|  | ||||
| func (config UnpinChatMessageConfig) values() (url.Values, error) { | ||||
| 	v := url.Values{} | ||||
|  | ||||
| 	v.Add("chat_id", strconv.FormatInt(config.ChatID, 10)) | ||||
|  | ||||
| 	return v, nil | ||||
| } | ||||
							
								
								
									
										44
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -194,6 +194,37 @@ func NewVideoShare(chatID int64, fileID string) VideoConfig { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NewVideoNoteUpload creates a new video note uploader. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| func NewVideoNoteUpload(chatID int64, length int, file interface{}) VideoNoteConfig { | ||||
| 	return VideoNoteConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 		}, | ||||
| 		Length: length, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NewVideoNoteShare shares an existing video. | ||||
| // You may use this to reshare an existing video without reuploading it. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the video | ||||
| // already uploaded. | ||||
| func NewVideoNoteShare(chatID int64, length int, fileID string) VideoNoteConfig { | ||||
| 	return VideoNoteConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| 		}, | ||||
| 		Length: length, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NewVoiceUpload creates a new voice uploader. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| @@ -609,3 +640,16 @@ func NewCallbackWithAlert(id, text string) CallbackConfig { | ||||
| 		ShowAlert:       true, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NewInvoice created a new Invoice request to the user. | ||||
| func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices *[]LabeledPrice) InvoiceConfig { | ||||
| 	return InvoiceConfig{ | ||||
| 		BaseChat:       BaseChat{ChatID: chatID}, | ||||
| 		Title:          title, | ||||
| 		Description:    description, | ||||
| 		Payload:        payload, | ||||
| 		ProviderToken:  providerToken, | ||||
| 		StartParameter: startParameter, | ||||
| 		Currency:       currency, | ||||
| 		Prices:         prices} | ||||
| } | ||||
|   | ||||
							
								
								
									
										205
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										205
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -35,6 +35,8 @@ type Update struct { | ||||
| 	InlineQuery        *InlineQuery        `json:"inline_query"` | ||||
| 	ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"` | ||||
| 	CallbackQuery      *CallbackQuery      `json:"callback_query"` | ||||
| 	ShippingQuery      *ShippingQuery      `json:"shipping_query"` | ||||
| 	PreCheckoutQuery   *PreCheckoutQuery   `json:"pre_checkout_query"` | ||||
| } | ||||
|  | ||||
| // UpdatesChannel is the channel for getting updates. | ||||
| @@ -49,10 +51,11 @@ func (ch UpdatesChannel) Clear() { | ||||
|  | ||||
| // User is a user on Telegram. | ||||
| type User struct { | ||||
| 	ID        int    `json:"id"` | ||||
| 	FirstName string `json:"first_name"` | ||||
| 	LastName  string `json:"last_name"` // optional | ||||
| 	UserName  string `json:"username"`  // optional | ||||
| 	ID           int    `json:"id"` | ||||
| 	FirstName    string `json:"first_name"` | ||||
| 	LastName     string `json:"last_name"`     // optional | ||||
| 	UserName     string `json:"username"`      // optional | ||||
| 	LanguageCode string `json:"language_code"` // optional | ||||
| } | ||||
|  | ||||
| // String displays a simple text version of a user. | ||||
| @@ -78,15 +81,24 @@ type GroupChat struct { | ||||
| 	Title string `json:"title"` | ||||
| } | ||||
|  | ||||
| // ChatPhoto represents a chat photo. | ||||
| type ChatPhoto struct { | ||||
| 	SmallFileID string `json:"small_file_id"` | ||||
| 	BigFileID   string `json:"big_file_id"` | ||||
| } | ||||
|  | ||||
| // Chat contains information about the place a message was sent. | ||||
| type Chat struct { | ||||
| 	ID                  int64  `json:"id"` | ||||
| 	Type                string `json:"type"` | ||||
| 	Title               string `json:"title"`                          // optional | ||||
| 	UserName            string `json:"username"`                       // optional | ||||
| 	FirstName           string `json:"first_name"`                     // optional | ||||
| 	LastName            string `json:"last_name"`                      // optional | ||||
| 	AllMembersAreAdmins bool   `json:"all_members_are_administrators"` // optional | ||||
| 	ID                  int64      `json:"id"` | ||||
| 	Type                string     `json:"type"` | ||||
| 	Title               string     `json:"title"`                          // optional | ||||
| 	UserName            string     `json:"username"`                       // optional | ||||
| 	FirstName           string     `json:"first_name"`                     // optional | ||||
| 	LastName            string     `json:"last_name"`                      // optional | ||||
| 	AllMembersAreAdmins bool       `json:"all_members_are_administrators"` // optional | ||||
| 	Photo               *ChatPhoto `json:"photo"` | ||||
| 	Description         string     `json:"description,omitempty"` // optional | ||||
| 	InviteLink          string     `json:"invite_link,omitempty"` // optional | ||||
| } | ||||
|  | ||||
| // IsPrivate returns if the Chat is a private conversation. | ||||
| @@ -117,40 +129,43 @@ func (c Chat) ChatConfig() ChatConfig { | ||||
| // Message is returned by almost every request, and contains data about | ||||
| // almost anything. | ||||
| type Message struct { | ||||
| 	MessageID             int              `json:"message_id"` | ||||
| 	From                  *User            `json:"from"` // optional | ||||
| 	Date                  int              `json:"date"` | ||||
| 	Chat                  *Chat            `json:"chat"` | ||||
| 	ForwardFrom           *User            `json:"forward_from"`            // optional | ||||
| 	ForwardFromChat       *Chat            `json:"forward_from_chat"`       // optional | ||||
| 	ForwardFromMessageID  int              `json:"forward_from_message_id"` // optional | ||||
| 	ForwardDate           int              `json:"forward_date"`            // optional | ||||
| 	ReplyToMessage        *Message         `json:"reply_to_message"`        // optional | ||||
| 	EditDate              int              `json:"edit_date"`               // optional | ||||
| 	Text                  string           `json:"text"`                    // optional | ||||
| 	Entities              *[]MessageEntity `json:"entities"`                // optional | ||||
| 	Audio                 *Audio           `json:"audio"`                   // optional | ||||
| 	Document              *Document        `json:"document"`                // optional | ||||
| 	Game                  *Game            `json:"game"`                    // optional | ||||
| 	Photo                 *[]PhotoSize     `json:"photo"`                   // optional | ||||
| 	Sticker               *Sticker         `json:"sticker"`                 // optional | ||||
| 	Video                 *Video           `json:"video"`                   // optional | ||||
| 	Voice                 *Voice           `json:"voice"`                   // optional | ||||
| 	Caption               string           `json:"caption"`                 // optional | ||||
| 	Contact               *Contact         `json:"contact"`                 // optional | ||||
| 	Location              *Location        `json:"location"`                // optional | ||||
| 	Venue                 *Venue           `json:"venue"`                   // optional | ||||
| 	NewChatMember         *User            `json:"new_chat_member"`         // optional | ||||
| 	LeftChatMember        *User            `json:"left_chat_member"`        // optional | ||||
| 	NewChatTitle          string           `json:"new_chat_title"`          // optional | ||||
| 	NewChatPhoto          *[]PhotoSize     `json:"new_chat_photo"`          // optional | ||||
| 	DeleteChatPhoto       bool             `json:"delete_chat_photo"`       // optional | ||||
| 	GroupChatCreated      bool             `json:"group_chat_created"`      // optional | ||||
| 	SuperGroupChatCreated bool             `json:"supergroup_chat_created"` // optional | ||||
| 	ChannelChatCreated    bool             `json:"channel_chat_created"`    // optional | ||||
| 	MigrateToChatID       int64            `json:"migrate_to_chat_id"`      // optional | ||||
| 	MigrateFromChatID     int64            `json:"migrate_from_chat_id"`    // optional | ||||
| 	PinnedMessage         *Message         `json:"pinned_message"`          // optional | ||||
| 	MessageID             int                `json:"message_id"` | ||||
| 	From                  *User              `json:"from"` // optional | ||||
| 	Date                  int                `json:"date"` | ||||
| 	Chat                  *Chat              `json:"chat"` | ||||
| 	ForwardFrom           *User              `json:"forward_from"`            // optional | ||||
| 	ForwardFromChat       *Chat              `json:"forward_from_chat"`       // optional | ||||
| 	ForwardFromMessageID  int                `json:"forward_from_message_id"` // optional | ||||
| 	ForwardDate           int                `json:"forward_date"`            // optional | ||||
| 	ReplyToMessage        *Message           `json:"reply_to_message"`        // optional | ||||
| 	EditDate              int                `json:"edit_date"`               // optional | ||||
| 	Text                  string             `json:"text"`                    // optional | ||||
| 	Entities              *[]MessageEntity   `json:"entities"`                // optional | ||||
| 	Audio                 *Audio             `json:"audio"`                   // optional | ||||
| 	Document              *Document          `json:"document"`                // optional | ||||
| 	Game                  *Game              `json:"game"`                    // optional | ||||
| 	Photo                 *[]PhotoSize       `json:"photo"`                   // optional | ||||
| 	Sticker               *Sticker           `json:"sticker"`                 // optional | ||||
| 	Video                 *Video             `json:"video"`                   // optional | ||||
| 	VideoNote             *VideoNote         `json:"video_note"`              // optional | ||||
| 	Voice                 *Voice             `json:"voice"`                   // optional | ||||
| 	Caption               string             `json:"caption"`                 // optional | ||||
| 	Contact               *Contact           `json:"contact"`                 // optional | ||||
| 	Location              *Location          `json:"location"`                // optional | ||||
| 	Venue                 *Venue             `json:"venue"`                   // optional | ||||
| 	NewChatMembers        *[]User            `json:"new_chat_members"`        // optional | ||||
| 	LeftChatMember        *User              `json:"left_chat_member"`        // optional | ||||
| 	NewChatTitle          string             `json:"new_chat_title"`          // optional | ||||
| 	NewChatPhoto          *[]PhotoSize       `json:"new_chat_photo"`          // optional | ||||
| 	DeleteChatPhoto       bool               `json:"delete_chat_photo"`       // optional | ||||
| 	GroupChatCreated      bool               `json:"group_chat_created"`      // optional | ||||
| 	SuperGroupChatCreated bool               `json:"supergroup_chat_created"` // optional | ||||
| 	ChannelChatCreated    bool               `json:"channel_chat_created"`    // optional | ||||
| 	MigrateToChatID       int64              `json:"migrate_to_chat_id"`      // optional | ||||
| 	MigrateFromChatID     int64              `json:"migrate_from_chat_id"`    // optional | ||||
| 	PinnedMessage         *Message           `json:"pinned_message"`          // optional | ||||
| 	Invoice               *Invoice           `json:"invoice"`                 // optional | ||||
| 	SuccessfulPayment     *SuccessfulPayment `json:"successful_payment"`      // optional | ||||
| } | ||||
|  | ||||
| // Time converts the message timestamp into a Time. | ||||
| @@ -263,6 +278,15 @@ type Video struct { | ||||
| 	FileSize  int        `json:"file_size"` // optional | ||||
| } | ||||
|  | ||||
| // VideoNote contains information about a video. | ||||
| type VideoNote struct { | ||||
| 	FileID    string     `json:"file_id"` | ||||
| 	Length    int        `json:"length"` | ||||
| 	Duration  int        `json:"duration"` | ||||
| 	Thumbnail *PhotoSize `json:"thumb"`     // optional | ||||
| 	FileSize  int        `json:"file_size"` // optional | ||||
| } | ||||
|  | ||||
| // Voice contains information about a voice. | ||||
| type Voice struct { | ||||
| 	FileID   string `json:"file_id"` | ||||
| @@ -361,6 +385,7 @@ type InlineKeyboardButton struct { | ||||
| 	SwitchInlineQuery            *string       `json:"switch_inline_query,omitempty"`              // optional | ||||
| 	SwitchInlineQueryCurrentChat *string       `json:"switch_inline_query_current_chat,omitempty"` // optional | ||||
| 	CallbackGame                 *CallbackGame `json:"callback_game,omitempty"`                    // optional | ||||
| 	Pay                          bool          `json:"pay,omitempty"`			       // optional | ||||
| } | ||||
|  | ||||
| // CallbackQuery is data sent when a keyboard button with callback data | ||||
| @@ -384,8 +409,22 @@ type ForceReply struct { | ||||
|  | ||||
| // ChatMember is information about a member in a chat. | ||||
| type ChatMember struct { | ||||
| 	User   *User  `json:"user"` | ||||
| 	Status string `json:"status"` | ||||
| 	User                  *User  `json:"user"` | ||||
| 	Status                string `json:"status"` | ||||
| 	UntilDate             int64  `json:"until_date,omitempty"`                // optional | ||||
| 	CanBeEdited           bool   `json:"can_be_edited,omitempty"`             // optional | ||||
| 	CanChangeInfo         bool   `json:"can_change_info,omitempty"`           // optional | ||||
| 	CanPostMessages       bool   `json:"can_post_messages,omitempty"`         // optional | ||||
| 	CanEditMessages       bool   `json:"can_edit_messages,omitempty"`         // optional | ||||
| 	CanDeleteMessages     bool   `json:"can_delete_messages,omitempty"`       // optional | ||||
| 	CanInviteUsers        bool   `json:"can_invite_users,omitempty"`          // optional | ||||
| 	CanRestrictMembers    bool   `json:"can_restrict_members,omitempty"`      // optional | ||||
| 	CanPinMessages        bool   `json:"can_pin_messages,omitempty"`          // optional | ||||
| 	CanPromoteMembers     bool   `json:"can_promote_members,omitempty"`       // optional | ||||
| 	CanSendMessages       bool   `json:"can_send_messages,omitempty"`         // optional | ||||
| 	CanSendMediaMessages  bool   `json:"can_send_media_messages,omitempty"`   // optional | ||||
| 	CanSendOtherMessages  bool   `json:"can_send_other_messages,omitempty"`   // optional | ||||
| 	CanAddWebPagePreviews bool   `json:"can_add_web_page_previews,omitempty"` // optional | ||||
| } | ||||
|  | ||||
| // IsCreator returns if the ChatMember was the creator of the chat. | ||||
| @@ -493,6 +532,7 @@ type InlineQueryResultGIF struct { | ||||
| 	URL                 string                `json:"gif_url"` // required | ||||
| 	Width               int                   `json:"gif_width"` | ||||
| 	Height              int                   `json:"gif_height"` | ||||
| 	Duration            int                   `json:"gif_duration"` | ||||
| 	ThumbURL            string                `json:"thumb_url"` | ||||
| 	Title               string                `json:"title"` | ||||
| 	Caption             string                `json:"caption"` | ||||
| @@ -507,6 +547,7 @@ type InlineQueryResultMPEG4GIF struct { | ||||
| 	URL                 string                `json:"mpeg4_url"` // required | ||||
| 	Width               int                   `json:"mpeg4_width"` | ||||
| 	Height              int                   `json:"mpeg4_height"` | ||||
| 	Duration            int                   `json:"mpeg4_duration"` | ||||
| 	ThumbURL            string                `json:"thumb_url"` | ||||
| 	Title               string                `json:"title"` | ||||
| 	Caption             string                `json:"caption"` | ||||
| @@ -635,3 +676,73 @@ type InputContactMessageContent struct { | ||||
| 	FirstName   string `json:"first_name"` | ||||
| 	LastName    string `json:"last_name"` | ||||
| } | ||||
|  | ||||
| // Invoice contains basic information about an invoice. | ||||
| type Invoice struct { | ||||
| 	Title          string `json:"title"` | ||||
| 	Description    string `json:"description"` | ||||
| 	StartParameter string `json:"start_parameter"` | ||||
| 	Currency       string `json:"currency"` | ||||
| 	TotalAmount    int    `json:"total_amount"` | ||||
| } | ||||
|  | ||||
| // LabeledPrice represents a portion of the price for goods or services. | ||||
| type LabeledPrice struct { | ||||
| 	Label  string `json:"label"` | ||||
| 	Amount int    `json:"amount"` | ||||
| } | ||||
|  | ||||
| // ShippingAddress represents a shipping address. | ||||
| type ShippingAddress struct { | ||||
| 	CountryCode string `json:"country_code"` | ||||
| 	State       string `json:"state"` | ||||
| 	City        string `json:"city"` | ||||
| 	StreetLine1 string `json:"street_line1"` | ||||
| 	StreetLine2 string `json:"street_line2"` | ||||
| 	PostCode    string `json:"post_code"` | ||||
| } | ||||
|  | ||||
| // OrderInfo represents information about an order. | ||||
| type OrderInfo struct { | ||||
| 	Name            string           `json:"name,omitempty"` | ||||
| 	PhoneNumber     string           `json:"phone_number,omitempty"` | ||||
| 	Email           string           `json:"email,omitempty"` | ||||
| 	ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"` | ||||
| } | ||||
|  | ||||
| // ShippingOption represents one shipping option. | ||||
| type ShippingOption struct { | ||||
| 	ID     string          `json:"id"` | ||||
| 	Title  string          `json:"title"` | ||||
| 	Prices *[]LabeledPrice `json:"prices"` | ||||
| } | ||||
|  | ||||
| // SuccessfulPayment contains basic information about a successful payment. | ||||
| type SuccessfulPayment struct { | ||||
| 	Currency                string     `json:"currency"` | ||||
| 	TotalAmount             int        `json:"total_amount"` | ||||
| 	InvoicePayload          string     `json:"invoice_payload"` | ||||
| 	ShippingOptionID        string     `json:"shipping_option_id,omitempty"` | ||||
| 	OrderInfo               *OrderInfo `json:"order_info,omitempty"` | ||||
| 	TelegramPaymentChargeID string     `json:"telegram_payment_charge_id"` | ||||
| 	ProviderPaymentChargeID string     `json:"provider_payment_charge_id"` | ||||
| } | ||||
|  | ||||
| // ShippingQuery contains information about an incoming shipping query. | ||||
| type ShippingQuery struct { | ||||
| 	ID              string           `json:"id"` | ||||
| 	From            *User            `json:"from"` | ||||
| 	InvoicePayload  string           `json:"invoice_payload"` | ||||
| 	ShippingAddress *ShippingAddress `json:"shipping_address"` | ||||
| } | ||||
|  | ||||
| // PreCheckoutQuery contains information about an incoming pre-checkout query. | ||||
| type PreCheckoutQuery struct { | ||||
| 	ID               string     `json:"id"` | ||||
| 	From             *User      `json:"from"` | ||||
| 	Currency         string     `json:"currency"` | ||||
| 	TotalAmount      int        `json:"total_amount"` | ||||
| 	InvoicePayload   string     `json:"invoice_payload"` | ||||
| 	ShippingOptionID string     `json:"shipping_option_id,omitempty"` | ||||
| 	OrderInfo        *OrderInfo `json:"order_info,omitempty"` | ||||
| } | ||||
|   | ||||
							
								
								
									
										22
									
								
								vendor/github.com/mattermost/platform/einterfaces/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/mattermost/platform/einterfaces/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,32 +1,32 @@ | ||||
| Mattermost Licensing | ||||
|  | ||||
| SOFTWARE LICENSING  | ||||
| SOFTWARE LICENSING | ||||
|  | ||||
| You are licensed to use compiled versions of the Mattermost platform produced by Mattermost, Inc. under an MIT LICENSE  | ||||
| You are licensed to use compiled versions of the Mattermost platform produced by Mattermost, Inc. under an MIT LICENSE | ||||
|  | ||||
| -	See MIT-COMPILED-LICENSE.md included in compiled versions for details | ||||
|  | ||||
| You may be licensed to use source code to create compiled versions not produced by Mattermost, Inc. in one of two ways: | ||||
|  | ||||
| 1. Under the Free Software Foundation’s GNU AGPL v.3.0, subject to the exceptions outlined in this policy; or  | ||||
| 2. Under a commercial license available from Mattermost, Inc. by contacting commercial@mattermost.com  | ||||
| 1. Under the Free Software Foundation’s GNU AGPL v.3.0, subject to the exceptions outlined in this policy; or | ||||
| 2. Under a commercial license available from Mattermost, Inc. by contacting commercial@mattermost.com | ||||
|  | ||||
| You are licensed to use the source code in Admin Tools and Configuration Files (templates/, config/, model/,  | ||||
| You are licensed to use the source code in Admin Tools and Configuration Files (templates/, config/, model/, | ||||
| webapp/client, webapp/fonts, webapp/i18n, webapp/images and all subdirectories thereof) under the Apache License v2.0. | ||||
|  | ||||
| We promise that we will not enforce the copyleft provisions in AGPL v3.0 against you if your application (a) does not  | ||||
| We promise that we will not enforce the copyleft provisions in AGPL v3.0 against you if your application (a) does not | ||||
| link to the Mattermost Platform directly, but exclusively uses the Mattermost Admin Tools and Configuration Files, and | ||||
| (b) you have not modified, added to or adapted the source code of Mattermost in a way that results in the creation of  | ||||
| (b) you have not modified, added to or adapted the source code of Mattermost in a way that results in the creation of | ||||
| a “modified version” or “work based on” Mattermost as these terms are defined in the AGPL v3.0 license. | ||||
|  | ||||
| MATTERMOST TRADEMARK GUIDELINES | ||||
|  | ||||
| Your use of the mark Mattermost is subject to Mattermost, Inc's prior written approval and our organization’s Trademark  | ||||
| Standards of Use at http://www.mattermost.org/trademark-standards-of-use/. For trademark approval or any questions  | ||||
| you have about using these trademarks, please email trademark@mattermost.com  | ||||
| Your use of the mark Mattermost is subject to Mattermost, Inc's prior written approval and our organization’s Trademark | ||||
| Standards of Use at http://www.mattermost.org/trademark-standards-of-use/. For trademark approval or any questions | ||||
| you have about using these trademarks, please email trademark@mattermost.com | ||||
|  | ||||
| ------------------------------------------------------------------------------------------------------------------------------ | ||||
|                                 | ||||
|  | ||||
|                                Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/mattermost/platform/einterfaces/account_migration.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/mattermost/platform/einterfaces/account_migration.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
| @@ -6,7 +6,7 @@ package einterfaces | ||||
| import "github.com/mattermost/platform/model" | ||||
|  | ||||
| type AccountMigrationInterface interface { | ||||
| 	MigrateToLdap(fromAuthService string, forignUserFieldNameToMatch string) *model.AppError | ||||
| 	MigrateToLdap(fromAuthService string, forignUserFieldNameToMatch string, force bool) *model.AppError | ||||
| } | ||||
|  | ||||
| var theAccountMigrationInterface AccountMigrationInterface | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/brand.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/brand.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
|   | ||||
							
								
								
									
										25
									
								
								vendor/github.com/mattermost/platform/einterfaces/cluster.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/mattermost/platform/einterfaces/cluster.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
| @@ -7,26 +7,19 @@ import ( | ||||
| 	"github.com/mattermost/platform/model" | ||||
| ) | ||||
|  | ||||
| type ClusterMessageHandler func(msg *model.ClusterMessage) | ||||
|  | ||||
| type ClusterInterface interface { | ||||
| 	StartInterNodeCommunication() | ||||
| 	StopInterNodeCommunication() | ||||
| 	GetClusterInfos() []*model.ClusterInfo | ||||
| 	GetClusterStats() ([]*model.ClusterStats, *model.AppError) | ||||
| 	ClearSessionCacheForUser(userId string) | ||||
| 	InvalidateCacheForUser(userId string) | ||||
| 	InvalidateCacheForChannel(channelId string) | ||||
| 	InvalidateCacheForChannelByName(teamId, name string) | ||||
| 	InvalidateCacheForChannelMembers(channelId string) | ||||
| 	InvalidateCacheForChannelMembersNotifyProps(channelId string) | ||||
| 	InvalidateCacheForChannelPosts(channelId string) | ||||
| 	InvalidateCacheForWebhook(webhookId string) | ||||
| 	InvalidateCacheForReactions(postId string) | ||||
| 	Publish(event *model.WebSocketEvent) | ||||
| 	UpdateStatus(status *model.Status) | ||||
| 	GetLogs() ([]string, *model.AppError) | ||||
| 	RegisterClusterMessageHandler(event string, crm ClusterMessageHandler) | ||||
| 	GetClusterId() string | ||||
| 	GetClusterInfos() []*model.ClusterInfo | ||||
| 	SendClusterMessage(cluster *model.ClusterMessage) | ||||
| 	NotifyMsg(buf []byte) | ||||
| 	GetClusterStats() ([]*model.ClusterStats, *model.AppError) | ||||
| 	GetLogs(page, perPage int) ([]string, *model.AppError) | ||||
| 	ConfigChanged(previousConfig *model.Config, newConfig *model.Config, sendToOtherServer bool) *model.AppError | ||||
| 	InvalidateAllCaches() *model.AppError | ||||
| } | ||||
|  | ||||
| var theClusterInterface ClusterInterface | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/compliance.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/compliance.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
|   | ||||
							
								
								
									
										25
									
								
								vendor/github.com/mattermost/platform/einterfaces/elasticsearch.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/mattermost/platform/einterfaces/elasticsearch.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
|  | ||||
| import "github.com/mattermost/platform/model" | ||||
|  | ||||
| type ElasticsearchInterface interface { | ||||
| 	Start() *model.AppError | ||||
| 	IndexPost(post *model.Post, teamId string) *model.AppError | ||||
| 	SearchPosts(channels *model.ChannelList, searchParams []*model.SearchParams) ([]string, *model.AppError) | ||||
| 	DeletePost(post *model.Post) *model.AppError | ||||
| 	TestConfig(cfg *model.Config) *model.AppError | ||||
| 	PurgeIndexes() *model.AppError | ||||
| } | ||||
|  | ||||
| var theElasticsearchInterface ElasticsearchInterface | ||||
|  | ||||
| func RegisterElasticsearchInterface(newInterface ElasticsearchInterface) { | ||||
| 	theElasticsearchInterface = newInterface | ||||
| } | ||||
|  | ||||
| func GetElasticsearchInterface() ElasticsearchInterface { | ||||
| 	return theElasticsearchInterface | ||||
| } | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/emoji.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/emoji.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
|   | ||||
							
								
								
									
										23
									
								
								vendor/github.com/mattermost/platform/einterfaces/jobs/data_retention.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/mattermost/platform/einterfaces/jobs/data_retention.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package jobs | ||||
|  | ||||
| import ( | ||||
| 	"github.com/mattermost/platform/model" | ||||
| ) | ||||
|  | ||||
| type DataRetentionInterface interface { | ||||
| 	MakeWorker() model.Worker | ||||
| 	MakeScheduler() model.Scheduler | ||||
| } | ||||
|  | ||||
| var theDataRetentionInterface DataRetentionInterface | ||||
|  | ||||
| func RegisterDataRetentionInterface(newInterface DataRetentionInterface) { | ||||
| 	theDataRetentionInterface = newInterface | ||||
| } | ||||
|  | ||||
| func GetDataRetentionInterface() DataRetentionInterface { | ||||
| 	return theDataRetentionInterface | ||||
| } | ||||
							
								
								
									
										22
									
								
								vendor/github.com/mattermost/platform/einterfaces/jobs/elasticsearch.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/mattermost/platform/einterfaces/jobs/elasticsearch.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package jobs | ||||
|  | ||||
| import ( | ||||
| 	"github.com/mattermost/platform/model" | ||||
| ) | ||||
|  | ||||
| type ElasticsearchIndexerInterface interface { | ||||
| 	MakeWorker() model.Worker | ||||
| } | ||||
|  | ||||
| var theElasticsearchIndexerInterface ElasticsearchIndexerInterface | ||||
|  | ||||
| func RegisterElasticsearchIndexerInterface(newInterface ElasticsearchIndexerInterface) { | ||||
| 	theElasticsearchIndexerInterface = newInterface | ||||
| } | ||||
|  | ||||
| func GetElasticsearchIndexerInterface() ElasticsearchIndexerInterface { | ||||
| 	return theElasticsearchIndexerInterface | ||||
| } | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/mattermost/platform/einterfaces/metrics.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/mattermost/platform/einterfaces/metrics.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
| @@ -33,6 +33,7 @@ type MetricsInterface interface { | ||||
| 	IncrementMemCacheHitCounterSession() | ||||
|  | ||||
| 	IncrementWebsocketEvent(eventType string) | ||||
| 	IncrementWebSocketBroadcast(eventType string) | ||||
|  | ||||
| 	AddMemCacheHitCounter(cacheName string, amount float64) | ||||
| 	AddMemCacheMissCounter(cacheName string, amount float64) | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/mfa.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/mfa.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/oauthproviders.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/einterfaces/oauthproviders.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/mattermost/platform/einterfaces/saml.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/mattermost/platform/einterfaces/saml.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package einterfaces | ||||
| @@ -10,7 +10,7 @@ import ( | ||||
| type SamlInterface interface { | ||||
| 	ConfigureSP() *model.AppError | ||||
| 	BuildRequest(relayState string) (*model.SamlAuthRequest, *model.AppError) | ||||
| 	DoLogin(encodedXML string, relayState map[string]string, siteURL string) (*model.User, *model.AppError) | ||||
| 	DoLogin(encodedXML string, relayState map[string]string) (*model.User, *model.AppError) | ||||
| 	GetMetadata() (string, *model.AppError) | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										22
									
								
								vendor/github.com/mattermost/platform/model/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/mattermost/platform/model/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,32 +1,32 @@ | ||||
| Mattermost Licensing | ||||
|  | ||||
| SOFTWARE LICENSING  | ||||
| SOFTWARE LICENSING | ||||
|  | ||||
| You are licensed to use compiled versions of the Mattermost platform produced by Mattermost, Inc. under an MIT LICENSE  | ||||
| You are licensed to use compiled versions of the Mattermost platform produced by Mattermost, Inc. under an MIT LICENSE | ||||
|  | ||||
| -	See MIT-COMPILED-LICENSE.md included in compiled versions for details | ||||
|  | ||||
| You may be licensed to use source code to create compiled versions not produced by Mattermost, Inc. in one of two ways: | ||||
|  | ||||
| 1. Under the Free Software Foundation’s GNU AGPL v.3.0, subject to the exceptions outlined in this policy; or  | ||||
| 2. Under a commercial license available from Mattermost, Inc. by contacting commercial@mattermost.com  | ||||
| 1. Under the Free Software Foundation’s GNU AGPL v.3.0, subject to the exceptions outlined in this policy; or | ||||
| 2. Under a commercial license available from Mattermost, Inc. by contacting commercial@mattermost.com | ||||
|  | ||||
| You are licensed to use the source code in Admin Tools and Configuration Files (templates/, config/, model/,  | ||||
| You are licensed to use the source code in Admin Tools and Configuration Files (templates/, config/, model/, | ||||
| webapp/client, webapp/fonts, webapp/i18n, webapp/images and all subdirectories thereof) under the Apache License v2.0. | ||||
|  | ||||
| We promise that we will not enforce the copyleft provisions in AGPL v3.0 against you if your application (a) does not  | ||||
| We promise that we will not enforce the copyleft provisions in AGPL v3.0 against you if your application (a) does not | ||||
| link to the Mattermost Platform directly, but exclusively uses the Mattermost Admin Tools and Configuration Files, and | ||||
| (b) you have not modified, added to or adapted the source code of Mattermost in a way that results in the creation of  | ||||
| (b) you have not modified, added to or adapted the source code of Mattermost in a way that results in the creation of | ||||
| a “modified version” or “work based on” Mattermost as these terms are defined in the AGPL v3.0 license. | ||||
|  | ||||
| MATTERMOST TRADEMARK GUIDELINES | ||||
|  | ||||
| Your use of the mark Mattermost is subject to Mattermost, Inc's prior written approval and our organization’s Trademark  | ||||
| Standards of Use at http://www.mattermost.org/trademark-standards-of-use/. For trademark approval or any questions  | ||||
| you have about using these trademarks, please email trademark@mattermost.com  | ||||
| Your use of the mark Mattermost is subject to Mattermost, Inc's prior written approval and our organization’s Trademark | ||||
| Standards of Use at http://www.mattermost.org/trademark-standards-of-use/. For trademark approval or any questions | ||||
| you have about using these trademarks, please email trademark@mattermost.com | ||||
|  | ||||
| ------------------------------------------------------------------------------------------------------------------------------ | ||||
|                                 | ||||
|  | ||||
|                                Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/github.com/mattermost/platform/model/access.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/mattermost/platform/model/access.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -21,6 +21,7 @@ type AccessData struct { | ||||
| 	RefreshToken string `json:"refresh_token"` | ||||
| 	RedirectUri  string `json:"redirect_uri"` | ||||
| 	ExpiresAt    int64  `json:"expires_at"` | ||||
| 	Scope        string `json:"scope"` | ||||
| } | ||||
|  | ||||
| type AccessResponse struct { | ||||
| @@ -51,7 +52,7 @@ func (ad *AccessData) IsValid() *AppError { | ||||
| 		return NewLocAppError("AccessData.IsValid", "model.access.is_valid.refresh_token.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if len(ad.RedirectUri) > 256 { | ||||
| 	if len(ad.RedirectUri) == 0 || len(ad.RedirectUri) > 256 || !IsValidHttpUrl(ad.RedirectUri) { | ||||
| 		return NewLocAppError("AccessData.IsValid", "model.access.is_valid.redirect_uri.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/analytics_row.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/analytics_row.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/audit.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/audit.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/audits.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/audits.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										116
									
								
								vendor/github.com/mattermost/platform/model/authorization.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										116
									
								
								vendor/github.com/mattermost/platform/model/authorization.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -39,6 +39,7 @@ var PERMISSION_DELETE_PUBLIC_CHANNEL *Permission | ||||
| var PERMISSION_DELETE_PRIVATE_CHANNEL *Permission | ||||
| var PERMISSION_EDIT_OTHER_USERS *Permission | ||||
| var PERMISSION_READ_CHANNEL *Permission | ||||
| var PERMISSION_READ_PUBLIC_CHANNEL *Permission | ||||
| var PERMISSION_PERMANENT_DELETE_USER *Permission | ||||
| var PERMISSION_UPLOAD_FILE *Permission | ||||
| var PERMISSION_GET_PUBLIC_LINK *Permission | ||||
| @@ -47,6 +48,7 @@ var PERMISSION_MANAGE_OTHERS_WEBHOOKS *Permission | ||||
| var PERMISSION_MANAGE_OAUTH *Permission | ||||
| var PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH *Permission | ||||
| var PERMISSION_CREATE_POST *Permission | ||||
| var PERMISSION_CREATE_POST_PUBLIC *Permission | ||||
| var PERMISSION_EDIT_POST *Permission | ||||
| var PERMISSION_EDIT_OTHERS_POSTS *Permission | ||||
| var PERMISSION_DELETE_POST *Permission | ||||
| @@ -56,6 +58,11 @@ var PERMISSION_CREATE_TEAM *Permission | ||||
| var PERMISSION_MANAGE_TEAM *Permission | ||||
| var PERMISSION_IMPORT_TEAM *Permission | ||||
| var PERMISSION_VIEW_TEAM *Permission | ||||
| var PERMISSION_LIST_USERS_WITHOUT_TEAM *Permission | ||||
| var PERMISSION_MANAGE_JOBS *Permission | ||||
| var PERMISSION_CREATE_USER_ACCESS_TOKEN *Permission | ||||
| var PERMISSION_READ_USER_ACCESS_TOKEN *Permission | ||||
| var PERMISSION_REVOKE_USER_ACCESS_TOKEN *Permission | ||||
|  | ||||
| // General permission that encompases all system admin functions | ||||
| // in the future this could be broken up to allow access to some | ||||
| @@ -64,9 +71,14 @@ var PERMISSION_MANAGE_SYSTEM *Permission | ||||
|  | ||||
| var ROLE_SYSTEM_USER *Role | ||||
| var ROLE_SYSTEM_ADMIN *Role | ||||
| var ROLE_SYSTEM_POST_ALL *Role | ||||
| var ROLE_SYSTEM_POST_ALL_PUBLIC *Role | ||||
| var ROLE_SYSTEM_USER_ACCESS_TOKEN *Role | ||||
|  | ||||
| var ROLE_TEAM_USER *Role | ||||
| var ROLE_TEAM_ADMIN *Role | ||||
| var ROLE_TEAM_POST_ALL *Role | ||||
| var ROLE_TEAM_POST_ALL_PUBLIC *Role | ||||
|  | ||||
| var ROLE_CHANNEL_USER *Role | ||||
| var ROLE_CHANNEL_ADMIN *Role | ||||
| @@ -195,6 +207,11 @@ func InitalizePermissions() { | ||||
| 		"authentication.permissions.read_channel.name", | ||||
| 		"authentication.permissions.read_channel.description", | ||||
| 	} | ||||
| 	PERMISSION_READ_PUBLIC_CHANNEL = &Permission{ | ||||
| 		"read_public_channel", | ||||
| 		"authentication.permissions.read_public_channel.name", | ||||
| 		"authentication.permissions.read_public_channel.description", | ||||
| 	} | ||||
| 	PERMISSION_PERMANENT_DELETE_USER = &Permission{ | ||||
| 		"permanent_delete_user", | ||||
| 		"authentication.permissions.permanent_delete_user.name", | ||||
| @@ -235,6 +252,11 @@ func InitalizePermissions() { | ||||
| 		"authentication.permissions.create_post.name", | ||||
| 		"authentication.permissions.create_post.description", | ||||
| 	} | ||||
| 	PERMISSION_CREATE_POST_PUBLIC = &Permission{ | ||||
| 		"create_post_public", | ||||
| 		"authentication.permissions.create_post_public.name", | ||||
| 		"authentication.permissions.create_post_public.description", | ||||
| 	} | ||||
| 	PERMISSION_EDIT_POST = &Permission{ | ||||
| 		"edit_post", | ||||
| 		"authentication.permissions.edit_post.name", | ||||
| @@ -280,6 +302,31 @@ func InitalizePermissions() { | ||||
| 		"authentication.permissions.view_team.name", | ||||
| 		"authentication.permissions.view_team.description", | ||||
| 	} | ||||
| 	PERMISSION_LIST_USERS_WITHOUT_TEAM = &Permission{ | ||||
| 		"list_users_without_team", | ||||
| 		"authentication.permissions.list_users_without_team.name", | ||||
| 		"authentication.permissions.list_users_without_team.description", | ||||
| 	} | ||||
| 	PERMISSION_CREATE_USER_ACCESS_TOKEN = &Permission{ | ||||
| 		"create_user_access_token", | ||||
| 		"authentication.permissions.create_user_access_token.name", | ||||
| 		"authentication.permissions.create_user_access_token.description", | ||||
| 	} | ||||
| 	PERMISSION_READ_USER_ACCESS_TOKEN = &Permission{ | ||||
| 		"read_user_access_token", | ||||
| 		"authentication.permissions.read_user_access_token.name", | ||||
| 		"authentication.permissions.read_user_access_token.description", | ||||
| 	} | ||||
| 	PERMISSION_REVOKE_USER_ACCESS_TOKEN = &Permission{ | ||||
| 		"revoke_user_access_token", | ||||
| 		"authentication.permissions.revoke_user_access_token.name", | ||||
| 		"authentication.permissions.revoke_user_access_token.description", | ||||
| 	} | ||||
| 	PERMISSION_MANAGE_JOBS = &Permission{ | ||||
| 		"manage_jobs", | ||||
| 		"authentication.permisssions.manage_jobs.name", | ||||
| 		"authentication.permisssions.manage_jobs.description", | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func InitalizeRoles() { | ||||
| @@ -293,7 +340,6 @@ func InitalizeRoles() { | ||||
| 		[]string{ | ||||
| 			PERMISSION_READ_CHANNEL.Id, | ||||
| 			PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, | ||||
| 			PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, | ||||
| 			PERMISSION_UPLOAD_FILE.Id, | ||||
| 			PERMISSION_GET_PUBLIC_LINK.Id, | ||||
| 			PERMISSION_CREATE_POST.Id, | ||||
| @@ -326,17 +372,38 @@ func InitalizeRoles() { | ||||
| 		[]string{ | ||||
| 			PERMISSION_LIST_TEAM_CHANNELS.Id, | ||||
| 			PERMISSION_JOIN_PUBLIC_CHANNELS.Id, | ||||
| 			PERMISSION_READ_PUBLIC_CHANNEL.Id, | ||||
| 			PERMISSION_VIEW_TEAM.Id, | ||||
| 		}, | ||||
| 	} | ||||
| 	BuiltInRoles[ROLE_TEAM_USER.Id] = ROLE_TEAM_USER | ||||
|  | ||||
| 	ROLE_TEAM_POST_ALL = &Role{ | ||||
| 		"team_post_all", | ||||
| 		"authentication.roles.team_post_all.name", | ||||
| 		"authentication.roles.team_post_all.description", | ||||
| 		[]string{ | ||||
| 			PERMISSION_CREATE_POST.Id, | ||||
| 		}, | ||||
| 	} | ||||
| 	BuiltInRoles[ROLE_TEAM_POST_ALL.Id] = ROLE_TEAM_POST_ALL | ||||
|  | ||||
| 	ROLE_TEAM_POST_ALL_PUBLIC = &Role{ | ||||
| 		"team_post_all_public", | ||||
| 		"authentication.roles.team_post_all_public.name", | ||||
| 		"authentication.roles.team_post_all_public.description", | ||||
| 		[]string{ | ||||
| 			PERMISSION_CREATE_POST_PUBLIC.Id, | ||||
| 		}, | ||||
| 	} | ||||
| 	BuiltInRoles[ROLE_TEAM_POST_ALL_PUBLIC.Id] = ROLE_TEAM_POST_ALL_PUBLIC | ||||
|  | ||||
| 	ROLE_TEAM_ADMIN = &Role{ | ||||
| 		"team_admin", | ||||
| 		"authentication.roles.team_admin.name", | ||||
| 		"authentication.roles.team_admin.description", | ||||
| 		[]string{ | ||||
| 			PERMISSION_EDIT_OTHERS_POSTS.Id, | ||||
| 			PERMISSION_ADD_USER_TO_TEAM.Id, | ||||
| 			PERMISSION_REMOVE_USER_FROM_TEAM.Id, | ||||
| 			PERMISSION_MANAGE_TEAM.Id, | ||||
| 			PERMISSION_IMPORT_TEAM.Id, | ||||
| @@ -358,10 +425,42 @@ func InitalizeRoles() { | ||||
| 			PERMISSION_CREATE_DIRECT_CHANNEL.Id, | ||||
| 			PERMISSION_CREATE_GROUP_CHANNEL.Id, | ||||
| 			PERMISSION_PERMANENT_DELETE_USER.Id, | ||||
| 			PERMISSION_MANAGE_OAUTH.Id, | ||||
| 		}, | ||||
| 	} | ||||
| 	BuiltInRoles[ROLE_SYSTEM_USER.Id] = ROLE_SYSTEM_USER | ||||
|  | ||||
| 	ROLE_SYSTEM_POST_ALL = &Role{ | ||||
| 		"system_post_all", | ||||
| 		"authentication.roles.system_post_all.name", | ||||
| 		"authentication.roles.system_post_all.description", | ||||
| 		[]string{ | ||||
| 			PERMISSION_CREATE_POST.Id, | ||||
| 		}, | ||||
| 	} | ||||
| 	BuiltInRoles[ROLE_SYSTEM_POST_ALL.Id] = ROLE_SYSTEM_POST_ALL | ||||
|  | ||||
| 	ROLE_SYSTEM_POST_ALL_PUBLIC = &Role{ | ||||
| 		"system_post_all_public", | ||||
| 		"authentication.roles.system_post_all_public.name", | ||||
| 		"authentication.roles.system_post_all_public.description", | ||||
| 		[]string{ | ||||
| 			PERMISSION_CREATE_POST_PUBLIC.Id, | ||||
| 		}, | ||||
| 	} | ||||
| 	BuiltInRoles[ROLE_SYSTEM_POST_ALL_PUBLIC.Id] = ROLE_SYSTEM_POST_ALL_PUBLIC | ||||
|  | ||||
| 	ROLE_SYSTEM_USER_ACCESS_TOKEN = &Role{ | ||||
| 		"system_user_access_token", | ||||
| 		"authentication.roles.system_user_access_token.name", | ||||
| 		"authentication.roles.system_user_access_token.description", | ||||
| 		[]string{ | ||||
| 			PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, | ||||
| 			PERMISSION_READ_USER_ACCESS_TOKEN.Id, | ||||
| 			PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, | ||||
| 		}, | ||||
| 	} | ||||
| 	BuiltInRoles[ROLE_SYSTEM_USER_ACCESS_TOKEN.Id] = ROLE_SYSTEM_USER_ACCESS_TOKEN | ||||
|  | ||||
| 	ROLE_SYSTEM_ADMIN = &Role{ | ||||
| 		"system_admin", | ||||
| 		"authentication.roles.global_admin.name", | ||||
| @@ -378,6 +477,8 @@ func InitalizeRoles() { | ||||
| 							PERMISSION_MANAGE_SYSTEM.Id, | ||||
| 							PERMISSION_MANAGE_ROLES.Id, | ||||
| 							PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id, | ||||
| 							PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, | ||||
| 							PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id, | ||||
| 							PERMISSION_DELETE_PUBLIC_CHANNEL.Id, | ||||
| 							PERMISSION_CREATE_PUBLIC_CHANNEL.Id, | ||||
| 							PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id, | ||||
| @@ -391,6 +492,13 @@ func InitalizeRoles() { | ||||
| 							PERMISSION_DELETE_POST.Id, | ||||
| 							PERMISSION_DELETE_OTHERS_POSTS.Id, | ||||
| 							PERMISSION_CREATE_TEAM.Id, | ||||
| 							PERMISSION_ADD_USER_TO_TEAM.Id, | ||||
| 							PERMISSION_LIST_USERS_WITHOUT_TEAM.Id, | ||||
| 							PERMISSION_MANAGE_JOBS.Id, | ||||
| 							PERMISSION_CREATE_POST_PUBLIC.Id, | ||||
| 							PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, | ||||
| 							PERMISSION_READ_USER_ACCESS_TOKEN.Id, | ||||
| 							PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, | ||||
| 						}, | ||||
| 						ROLE_TEAM_USER.Permissions..., | ||||
| 					), | ||||
|   | ||||
							
								
								
									
										60
									
								
								vendor/github.com/mattermost/platform/model/authorize.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/mattermost/platform/model/authorize.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -6,6 +6,7 @@ package model | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -25,6 +26,14 @@ type AuthData struct { | ||||
| 	Scope       string `json:"scope"` | ||||
| } | ||||
|  | ||||
| type AuthorizeRequest struct { | ||||
| 	ResponseType string `json:"response_type"` | ||||
| 	ClientId     string `json:"client_id"` | ||||
| 	RedirectUri  string `json:"redirect_uri"` | ||||
| 	Scope        string `json:"scope"` | ||||
| 	State        string `json:"state"` | ||||
| } | ||||
|  | ||||
| // IsValid validates the AuthData and returns an error if it isn't configured | ||||
| // correctly. | ||||
| func (ad *AuthData) IsValid() *AppError { | ||||
| @@ -49,7 +58,7 @@ func (ad *AuthData) IsValid() *AppError { | ||||
| 		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.create_at.app_error", nil, "client_id="+ad.ClientId) | ||||
| 	} | ||||
|  | ||||
| 	if len(ad.RedirectUri) > 256 { | ||||
| 	if len(ad.RedirectUri) == 0 || len(ad.RedirectUri) > 256 || !IsValidHttpUrl(ad.RedirectUri) { | ||||
| 		return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ad.ClientId) | ||||
| 	} | ||||
|  | ||||
| @@ -64,6 +73,33 @@ func (ad *AuthData) IsValid() *AppError { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // IsValid validates the AuthorizeRequest and returns an error if it isn't configured | ||||
| // correctly. | ||||
| func (ar *AuthorizeRequest) IsValid() *AppError { | ||||
|  | ||||
| 	if len(ar.ClientId) != 26 { | ||||
| 		return NewAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(ar.ResponseType) == 0 { | ||||
| 		return NewAppError("AuthData.IsValid", "model.authorize.is_valid.response_type.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(ar.RedirectUri) == 0 || len(ar.RedirectUri) > 256 || !IsValidHttpUrl(ar.RedirectUri) { | ||||
| 		return NewAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(ar.State) > 128 { | ||||
| 		return NewAppError("AuthData.IsValid", "model.authorize.is_valid.state.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(ar.Scope) > 128 { | ||||
| 		return NewAppError("AuthData.IsValid", "model.authorize.is_valid.scope.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (ad *AuthData) PreSave() { | ||||
| 	if ad.ExpiresIn == 0 { | ||||
| 		ad.ExpiresIn = AUTHCODE_EXPIRE_TIME | ||||
| @@ -98,6 +134,26 @@ func AuthDataFromJson(data io.Reader) *AuthData { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (ar *AuthorizeRequest) ToJson() string { | ||||
| 	b, err := json.Marshal(ar) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} else { | ||||
| 		return string(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func AuthorizeRequestFromJson(data io.Reader) *AuthorizeRequest { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var ar AuthorizeRequest | ||||
| 	err := decoder.Decode(&ar) | ||||
| 	if err == nil { | ||||
| 		return &ar | ||||
| 	} else { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (ad *AuthData) IsExpired() bool { | ||||
|  | ||||
| 	if GetMillis() > ad.CreateAt+int64(ad.ExpiresIn*1000) { | ||||
|   | ||||
							
								
								
									
										47
									
								
								vendor/github.com/mattermost/platform/model/channel.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								vendor/github.com/mattermost/platform/model/channel.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -46,6 +46,13 @@ type Channel struct { | ||||
| 	CreatorId     string `json:"creator_id"` | ||||
| } | ||||
|  | ||||
| type ChannelPatch struct { | ||||
| 	DisplayName *string `json:"display_name"` | ||||
| 	Name        *string `json:"name"` | ||||
| 	Header      *string `json:"header"` | ||||
| 	Purpose     *string `json:"purpose"` | ||||
| } | ||||
|  | ||||
| func (o *Channel) ToJson() string { | ||||
| 	b, err := json.Marshal(o) | ||||
| 	if err != nil { | ||||
| @@ -55,6 +62,15 @@ func (o *Channel) ToJson() string { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *ChannelPatch) ToJson() string { | ||||
| 	b, err := json.Marshal(o) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} else { | ||||
| 		return string(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ChannelFromJson(data io.Reader) *Channel { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var o Channel | ||||
| @@ -66,6 +82,17 @@ func ChannelFromJson(data io.Reader) *Channel { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ChannelPatchFromJson(data io.Reader) *ChannelPatch { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var o ChannelPatch | ||||
| 	err := decoder.Decode(&o) | ||||
| 	if err == nil { | ||||
| 		return &o | ||||
| 	} else { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *Channel) Etag() string { | ||||
| 	return Etag(o.Id, o.UpdateAt) | ||||
| } | ||||
| @@ -137,6 +164,24 @@ func (o *Channel) IsGroupOrDirect() bool { | ||||
| 	return o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP | ||||
| } | ||||
|  | ||||
| func (o *Channel) Patch(patch *ChannelPatch) { | ||||
| 	if patch.DisplayName != nil { | ||||
| 		o.DisplayName = *patch.DisplayName | ||||
| 	} | ||||
|  | ||||
| 	if patch.Name != nil { | ||||
| 		o.Name = *patch.Name | ||||
| 	} | ||||
|  | ||||
| 	if patch.Header != nil { | ||||
| 		o.Header = *patch.Header | ||||
| 	} | ||||
|  | ||||
| 	if patch.Purpose != nil { | ||||
| 		o.Purpose = *patch.Purpose | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func GetDMNameFromIds(userId1, userId2 string) string { | ||||
| 	if userId1 > userId2 { | ||||
| 		return userId2 + "__" + userId1 | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_count.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_count.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_data.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_data.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										13
									
								
								vendor/github.com/mattermost/platform/model/channel_list.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/mattermost/platform/model/channel_list.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -50,3 +50,14 @@ func ChannelListFromJson(data io.Reader) *ChannelList { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ChannelSliceFromJson(data io.Reader) []*Channel { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var o []*Channel | ||||
| 	err := decoder.Decode(&o) | ||||
| 	if err == nil { | ||||
| 		return o | ||||
| 	} else { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										32
									
								
								vendor/github.com/mattermost/platform/model/channel_member.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								vendor/github.com/mattermost/platform/model/channel_member.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -19,11 +19,11 @@ const ( | ||||
| ) | ||||
|  | ||||
| type ChannelUnread struct { | ||||
| 	TeamId        string | ||||
| 	TotalMsgCount int64 | ||||
| 	MsgCount      int64 | ||||
| 	MentionCount  int64 | ||||
| 	NotifyProps   StringMap | ||||
| 	TeamId       string    `json:"team_id"` | ||||
| 	ChannelId    string    `json:"channel_id"` | ||||
| 	MsgCount     int64     `json:"msg_count"` | ||||
| 	MentionCount int64     `json:"mention_count"` | ||||
| 	NotifyProps  StringMap `json:"-"` | ||||
| } | ||||
|  | ||||
| type ChannelMember struct { | ||||
| @@ -47,6 +47,15 @@ func (o *ChannelMembers) ToJson() string { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *ChannelUnread) ToJson() string { | ||||
| 	b, err := json.Marshal(o) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} else { | ||||
| 		return string(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ChannelMembersFromJson(data io.Reader) *ChannelMembers { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var o ChannelMembers | ||||
| @@ -58,6 +67,17 @@ func ChannelMembersFromJson(data io.Reader) *ChannelMembers { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ChannelUnreadFromJson(data io.Reader) *ChannelUnread { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var o ChannelUnread | ||||
| 	err := decoder.Decode(&o) | ||||
| 	if err == nil { | ||||
| 		return &o | ||||
| 	} else { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *ChannelMember) ToJson() string { | ||||
| 	b, err := json.Marshal(o) | ||||
| 	if err != nil { | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_search.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_search.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_stats.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_stats.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_view.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/channel_view.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										80
									
								
								vendor/github.com/mattermost/platform/model/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										80
									
								
								vendor/github.com/mattermost/platform/model/client.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -1191,17 +1191,6 @@ func (c *Client) GetChannel(id, etag string) (*Result, *AppError) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SCHEDULED FOR DEPRECATION IN 3.7 - use GetMoreChannelsPage instead | ||||
| func (c *Client) GetMoreChannels(etag string) (*Result, *AppError) { | ||||
| 	if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/more", "", etag); err != nil { | ||||
| 		return nil, err | ||||
| 	} else { | ||||
| 		defer closeBody(r) | ||||
| 		return &Result{r.Header.Get(HEADER_REQUEST_ID), | ||||
| 			r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetMoreChannelsPage will return a page of open channels the user is not in based on | ||||
| // the provided offset and limit. Must be authenticated. | ||||
| func (c *Client) GetMoreChannelsPage(offset int, limit int) (*Result, *AppError) { | ||||
| @@ -1333,22 +1322,6 @@ func (c *Client) RemoveChannelMember(id, user_id string) (*Result, *AppError) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // UpdateLastViewedAt will mark a channel as read. | ||||
| // The channelId indicates the channel to mark as read. If active is true, push notifications | ||||
| // will be cleared if there are unread messages. The default for active is true. | ||||
| // SCHEDULED FOR DEPRECATION IN 3.8 - use ViewChannel instead | ||||
| func (c *Client) UpdateLastViewedAt(channelId string, active bool) (*Result, *AppError) { | ||||
| 	data := make(map[string]interface{}) | ||||
| 	data["active"] = active | ||||
| 	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/update_last_viewed_at", StringInterfaceToJson(data)); err != nil { | ||||
| 		return nil, err | ||||
| 	} else { | ||||
| 		defer closeBody(r) | ||||
| 		return &Result{r.Header.Get(HEADER_REQUEST_ID), | ||||
| 			r.Header.Get(HEADER_ETAG_SERVER), nil}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ViewChannel performs all the actions related to viewing a channel. This includes marking | ||||
| // the channel and the previous one as read, and marking the channel as being actively viewed. | ||||
| // ChannelId is required but may be blank to indicate no channel is being viewed. | ||||
| @@ -1533,6 +1506,16 @@ func (c *Client) GetFlaggedPosts(offset int, limit int) (*Result, *AppError) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *Client) GetPinnedPosts(channelId string) (*Result, *AppError) { | ||||
| 	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", "", ""); err != nil { | ||||
| 		return nil, err | ||||
| 	} else { | ||||
| 		defer closeBody(r) | ||||
| 		return &Result{r.Header.Get(HEADER_REQUEST_ID), | ||||
| 			r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *Client) UploadProfileFile(data []byte, contentType string) (*Result, *AppError) { | ||||
| 	return c.uploadFile(c.ApiUrl+"/users/newimage", data, contentType) | ||||
| } | ||||
| @@ -1782,22 +1765,6 @@ func (c *Client) GetStatusesByIds(userIds []string) (*Result, *AppError) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SetActiveChannel sets the the channel id the user is currently viewing. | ||||
| // The channelId key is required but the value can be blank. Returns standard | ||||
| // response. | ||||
| // SCHEDULED FOR DEPRECATION IN 3.8 - use ViewChannel instead | ||||
| func (c *Client) SetActiveChannel(channelId string) (*Result, *AppError) { | ||||
| 	data := map[string]string{} | ||||
| 	data["channel_id"] = channelId | ||||
| 	if r, err := c.DoApiPost("/users/status/set_active_channel", MapToJson(data)); err != nil { | ||||
| 		return nil, err | ||||
| 	} else { | ||||
| 		defer closeBody(r) | ||||
| 		return &Result{r.Header.Get(HEADER_REQUEST_ID), | ||||
| 			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *Client) GetMyTeam(etag string) (*Result, *AppError) { | ||||
| 	if r, err := c.DoApiGet(c.GetTeamRoute()+"/me", "", etag); err != nil { | ||||
| 		return nil, err | ||||
| @@ -1874,15 +1841,14 @@ func (c *Client) GetTeamStats(teamId string) (*Result, *AppError) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetTeamStats will return a team stats object containing the number of users on the team | ||||
| // based on the team id provided. Must be authenticated. | ||||
| // GetTeamByName will return a team object based on the team name provided. Must be authenticated. | ||||
| func (c *Client) GetTeamByName(teamName string) (*Result, *AppError) { | ||||
| 	if r, err := c.DoApiGet(fmt.Sprintf("/teams/name/%v", teamName), "", ""); err != nil { | ||||
| 		return nil, err | ||||
| 	} else { | ||||
| 		defer closeBody(r) | ||||
| 		return &Result{r.Header.Get(HEADER_REQUEST_ID), | ||||
| 			r.Header.Get(HEADER_ETAG_SERVER), TeamStatsFromJson(r.Body)}, nil | ||||
| 			r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -2389,3 +2355,23 @@ func (c *Client) UpdateChannelRoles(channelId string, userId string, roles strin | ||||
| 			} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *Client) PinPost(channelId string, postId string) (*Result, *AppError) { | ||||
| 	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/posts/"+postId+"/pin", ""); err != nil { | ||||
| 		return nil, err | ||||
| 	} else { | ||||
| 		defer closeBody(r) | ||||
| 		return &Result{r.Header.Get(HEADER_REQUEST_ID), | ||||
| 			r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *Client) UnpinPost(channelId string, postId string) (*Result, *AppError) { | ||||
| 	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/posts/"+postId+"/unpin", ""); err != nil { | ||||
| 		return nil, err | ||||
| 	} else { | ||||
| 		defer closeBody(r) | ||||
| 		return &Result{r.Header.Get(HEADER_REQUEST_ID), | ||||
| 			r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										2225
									
								
								vendor/github.com/mattermost/platform/model/client4.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2225
									
								
								vendor/github.com/mattermost/platform/model/client4.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										132
									
								
								vendor/github.com/mattermost/platform/model/cluster_discovery.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								vendor/github.com/mattermost/platform/model/cluster_discovery.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,132 @@ | ||||
| // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"os" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	CDS_OFFLINE_AFTER_MILLIS = 1000 * 60 * 30 // 30 minutes | ||||
| 	CDS_TYPE_APP             = "mattermost_app" | ||||
| ) | ||||
|  | ||||
| type ClusterDiscovery struct { | ||||
| 	Id          string `json:"id"` | ||||
| 	Type        string `json:"type"` | ||||
| 	ClusterName string `json:"cluster_name"` | ||||
| 	Hostname    string `json:"hostname"` | ||||
| 	GossipPort  int32  `json:"gossip_port"` | ||||
| 	Port        int32  `json:"port"` | ||||
| 	CreateAt    int64  `json:"create_at"` | ||||
| 	LastPingAt  int64  `json:"last_ping_at"` | ||||
| } | ||||
|  | ||||
| func (o *ClusterDiscovery) PreSave() { | ||||
| 	if o.Id == "" { | ||||
| 		o.Id = NewId() | ||||
| 	} | ||||
|  | ||||
| 	if o.CreateAt == 0 { | ||||
| 		o.CreateAt = GetMillis() | ||||
| 		o.LastPingAt = o.CreateAt | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *ClusterDiscovery) AutoFillHostname() { | ||||
| 	// attempt to set the hostname from the OS | ||||
| 	if len(o.Hostname) == 0 { | ||||
| 		if hn, err := os.Hostname(); err == nil { | ||||
| 			o.Hostname = hn | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *ClusterDiscovery) AutoFillIpAddress() { | ||||
| 	// attempt to set the hostname to the first non-local IP address | ||||
| 	if len(o.Hostname) == 0 { | ||||
| 		o.Hostname = GetServerIpAddress() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *ClusterDiscovery) IsEqual(in *ClusterDiscovery) bool { | ||||
| 	if in == nil { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if o.Type != in.Type { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterName != in.ClusterName { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if o.Hostname != in.Hostname { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func FilterClusterDiscovery(vs []*ClusterDiscovery, f func(*ClusterDiscovery) bool) []*ClusterDiscovery { | ||||
| 	copy := make([]*ClusterDiscovery, 0) | ||||
| 	for _, v := range vs { | ||||
| 		if f(v) { | ||||
| 			copy = append(copy, v) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return copy | ||||
| } | ||||
|  | ||||
| func (o *ClusterDiscovery) IsValid() *AppError { | ||||
| 	if len(o.Id) != 26 { | ||||
| 		return NewLocAppError("Channel.IsValid", "model.channel.is_valid.id.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if len(o.ClusterName) == 0 { | ||||
| 		return NewLocAppError("ClusterDiscovery.IsValid", "ClusterName must be set", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if len(o.Type) == 0 { | ||||
| 		return NewLocAppError("ClusterDiscovery.IsValid", "Type must be set", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if len(o.Hostname) == 0 { | ||||
| 		return NewLocAppError("ClusterDiscovery.IsValid", "Hostname must be set", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if o.CreateAt == 0 { | ||||
| 		return NewLocAppError("ClusterDiscovery.IsValid", "CreateAt must be set", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if o.LastPingAt == 0 { | ||||
| 		return NewLocAppError("ClusterDiscovery.IsValid", "LastPingAt must be set", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (o *ClusterDiscovery) ToJson() string { | ||||
| 	b, err := json.Marshal(o) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	return string(b) | ||||
| } | ||||
|  | ||||
| func ClusterDiscoveryFromJson(data io.Reader) *ClusterDiscovery { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var me ClusterDiscovery | ||||
| 	err := decoder.Decode(&me) | ||||
| 	if err == nil { | ||||
| 		return &me | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										27
									
								
								vendor/github.com/mattermost/platform/model/cluster_info.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/mattermost/platform/model/cluster_info.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -6,16 +6,14 @@ package model | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| type ClusterInfo struct { | ||||
| 	Id                 string `json:"id"` | ||||
| 	Version            string `json:"version"` | ||||
| 	ConfigHash         string `json:"config_hash"` | ||||
| 	InterNodeUrl       string `json:"internode_url"` | ||||
| 	Hostname           string `json:"hostname"` | ||||
| 	LastSuccessfulPing int64  `json:"last_ping"` | ||||
| 	IsAlive            bool   `json:"is_alive"` | ||||
| 	Version    string `json:"version"` | ||||
| 	ConfigHash string `json:"config_hash"` | ||||
| 	IpAddress  string `json:"ipaddress"` | ||||
| 	Hostname   string `json:"hostname"` | ||||
| } | ||||
|  | ||||
| func (me *ClusterInfo) ToJson() string { | ||||
| @@ -27,6 +25,11 @@ func (me *ClusterInfo) ToJson() string { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (me *ClusterInfo) Copy() *ClusterInfo { | ||||
| 	json := me.ToJson() | ||||
| 	return ClusterInfoFromJson(strings.NewReader(json)) | ||||
| } | ||||
|  | ||||
| func ClusterInfoFromJson(data io.Reader) *ClusterInfo { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var me ClusterInfo | ||||
| @@ -38,14 +41,6 @@ func ClusterInfoFromJson(data io.Reader) *ClusterInfo { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (me *ClusterInfo) HaveEstablishedInitialContact() bool { | ||||
| 	if me.Id != "" { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func ClusterInfosToJson(objmap []*ClusterInfo) string { | ||||
| 	if b, err := json.Marshal(objmap); err != nil { | ||||
| 		return "" | ||||
|   | ||||
							
								
								
									
										55
									
								
								vendor/github.com/mattermost/platform/model/cluster_message.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/mattermost/platform/model/cluster_message.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	CLUSTER_EVENT_PUBLISH                                           = "publish" | ||||
| 	CLUSTER_EVENT_UPDATE_STATUS                                     = "update_status" | ||||
| 	CLUSTER_EVENT_INVALIDATE_ALL_CACHES                             = "inv_all_caches" | ||||
| 	CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS                    = "inv_reactions" | ||||
| 	CLUSTER_EVENT_INVALIDATE_CACHE_FOR_WEBHOOK                      = "inv_webhook" | ||||
| 	CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_POSTS                = "inv_channel_posts" | ||||
| 	CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBERS_NOTIFY_PROPS = "inv_channel_members_notify_props" | ||||
| 	CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBERS              = "inv_channel_members" | ||||
| 	CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_BY_NAME              = "inv_channel_name" | ||||
| 	CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL                      = "inv_channel" | ||||
| 	CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER                         = "inv_user" | ||||
| 	CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER                      = "clear_session_user" | ||||
|  | ||||
| 	CLUSTER_SEND_BEST_EFFORT = "best_effort" | ||||
| 	CLUSTER_SEND_RELIABLE    = "reliable" | ||||
| ) | ||||
|  | ||||
| type ClusterMessage struct { | ||||
| 	Event            string            `json:"event"` | ||||
| 	SendType         string            `json:"-"` | ||||
| 	WaitForAllToSend bool              `json:"-"` | ||||
| 	Data             string            `json:"data,omitempty"` | ||||
| 	Props            map[string]string `json:"props,omitempty"` | ||||
| } | ||||
|  | ||||
| func (o *ClusterMessage) ToJson() string { | ||||
| 	b, err := json.Marshal(o) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} else { | ||||
| 		return string(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func ClusterMessageFromJson(data io.Reader) *ClusterMessage { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var o ClusterMessage | ||||
| 	err := decoder.Decode(&o) | ||||
| 	if err == nil { | ||||
| 		return &o | ||||
| 	} else { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/cluster_stats.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/cluster_stats.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/command.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/command.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										17
									
								
								vendor/github.com/mattermost/platform/model/command_args.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/mattermost/platform/model/command_args.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -6,13 +6,20 @@ package model | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
|  | ||||
| 	goi18n "github.com/nicksnyder/go-i18n/i18n" | ||||
| ) | ||||
|  | ||||
| type CommandArgs struct { | ||||
| 	ChannelId string `json:"channel_id"` | ||||
| 	RootId    string `json:"root_id"` | ||||
| 	ParentId  string `json:"parent_id"` | ||||
| 	Command   string `json:"command"` | ||||
| 	UserId    string               `json:"user_id"` | ||||
| 	ChannelId string               `json:"channel_id"` | ||||
| 	TeamId    string               `json:"team_id"` | ||||
| 	RootId    string               `json:"root_id"` | ||||
| 	ParentId  string               `json:"parent_id"` | ||||
| 	Command   string               `json:"command"` | ||||
| 	SiteURL   string               `json:"-"` | ||||
| 	T         goi18n.TranslateFunc `json:"-"` | ||||
| 	Session   Session              `json:"-"` | ||||
| } | ||||
|  | ||||
| func (o *CommandArgs) ToJson() string { | ||||
|   | ||||
							
								
								
									
										13
									
								
								vendor/github.com/mattermost/platform/model/command_response.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/mattermost/platform/model/command_response.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,11 +1,10 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| @@ -40,14 +39,8 @@ func CommandResponseFromJson(data io.Reader) *CommandResponse { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// Ensure attachment fields are stored as strings | ||||
| 	for _, attachment := range o.Attachments { | ||||
| 		for _, field := range attachment.Fields { | ||||
| 			if field.Value != nil { | ||||
| 				field.Value = fmt.Sprintf("%v", field.Value) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	o.Text = ExpandAnnouncement(o.Text) | ||||
| 	o.Attachments = ProcessSlackAttachments(o.Attachments) | ||||
|  | ||||
| 	return &o | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/compliance.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/compliance.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										28
									
								
								vendor/github.com/mattermost/platform/model/compliance_post.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/mattermost/platform/model/compliance_post.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,9 +1,10 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|  | ||||
| import ( | ||||
| 	"regexp" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| @@ -64,6 +65,15 @@ func CompliancePostHeader() []string { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func cleanComplianceStrings(in string) string { | ||||
| 	if matched, _ := regexp.MatchString("^\\s*(=|\\+|\\-)", in); matched { | ||||
| 		return "'" + in | ||||
|  | ||||
| 	} else { | ||||
| 		return in | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (me *CompliancePost) Row() []string { | ||||
|  | ||||
| 	postDeleteAt := "" | ||||
| @@ -77,15 +87,15 @@ func (me *CompliancePost) Row() []string { | ||||
| 	} | ||||
|  | ||||
| 	return []string{ | ||||
| 		me.TeamName, | ||||
| 		me.TeamDisplayName, | ||||
| 		cleanComplianceStrings(me.TeamName), | ||||
| 		cleanComplianceStrings(me.TeamDisplayName), | ||||
|  | ||||
| 		me.ChannelName, | ||||
| 		me.ChannelDisplayName, | ||||
| 		cleanComplianceStrings(me.ChannelName), | ||||
| 		cleanComplianceStrings(me.ChannelDisplayName), | ||||
|  | ||||
| 		me.UserUsername, | ||||
| 		me.UserEmail, | ||||
| 		me.UserNickname, | ||||
| 		cleanComplianceStrings(me.UserUsername), | ||||
| 		cleanComplianceStrings(me.UserEmail), | ||||
| 		cleanComplianceStrings(me.UserNickname), | ||||
|  | ||||
| 		me.PostId, | ||||
| 		time.Unix(0, me.PostCreateAt*int64(1000*1000)).Format(time.RFC3339), | ||||
| @@ -95,7 +105,7 @@ func (me *CompliancePost) Row() []string { | ||||
| 		me.PostRootId, | ||||
| 		me.PostParentId, | ||||
| 		me.PostOriginalId, | ||||
| 		me.PostMessage, | ||||
| 		cleanComplianceStrings(me.PostMessage), | ||||
| 		me.PostType, | ||||
| 		me.PostProps, | ||||
| 		me.PostHashtags, | ||||
|   | ||||
							
								
								
									
										624
									
								
								vendor/github.com/mattermost/platform/model/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										624
									
								
								vendor/github.com/mattermost/platform/model/config.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -6,6 +6,7 @@ package model | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| ) | ||||
|  | ||||
| @@ -32,12 +33,17 @@ const ( | ||||
| 	WEBSERVER_MODE_GZIP     = "gzip" | ||||
| 	WEBSERVER_MODE_DISABLED = "disabled" | ||||
|  | ||||
| 	GENERIC_NOTIFICATION = "generic" | ||||
| 	FULL_NOTIFICATION    = "full" | ||||
| 	GENERIC_NO_CHANNEL_NOTIFICATION = "generic_no_channel" | ||||
| 	GENERIC_NOTIFICATION            = "generic" | ||||
| 	FULL_NOTIFICATION               = "full" | ||||
|  | ||||
| 	DIRECT_MESSAGE_ANY  = "any" | ||||
| 	DIRECT_MESSAGE_TEAM = "team" | ||||
|  | ||||
| 	SHOW_USERNAME          = "username" | ||||
| 	SHOW_NICKNAME_FULLNAME = "nickname_full_name" | ||||
| 	SHOW_FULLNAME          = "full_name" | ||||
|  | ||||
| 	PERMISSIONS_ALL           = "all" | ||||
| 	PERMISSIONS_CHANNEL_ADMIN = "channel_admin" | ||||
| 	PERMISSIONS_TEAM_ADMIN    = "team_admin" | ||||
| @@ -60,6 +66,9 @@ const ( | ||||
| 	EMAIL_BATCHING_BUFFER_SIZE = 256 | ||||
| 	EMAIL_BATCHING_INTERVAL    = 30 | ||||
|  | ||||
| 	EMAIL_NOTIFICATION_CONTENTS_FULL    = "full" | ||||
| 	EMAIL_NOTIFICATION_CONTENTS_GENERIC = "generic" | ||||
|  | ||||
| 	SITENAME_MAX_LENGTH = 30 | ||||
|  | ||||
| 	SERVICE_SETTINGS_DEFAULT_SITE_URL        = "" | ||||
| @@ -75,12 +84,15 @@ const ( | ||||
|  | ||||
| 	EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION = "" | ||||
|  | ||||
| 	SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK = "https://about.mattermost.com/default-terms/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK   = "https://about.mattermost.com/default-privacy-policy/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK            = "https://about.mattermost.com/default-about/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_HELP_LINK             = "https://about.mattermost.com/default-help/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK = "https://about.mattermost.com/default-report-a-problem/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL         = "feedback@mattermost.com" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK      = "https://about.mattermost.com/default-terms/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK        = "https://about.mattermost.com/default-privacy-policy/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK                 = "https://about.mattermost.com/default-about/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_HELP_LINK                  = "https://about.mattermost.com/default-help/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK      = "https://about.mattermost.com/default-report-a-problem/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_ADMINISTRATORS_GUIDE_LINK  = "https://about.mattermost.com/administrators-guide/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_TROUBLESHOOTING_FORUM_LINK = "https://about.mattermost.com/troubleshooting-forum/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_COMMERCIAL_SUPPORT_LINK    = "https://about.mattermost.com/commercial-support/" | ||||
| 	SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL              = "feedback@mattermost.com" | ||||
|  | ||||
| 	LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = "" | ||||
| 	LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE  = "" | ||||
| @@ -107,10 +119,20 @@ const ( | ||||
| 	WEBRTC_SETTINGS_DEFAULT_TURN_URI = "" | ||||
|  | ||||
| 	ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS = 2500 | ||||
|  | ||||
| 	ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR      = "#f2a93b" | ||||
| 	ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR = "#333333" | ||||
|  | ||||
| 	ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL      = "" | ||||
| 	ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME            = "" | ||||
| 	ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD            = "" | ||||
| 	ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_REPLICAS = 1 | ||||
| 	ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_SHARDS   = 1 | ||||
| ) | ||||
|  | ||||
| type ServiceSettings struct { | ||||
| 	SiteURL                                  *string | ||||
| 	LicenseFileLocation                      *string | ||||
| 	ListenAddress                            string | ||||
| 	ConnectionSecurity                       *string | ||||
| 	TLSCertFile                              *string | ||||
| @@ -121,6 +143,7 @@ type ServiceSettings struct { | ||||
| 	ReadTimeout                              *int | ||||
| 	WriteTimeout                             *int | ||||
| 	MaximumLoginAttempts                     int | ||||
| 	GoroutineHealthThreshold                 *int | ||||
| 	GoogleDeveloperKey                       string | ||||
| 	EnableOAuthServiceProvider               bool | ||||
| 	EnableIncomingWebhooks                   bool | ||||
| @@ -129,6 +152,7 @@ type ServiceSettings struct { | ||||
| 	EnableOnlyAdminIntegrations              *bool | ||||
| 	EnablePostUsernameOverride               bool | ||||
| 	EnablePostIconOverride                   bool | ||||
| 	EnableAPIv3                              *bool | ||||
| 	EnableLinkPreviews                       *bool | ||||
| 	EnableTesting                            bool | ||||
| 	EnableDeveloper                          *bool | ||||
| @@ -136,6 +160,7 @@ type ServiceSettings struct { | ||||
| 	EnableInsecureOutgoingConnections        *bool | ||||
| 	EnableMultifactorAuthentication          *bool | ||||
| 	EnforceMultifactorAuthentication         *bool | ||||
| 	EnableUserAccessTokens                   *bool | ||||
| 	AllowCorsFrom                            *string | ||||
| 	SessionLengthWebInDays                   *int | ||||
| 	SessionLengthMobileInDays                *int | ||||
| @@ -145,19 +170,28 @@ type ServiceSettings struct { | ||||
| 	WebsocketPort                            *int | ||||
| 	WebserverMode                            *string | ||||
| 	EnableCustomEmoji                        *bool | ||||
| 	EnableEmojiPicker                        *bool | ||||
| 	RestrictCustomEmojiCreation              *string | ||||
| 	RestrictPostDelete                       *string | ||||
| 	AllowEditPost                            *string | ||||
| 	PostEditTimeLimit                        *int | ||||
| 	TimeBetweenUserTypingUpdatesMilliseconds *int64 | ||||
| 	EnablePostSearch                         *bool | ||||
| 	EnableUserTypingMessages                 *bool | ||||
| 	EnableChannelViewedMessages              *bool | ||||
| 	EnableUserStatuses                       *bool | ||||
| 	ClusterLogTimeoutMilliseconds            *int | ||||
| } | ||||
|  | ||||
| type ClusterSettings struct { | ||||
| 	Enable                 *bool | ||||
| 	InterNodeListenAddress *string | ||||
| 	InterNodeUrls          []string | ||||
| 	Enable                *bool | ||||
| 	ClusterName           *string | ||||
| 	OverrideHostname      *string | ||||
| 	UseIpAddress          *bool | ||||
| 	UseExperimentalGossip *bool | ||||
| 	ReadOnlyConfig        *bool | ||||
| 	GossipPort            *int | ||||
| 	StreamingPort         *int | ||||
| } | ||||
|  | ||||
| type MetricsSettings struct { | ||||
| @@ -181,13 +215,15 @@ type SSOSettings struct { | ||||
| } | ||||
|  | ||||
| type SqlSettings struct { | ||||
| 	DriverName         string | ||||
| 	DataSource         string | ||||
| 	DataSourceReplicas []string | ||||
| 	MaxIdleConns       int | ||||
| 	MaxOpenConns       int | ||||
| 	Trace              bool | ||||
| 	AtRestEncryptKey   string | ||||
| 	DriverName               string | ||||
| 	DataSource               string | ||||
| 	DataSourceReplicas       []string | ||||
| 	DataSourceSearchReplicas []string | ||||
| 	MaxIdleConns             int | ||||
| 	MaxOpenConns             int | ||||
| 	Trace                    bool | ||||
| 	AtRestEncryptKey         string | ||||
| 	QueryTimeout             *int | ||||
| } | ||||
|  | ||||
| type LogSettings struct { | ||||
| @@ -210,17 +246,14 @@ type PasswordSettings struct { | ||||
| } | ||||
|  | ||||
| type FileSettings struct { | ||||
| 	EnableFileAttachments   *bool | ||||
| 	EnableMobileUpload      *bool | ||||
| 	EnableMobileDownload    *bool | ||||
| 	MaxFileSize             *int64 | ||||
| 	DriverName              string | ||||
| 	Directory               string | ||||
| 	EnablePublicLink        bool | ||||
| 	PublicLinkSalt          *string | ||||
| 	ThumbnailWidth          int | ||||
| 	ThumbnailHeight         int | ||||
| 	PreviewWidth            int | ||||
| 	PreviewHeight           int | ||||
| 	ProfileWidth            int | ||||
| 	ProfileHeight           int | ||||
| 	InitialFont             string | ||||
| 	AmazonS3AccessKeyId     string | ||||
| 	AmazonS3SecretAccessKey string | ||||
| @@ -228,30 +261,34 @@ type FileSettings struct { | ||||
| 	AmazonS3Region          string | ||||
| 	AmazonS3Endpoint        string | ||||
| 	AmazonS3SSL             *bool | ||||
| 	AmazonS3SignV2          *bool | ||||
| 	AmazonS3SSE             *bool | ||||
| } | ||||
|  | ||||
| type EmailSettings struct { | ||||
| 	EnableSignUpWithEmail    bool | ||||
| 	EnableSignInWithEmail    *bool | ||||
| 	EnableSignInWithUsername *bool | ||||
| 	SendEmailNotifications   bool | ||||
| 	RequireEmailVerification bool | ||||
| 	FeedbackName             string | ||||
| 	FeedbackEmail            string | ||||
| 	FeedbackOrganization     *string | ||||
| 	SMTPUsername             string | ||||
| 	SMTPPassword             string | ||||
| 	SMTPServer               string | ||||
| 	SMTPPort                 string | ||||
| 	ConnectionSecurity       string | ||||
| 	InviteSalt               string | ||||
| 	PasswordResetSalt        string | ||||
| 	SendPushNotifications    *bool | ||||
| 	PushNotificationServer   *string | ||||
| 	PushNotificationContents *string | ||||
| 	EnableEmailBatching      *bool | ||||
| 	EmailBatchingBufferSize  *int | ||||
| 	EmailBatchingInterval    *int | ||||
| 	EnableSignUpWithEmail             bool | ||||
| 	EnableSignInWithEmail             *bool | ||||
| 	EnableSignInWithUsername          *bool | ||||
| 	SendEmailNotifications            bool | ||||
| 	RequireEmailVerification          bool | ||||
| 	FeedbackName                      string | ||||
| 	FeedbackEmail                     string | ||||
| 	FeedbackOrganization              *string | ||||
| 	EnableSMTPAuth                    *bool | ||||
| 	SMTPUsername                      string | ||||
| 	SMTPPassword                      string | ||||
| 	SMTPServer                        string | ||||
| 	SMTPPort                          string | ||||
| 	ConnectionSecurity                string | ||||
| 	InviteSalt                        string | ||||
| 	SendPushNotifications             *bool | ||||
| 	PushNotificationServer            *string | ||||
| 	PushNotificationContents          *string | ||||
| 	EnableEmailBatching               *bool | ||||
| 	EmailBatchingBufferSize           *int | ||||
| 	EmailBatchingInterval             *int | ||||
| 	SkipServerCertificateVerification *bool | ||||
| 	EmailNotificationContentsType     *string | ||||
| } | ||||
|  | ||||
| type RateLimitSettings struct { | ||||
| @@ -269,35 +306,48 @@ type PrivacySettings struct { | ||||
| } | ||||
|  | ||||
| type SupportSettings struct { | ||||
| 	TermsOfServiceLink *string | ||||
| 	PrivacyPolicyLink  *string | ||||
| 	AboutLink          *string | ||||
| 	HelpLink           *string | ||||
| 	ReportAProblemLink *string | ||||
| 	SupportEmail       *string | ||||
| 	TermsOfServiceLink       *string | ||||
| 	PrivacyPolicyLink        *string | ||||
| 	AboutLink                *string | ||||
| 	HelpLink                 *string | ||||
| 	ReportAProblemLink       *string | ||||
| 	AdministratorsGuideLink  *string | ||||
| 	TroubleshootingForumLink *string | ||||
| 	CommercialSupportLink    *string | ||||
| 	SupportEmail             *string | ||||
| } | ||||
|  | ||||
| type AnnouncementSettings struct { | ||||
| 	EnableBanner         *bool | ||||
| 	BannerText           *string | ||||
| 	BannerColor          *string | ||||
| 	BannerTextColor      *string | ||||
| 	AllowBannerDismissal *bool | ||||
| } | ||||
|  | ||||
| type TeamSettings struct { | ||||
| 	SiteName                         string | ||||
| 	MaxUsersPerTeam                  int | ||||
| 	EnableTeamCreation               bool | ||||
| 	EnableUserCreation               bool | ||||
| 	EnableOpenServer                 *bool | ||||
| 	RestrictCreationToDomains        string | ||||
| 	EnableCustomBrand                *bool | ||||
| 	CustomBrandText                  *string | ||||
| 	CustomDescriptionText            *string | ||||
| 	RestrictDirectMessage            *string | ||||
| 	RestrictTeamInvite               *string | ||||
| 	RestrictPublicChannelManagement  *string | ||||
| 	RestrictPrivateChannelManagement *string | ||||
| 	RestrictPublicChannelCreation    *string | ||||
| 	RestrictPrivateChannelCreation   *string | ||||
| 	RestrictPublicChannelDeletion    *string | ||||
| 	RestrictPrivateChannelDeletion   *string | ||||
| 	UserStatusAwayTimeout            *int64 | ||||
| 	MaxChannelsPerTeam               *int64 | ||||
| 	MaxNotificationsPerChannel       *int64 | ||||
| 	SiteName                            string | ||||
| 	MaxUsersPerTeam                     int | ||||
| 	EnableTeamCreation                  bool | ||||
| 	EnableUserCreation                  bool | ||||
| 	EnableOpenServer                    *bool | ||||
| 	RestrictCreationToDomains           string | ||||
| 	EnableCustomBrand                   *bool | ||||
| 	CustomBrandText                     *string | ||||
| 	CustomDescriptionText               *string | ||||
| 	RestrictDirectMessage               *string | ||||
| 	RestrictTeamInvite                  *string | ||||
| 	RestrictPublicChannelManagement     *string | ||||
| 	RestrictPrivateChannelManagement    *string | ||||
| 	RestrictPublicChannelCreation       *string | ||||
| 	RestrictPrivateChannelCreation      *string | ||||
| 	RestrictPublicChannelDeletion       *string | ||||
| 	RestrictPrivateChannelDeletion      *string | ||||
| 	RestrictPrivateChannelManageMembers *string | ||||
| 	UserStatusAwayTimeout               *int64 | ||||
| 	MaxChannelsPerTeam                  *int64 | ||||
| 	MaxNotificationsPerChannel          *int64 | ||||
| 	TeammateNameDisplay                 *string | ||||
| } | ||||
|  | ||||
| type LdapSettings struct { | ||||
| @@ -389,29 +439,58 @@ type WebrtcSettings struct { | ||||
| 	TurnSharedKey       *string | ||||
| } | ||||
|  | ||||
| type ElasticsearchSettings struct { | ||||
| 	ConnectionUrl     *string | ||||
| 	Username          *string | ||||
| 	Password          *string | ||||
| 	EnableIndexing    *bool | ||||
| 	EnableSearching   *bool | ||||
| 	Sniff             *bool | ||||
| 	PostIndexReplicas *int | ||||
| 	PostIndexShards   *int | ||||
| } | ||||
|  | ||||
| type DataRetentionSettings struct { | ||||
| 	Enable *bool | ||||
| } | ||||
|  | ||||
| type JobSettings struct { | ||||
| 	RunJobs      *bool | ||||
| 	RunScheduler *bool | ||||
| } | ||||
|  | ||||
| type PluginSettings struct { | ||||
| 	Plugins map[string]interface{} | ||||
| } | ||||
|  | ||||
| type Config struct { | ||||
| 	ServiceSettings      ServiceSettings | ||||
| 	TeamSettings         TeamSettings | ||||
| 	SqlSettings          SqlSettings | ||||
| 	LogSettings          LogSettings | ||||
| 	PasswordSettings     PasswordSettings | ||||
| 	FileSettings         FileSettings | ||||
| 	EmailSettings        EmailSettings | ||||
| 	RateLimitSettings    RateLimitSettings | ||||
| 	PrivacySettings      PrivacySettings | ||||
| 	SupportSettings      SupportSettings | ||||
| 	GitLabSettings       SSOSettings | ||||
| 	GoogleSettings       SSOSettings | ||||
| 	Office365Settings    SSOSettings | ||||
| 	LdapSettings         LdapSettings | ||||
| 	ComplianceSettings   ComplianceSettings | ||||
| 	LocalizationSettings LocalizationSettings | ||||
| 	SamlSettings         SamlSettings | ||||
| 	NativeAppSettings    NativeAppSettings | ||||
| 	ClusterSettings      ClusterSettings | ||||
| 	MetricsSettings      MetricsSettings | ||||
| 	AnalyticsSettings    AnalyticsSettings | ||||
| 	WebrtcSettings       WebrtcSettings | ||||
| 	ServiceSettings       ServiceSettings | ||||
| 	TeamSettings          TeamSettings | ||||
| 	SqlSettings           SqlSettings | ||||
| 	LogSettings           LogSettings | ||||
| 	PasswordSettings      PasswordSettings | ||||
| 	FileSettings          FileSettings | ||||
| 	EmailSettings         EmailSettings | ||||
| 	RateLimitSettings     RateLimitSettings | ||||
| 	PrivacySettings       PrivacySettings | ||||
| 	SupportSettings       SupportSettings | ||||
| 	AnnouncementSettings  AnnouncementSettings | ||||
| 	GitLabSettings        SSOSettings | ||||
| 	GoogleSettings        SSOSettings | ||||
| 	Office365Settings     SSOSettings | ||||
| 	LdapSettings          LdapSettings | ||||
| 	ComplianceSettings    ComplianceSettings | ||||
| 	LocalizationSettings  LocalizationSettings | ||||
| 	SamlSettings          SamlSettings | ||||
| 	NativeAppSettings     NativeAppSettings | ||||
| 	ClusterSettings       ClusterSettings | ||||
| 	MetricsSettings       MetricsSettings | ||||
| 	AnalyticsSettings     AnalyticsSettings | ||||
| 	WebrtcSettings        WebrtcSettings | ||||
| 	ElasticsearchSettings ElasticsearchSettings | ||||
| 	DataRetentionSettings DataRetentionSettings | ||||
| 	JobSettings           JobSettings | ||||
| 	PluginSettings        PluginSettings | ||||
| } | ||||
|  | ||||
| func (o *Config) ToJson() string { | ||||
| @@ -453,27 +532,52 @@ func (o *Config) SetDefaults() { | ||||
| 		o.SqlSettings.AtRestEncryptKey = NewRandomString(32) | ||||
| 	} | ||||
|  | ||||
| 	if o.SqlSettings.QueryTimeout == nil { | ||||
| 		o.SqlSettings.QueryTimeout = new(int) | ||||
| 		*o.SqlSettings.QueryTimeout = 30 | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.AmazonS3Endpoint == "" { | ||||
| 		// Defaults to "s3.amazonaws.com" | ||||
| 		o.FileSettings.AmazonS3Endpoint = "s3.amazonaws.com" | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.AmazonS3Region == "" { | ||||
| 		// Defaults to "us-east-1" region. | ||||
| 		o.FileSettings.AmazonS3Region = "us-east-1" | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.AmazonS3SSL == nil { | ||||
| 		o.FileSettings.AmazonS3SSL = new(bool) | ||||
| 		*o.FileSettings.AmazonS3SSL = true // Secure by default. | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.AmazonS3SignV2 == nil { | ||||
| 		o.FileSettings.AmazonS3SignV2 = new(bool) | ||||
| 		// Signature v2 is not enabled by default. | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.AmazonS3SSE == nil { | ||||
| 		o.FileSettings.AmazonS3SSE = new(bool) | ||||
| 		*o.FileSettings.AmazonS3SSE = false // Not Encrypted by default. | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.EnableFileAttachments == nil { | ||||
| 		o.FileSettings.EnableFileAttachments = new(bool) | ||||
| 		*o.FileSettings.EnableFileAttachments = true | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.EnableMobileUpload == nil { | ||||
| 		o.FileSettings.EnableMobileUpload = new(bool) | ||||
| 		*o.FileSettings.EnableMobileUpload = true | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.EnableMobileDownload == nil { | ||||
| 		o.FileSettings.EnableMobileDownload = new(bool) | ||||
| 		*o.FileSettings.EnableMobileDownload = true | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.MaxFileSize == nil { | ||||
| 		o.FileSettings.MaxFileSize = new(int64) | ||||
| 		*o.FileSettings.MaxFileSize = 52428800 // 50 MB | ||||
| 	} | ||||
|  | ||||
| 	if len(*o.FileSettings.PublicLinkSalt) == 0 { | ||||
| 	if o.FileSettings.PublicLinkSalt == nil || len(*o.FileSettings.PublicLinkSalt) == 0 { | ||||
| 		o.FileSettings.PublicLinkSalt = new(string) | ||||
| 		*o.FileSettings.PublicLinkSalt = NewRandomString(32) | ||||
| 	} | ||||
| @@ -483,12 +587,12 @@ func (o *Config) SetDefaults() { | ||||
| 		o.FileSettings.InitialFont = "luximbi.ttf" | ||||
| 	} | ||||
|  | ||||
| 	if len(o.EmailSettings.InviteSalt) == 0 { | ||||
| 		o.EmailSettings.InviteSalt = NewRandomString(32) | ||||
| 	if o.FileSettings.Directory == "" { | ||||
| 		o.FileSettings.Directory = "./data/" | ||||
| 	} | ||||
|  | ||||
| 	if len(o.EmailSettings.PasswordResetSalt) == 0 { | ||||
| 		o.EmailSettings.PasswordResetSalt = NewRandomString(32) | ||||
| 	if len(o.EmailSettings.InviteSalt) == 0 { | ||||
| 		o.EmailSettings.InviteSalt = NewRandomString(32) | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.SiteURL == nil { | ||||
| @@ -496,6 +600,15 @@ func (o *Config) SetDefaults() { | ||||
| 		*o.ServiceSettings.SiteURL = SERVICE_SETTINGS_DEFAULT_SITE_URL | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.LicenseFileLocation == nil { | ||||
| 		o.ServiceSettings.LicenseFileLocation = new(string) | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.EnableAPIv3 == nil { | ||||
| 		o.ServiceSettings.EnableAPIv3 = new(bool) | ||||
| 		*o.ServiceSettings.EnableAPIv3 = true | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.EnableLinkPreviews == nil { | ||||
| 		o.ServiceSettings.EnableLinkPreviews = new(bool) | ||||
| 		*o.ServiceSettings.EnableLinkPreviews = false | ||||
| @@ -526,6 +639,11 @@ func (o *Config) SetDefaults() { | ||||
| 		*o.ServiceSettings.EnforceMultifactorAuthentication = false | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.EnableUserAccessTokens == nil { | ||||
| 		o.ServiceSettings.EnableUserAccessTokens = new(bool) | ||||
| 		*o.ServiceSettings.EnableUserAccessTokens = false | ||||
| 	} | ||||
|  | ||||
| 	if o.PasswordSettings.MinimumLength == nil { | ||||
| 		o.PasswordSettings.MinimumLength = new(int) | ||||
| 		*o.PasswordSettings.MinimumLength = PASSWORD_MINIMUM_LENGTH | ||||
| @@ -594,13 +712,21 @@ func (o *Config) SetDefaults() { | ||||
| 	if o.TeamSettings.RestrictPublicChannelCreation == nil { | ||||
| 		o.TeamSettings.RestrictPublicChannelCreation = new(string) | ||||
| 		// If this setting does not exist, assume migration from <3.6, so use management setting as default. | ||||
| 		*o.TeamSettings.RestrictPublicChannelCreation = *o.TeamSettings.RestrictPublicChannelManagement | ||||
| 		if *o.TeamSettings.RestrictPublicChannelManagement == PERMISSIONS_CHANNEL_ADMIN { | ||||
| 			*o.TeamSettings.RestrictPublicChannelCreation = PERMISSIONS_TEAM_ADMIN | ||||
| 		} else { | ||||
| 			*o.TeamSettings.RestrictPublicChannelCreation = *o.TeamSettings.RestrictPublicChannelManagement | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if o.TeamSettings.RestrictPrivateChannelCreation == nil { | ||||
| 		o.TeamSettings.RestrictPrivateChannelCreation = new(string) | ||||
| 		// If this setting does not exist, assume migration from <3.6, so use management setting as default. | ||||
| 		*o.TeamSettings.RestrictPrivateChannelCreation = *o.TeamSettings.RestrictPrivateChannelManagement | ||||
| 		if *o.TeamSettings.RestrictPrivateChannelManagement == PERMISSIONS_CHANNEL_ADMIN { | ||||
| 			*o.TeamSettings.RestrictPrivateChannelCreation = PERMISSIONS_TEAM_ADMIN | ||||
| 		} else { | ||||
| 			*o.TeamSettings.RestrictPrivateChannelCreation = *o.TeamSettings.RestrictPrivateChannelManagement | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if o.TeamSettings.RestrictPublicChannelDeletion == nil { | ||||
| @@ -615,6 +741,11 @@ func (o *Config) SetDefaults() { | ||||
| 		*o.TeamSettings.RestrictPrivateChannelDeletion = *o.TeamSettings.RestrictPrivateChannelManagement | ||||
| 	} | ||||
|  | ||||
| 	if o.TeamSettings.RestrictPrivateChannelManageMembers == nil { | ||||
| 		o.TeamSettings.RestrictPrivateChannelManageMembers = new(string) | ||||
| 		*o.TeamSettings.RestrictPrivateChannelManageMembers = PERMISSIONS_ALL | ||||
| 	} | ||||
|  | ||||
| 	if o.TeamSettings.UserStatusAwayTimeout == nil { | ||||
| 		o.TeamSettings.UserStatusAwayTimeout = new(int64) | ||||
| 		*o.TeamSettings.UserStatusAwayTimeout = TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT | ||||
| @@ -680,8 +811,31 @@ func (o *Config) SetDefaults() { | ||||
| 		*o.EmailSettings.EmailBatchingInterval = EMAIL_BATCHING_INTERVAL | ||||
| 	} | ||||
|  | ||||
| 	if o.EmailSettings.EnableSMTPAuth == nil { | ||||
| 		o.EmailSettings.EnableSMTPAuth = new(bool) | ||||
| 		if o.EmailSettings.ConnectionSecurity == CONN_SECURITY_NONE { | ||||
| 			*o.EmailSettings.EnableSMTPAuth = false | ||||
| 		} else { | ||||
| 			*o.EmailSettings.EnableSMTPAuth = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if o.EmailSettings.ConnectionSecurity == CONN_SECURITY_PLAIN { | ||||
| 		o.EmailSettings.ConnectionSecurity = CONN_SECURITY_NONE | ||||
| 	} | ||||
|  | ||||
| 	if o.EmailSettings.SkipServerCertificateVerification == nil { | ||||
| 		o.EmailSettings.SkipServerCertificateVerification = new(bool) | ||||
| 		*o.EmailSettings.SkipServerCertificateVerification = false | ||||
| 	} | ||||
|  | ||||
| 	if o.EmailSettings.EmailNotificationContentsType == nil { | ||||
| 		o.EmailSettings.EmailNotificationContentsType = new(string) | ||||
| 		*o.EmailSettings.EmailNotificationContentsType = EMAIL_NOTIFICATION_CONTENTS_FULL | ||||
| 	} | ||||
|  | ||||
| 	if !IsSafeLink(o.SupportSettings.TermsOfServiceLink) { | ||||
| 		o.SupportSettings.TermsOfServiceLink = nil | ||||
| 		*o.SupportSettings.TermsOfServiceLink = SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK | ||||
| 	} | ||||
|  | ||||
| 	if o.SupportSettings.TermsOfServiceLink == nil { | ||||
| @@ -690,7 +844,7 @@ func (o *Config) SetDefaults() { | ||||
| 	} | ||||
|  | ||||
| 	if !IsSafeLink(o.SupportSettings.PrivacyPolicyLink) { | ||||
| 		o.SupportSettings.PrivacyPolicyLink = nil | ||||
| 		*o.SupportSettings.PrivacyPolicyLink = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.SupportSettings.PrivacyPolicyLink == nil { | ||||
| @@ -699,7 +853,7 @@ func (o *Config) SetDefaults() { | ||||
| 	} | ||||
|  | ||||
| 	if !IsSafeLink(o.SupportSettings.AboutLink) { | ||||
| 		o.SupportSettings.AboutLink = nil | ||||
| 		*o.SupportSettings.AboutLink = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.SupportSettings.AboutLink == nil { | ||||
| @@ -708,7 +862,7 @@ func (o *Config) SetDefaults() { | ||||
| 	} | ||||
|  | ||||
| 	if !IsSafeLink(o.SupportSettings.HelpLink) { | ||||
| 		o.SupportSettings.HelpLink = nil | ||||
| 		*o.SupportSettings.HelpLink = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.SupportSettings.HelpLink == nil { | ||||
| @@ -717,7 +871,7 @@ func (o *Config) SetDefaults() { | ||||
| 	} | ||||
|  | ||||
| 	if !IsSafeLink(o.SupportSettings.ReportAProblemLink) { | ||||
| 		o.SupportSettings.ReportAProblemLink = nil | ||||
| 		*o.SupportSettings.ReportAProblemLink = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.SupportSettings.ReportAProblemLink == nil { | ||||
| @@ -725,11 +879,63 @@ func (o *Config) SetDefaults() { | ||||
| 		*o.SupportSettings.ReportAProblemLink = SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK | ||||
| 	} | ||||
|  | ||||
| 	if !IsSafeLink(o.SupportSettings.AdministratorsGuideLink) { | ||||
| 		*o.SupportSettings.AdministratorsGuideLink = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.SupportSettings.AdministratorsGuideLink == nil { | ||||
| 		o.SupportSettings.AdministratorsGuideLink = new(string) | ||||
| 		*o.SupportSettings.AdministratorsGuideLink = SUPPORT_SETTINGS_DEFAULT_ADMINISTRATORS_GUIDE_LINK | ||||
| 	} | ||||
|  | ||||
| 	if !IsSafeLink(o.SupportSettings.TroubleshootingForumLink) { | ||||
| 		*o.SupportSettings.TroubleshootingForumLink = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.SupportSettings.TroubleshootingForumLink == nil { | ||||
| 		o.SupportSettings.TroubleshootingForumLink = new(string) | ||||
| 		*o.SupportSettings.TroubleshootingForumLink = SUPPORT_SETTINGS_DEFAULT_TROUBLESHOOTING_FORUM_LINK | ||||
| 	} | ||||
|  | ||||
| 	if !IsSafeLink(o.SupportSettings.CommercialSupportLink) { | ||||
| 		*o.SupportSettings.CommercialSupportLink = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.SupportSettings.CommercialSupportLink == nil { | ||||
| 		o.SupportSettings.CommercialSupportLink = new(string) | ||||
| 		*o.SupportSettings.CommercialSupportLink = SUPPORT_SETTINGS_DEFAULT_COMMERCIAL_SUPPORT_LINK | ||||
| 	} | ||||
|  | ||||
| 	if o.SupportSettings.SupportEmail == nil { | ||||
| 		o.SupportSettings.SupportEmail = new(string) | ||||
| 		*o.SupportSettings.SupportEmail = SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL | ||||
| 	} | ||||
|  | ||||
| 	if o.AnnouncementSettings.EnableBanner == nil { | ||||
| 		o.AnnouncementSettings.EnableBanner = new(bool) | ||||
| 		*o.AnnouncementSettings.EnableBanner = false | ||||
| 	} | ||||
|  | ||||
| 	if o.AnnouncementSettings.BannerText == nil { | ||||
| 		o.AnnouncementSettings.BannerText = new(string) | ||||
| 		*o.AnnouncementSettings.BannerText = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.AnnouncementSettings.BannerColor == nil { | ||||
| 		o.AnnouncementSettings.BannerColor = new(string) | ||||
| 		*o.AnnouncementSettings.BannerColor = ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR | ||||
| 	} | ||||
|  | ||||
| 	if o.AnnouncementSettings.BannerTextColor == nil { | ||||
| 		o.AnnouncementSettings.BannerTextColor = new(string) | ||||
| 		*o.AnnouncementSettings.BannerTextColor = ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR | ||||
| 	} | ||||
|  | ||||
| 	if o.AnnouncementSettings.AllowBannerDismissal == nil { | ||||
| 		o.AnnouncementSettings.AllowBannerDismissal = new(bool) | ||||
| 		*o.AnnouncementSettings.AllowBannerDismissal = true | ||||
| 	} | ||||
|  | ||||
| 	if o.LdapSettings.Enable == nil { | ||||
| 		o.LdapSettings.Enable = new(bool) | ||||
| 		*o.LdapSettings.Enable = false | ||||
| @@ -884,7 +1090,12 @@ func (o *Config) SetDefaults() { | ||||
|  | ||||
| 	if o.ServiceSettings.EnableCustomEmoji == nil { | ||||
| 		o.ServiceSettings.EnableCustomEmoji = new(bool) | ||||
| 		*o.ServiceSettings.EnableCustomEmoji = true | ||||
| 		*o.ServiceSettings.EnableCustomEmoji = false | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.EnableEmojiPicker == nil { | ||||
| 		o.ServiceSettings.EnableEmojiPicker = new(bool) | ||||
| 		*o.ServiceSettings.EnableEmojiPicker = true | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.RestrictCustomEmojiCreation == nil { | ||||
| @@ -907,18 +1118,44 @@ func (o *Config) SetDefaults() { | ||||
| 		*o.ServiceSettings.PostEditTimeLimit = 300 | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterSettings.InterNodeListenAddress == nil { | ||||
| 		o.ClusterSettings.InterNodeListenAddress = new(string) | ||||
| 		*o.ClusterSettings.InterNodeListenAddress = ":8075" | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterSettings.Enable == nil { | ||||
| 		o.ClusterSettings.Enable = new(bool) | ||||
| 		*o.ClusterSettings.Enable = false | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterSettings.InterNodeUrls == nil { | ||||
| 		o.ClusterSettings.InterNodeUrls = []string{} | ||||
| 	if o.ClusterSettings.ClusterName == nil { | ||||
| 		o.ClusterSettings.ClusterName = new(string) | ||||
| 		*o.ClusterSettings.ClusterName = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterSettings.OverrideHostname == nil { | ||||
| 		o.ClusterSettings.OverrideHostname = new(string) | ||||
| 		*o.ClusterSettings.OverrideHostname = "" | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterSettings.UseIpAddress == nil { | ||||
| 		o.ClusterSettings.UseIpAddress = new(bool) | ||||
| 		*o.ClusterSettings.UseIpAddress = true | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterSettings.UseExperimentalGossip == nil { | ||||
| 		o.ClusterSettings.UseExperimentalGossip = new(bool) | ||||
| 		*o.ClusterSettings.UseExperimentalGossip = false | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterSettings.ReadOnlyConfig == nil { | ||||
| 		o.ClusterSettings.ReadOnlyConfig = new(bool) | ||||
| 		*o.ClusterSettings.ReadOnlyConfig = true | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterSettings.GossipPort == nil { | ||||
| 		o.ClusterSettings.GossipPort = new(int) | ||||
| 		*o.ClusterSettings.GossipPort = 8074 | ||||
| 	} | ||||
|  | ||||
| 	if o.ClusterSettings.StreamingPort == nil { | ||||
| 		o.ClusterSettings.StreamingPort = new(int) | ||||
| 		*o.ClusterSettings.StreamingPort = 8075 | ||||
| 	} | ||||
|  | ||||
| 	if o.MetricsSettings.ListenAddress == nil { | ||||
| @@ -978,12 +1215,12 @@ func (o *Config) SetDefaults() { | ||||
|  | ||||
| 	if o.SamlSettings.Verify == nil { | ||||
| 		o.SamlSettings.Verify = new(bool) | ||||
| 		*o.SamlSettings.Verify = false | ||||
| 		*o.SamlSettings.Verify = true | ||||
| 	} | ||||
|  | ||||
| 	if o.SamlSettings.Encrypt == nil { | ||||
| 		o.SamlSettings.Encrypt = new(bool) | ||||
| 		*o.SamlSettings.Encrypt = false | ||||
| 		*o.SamlSettings.Encrypt = true | ||||
| 	} | ||||
|  | ||||
| 	if o.SamlSettings.IdpUrl == nil { | ||||
| @@ -1056,6 +1293,15 @@ func (o *Config) SetDefaults() { | ||||
| 		*o.SamlSettings.LocaleAttribute = SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE | ||||
| 	} | ||||
|  | ||||
| 	if o.TeamSettings.TeammateNameDisplay == nil { | ||||
| 		o.TeamSettings.TeammateNameDisplay = new(string) | ||||
| 		*o.TeamSettings.TeammateNameDisplay = SHOW_USERNAME | ||||
|  | ||||
| 		if *o.SamlSettings.Enable || *o.LdapSettings.Enable { | ||||
| 			*o.TeamSettings.TeammateNameDisplay = SHOW_FULLNAME | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if o.NativeAppSettings.AppDownloadLink == nil { | ||||
| 		o.NativeAppSettings.AppDownloadLink = new(string) | ||||
| 		*o.NativeAppSettings.AppDownloadLink = NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK | ||||
| @@ -1076,6 +1322,11 @@ func (o *Config) SetDefaults() { | ||||
| 		*o.RateLimitSettings.Enable = false | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.GoroutineHealthThreshold == nil { | ||||
| 		o.ServiceSettings.GoroutineHealthThreshold = new(int) | ||||
| 		*o.ServiceSettings.GoroutineHealthThreshold = -1 | ||||
| 	} | ||||
|  | ||||
| 	if o.RateLimitSettings.MaxBurst == nil { | ||||
| 		o.RateLimitSettings.MaxBurst = new(int) | ||||
| 		*o.RateLimitSettings.MaxBurst = 100 | ||||
| @@ -1131,16 +1382,90 @@ func (o *Config) SetDefaults() { | ||||
| 		*o.ServiceSettings.TimeBetweenUserTypingUpdatesMilliseconds = 5000 | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.EnablePostSearch == nil { | ||||
| 		o.ServiceSettings.EnablePostSearch = new(bool) | ||||
| 		*o.ServiceSettings.EnablePostSearch = true | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.EnableUserTypingMessages == nil { | ||||
| 		o.ServiceSettings.EnableUserTypingMessages = new(bool) | ||||
| 		*o.ServiceSettings.EnableUserTypingMessages = true | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.EnableChannelViewedMessages == nil { | ||||
| 		o.ServiceSettings.EnableChannelViewedMessages = new(bool) | ||||
| 		*o.ServiceSettings.EnableChannelViewedMessages = true | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.EnableUserStatuses == nil { | ||||
| 		o.ServiceSettings.EnableUserStatuses = new(bool) | ||||
| 		*o.ServiceSettings.EnableUserStatuses = true | ||||
| 	} | ||||
|  | ||||
| 	if o.ServiceSettings.ClusterLogTimeoutMilliseconds == nil { | ||||
| 		o.ServiceSettings.ClusterLogTimeoutMilliseconds = new(int) | ||||
| 		*o.ServiceSettings.ClusterLogTimeoutMilliseconds = 2000 | ||||
| 	} | ||||
|  | ||||
| 	if o.ElasticsearchSettings.ConnectionUrl == nil { | ||||
| 		o.ElasticsearchSettings.ConnectionUrl = new(string) | ||||
| 		*o.ElasticsearchSettings.ConnectionUrl = ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL | ||||
| 	} | ||||
|  | ||||
| 	if o.ElasticsearchSettings.Username == nil { | ||||
| 		o.ElasticsearchSettings.Username = new(string) | ||||
| 		*o.ElasticsearchSettings.Username = ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME | ||||
| 	} | ||||
|  | ||||
| 	if o.ElasticsearchSettings.Password == nil { | ||||
| 		o.ElasticsearchSettings.Password = new(string) | ||||
| 		*o.ElasticsearchSettings.Password = ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD | ||||
| 	} | ||||
|  | ||||
| 	if o.ElasticsearchSettings.EnableIndexing == nil { | ||||
| 		o.ElasticsearchSettings.EnableIndexing = new(bool) | ||||
| 		*o.ElasticsearchSettings.EnableIndexing = false | ||||
| 	} | ||||
|  | ||||
| 	if o.ElasticsearchSettings.EnableSearching == nil { | ||||
| 		o.ElasticsearchSettings.EnableSearching = new(bool) | ||||
| 		*o.ElasticsearchSettings.EnableSearching = false | ||||
| 	} | ||||
|  | ||||
| 	if o.ElasticsearchSettings.Sniff == nil { | ||||
| 		o.ElasticsearchSettings.Sniff = new(bool) | ||||
| 		*o.ElasticsearchSettings.Sniff = true | ||||
| 	} | ||||
|  | ||||
| 	if o.ElasticsearchSettings.PostIndexReplicas == nil { | ||||
| 		o.ElasticsearchSettings.PostIndexReplicas = new(int) | ||||
| 		*o.ElasticsearchSettings.PostIndexReplicas = ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_REPLICAS | ||||
| 	} | ||||
|  | ||||
| 	if o.ElasticsearchSettings.PostIndexShards == nil { | ||||
| 		o.ElasticsearchSettings.PostIndexShards = new(int) | ||||
| 		*o.ElasticsearchSettings.PostIndexShards = ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_SHARDS | ||||
| 	} | ||||
|  | ||||
| 	if o.DataRetentionSettings.Enable == nil { | ||||
| 		o.DataRetentionSettings.Enable = new(bool) | ||||
| 		*o.DataRetentionSettings.Enable = false | ||||
| 	} | ||||
|  | ||||
| 	if o.JobSettings.RunJobs == nil { | ||||
| 		o.JobSettings.RunJobs = new(bool) | ||||
| 		*o.JobSettings.RunJobs = true | ||||
| 	} | ||||
|  | ||||
| 	if o.JobSettings.RunScheduler == nil { | ||||
| 		o.JobSettings.RunScheduler = new(bool) | ||||
| 		*o.JobSettings.RunScheduler = true | ||||
| 	} | ||||
|  | ||||
| 	if o.PluginSettings.Plugins == nil { | ||||
| 		o.PluginSettings.Plugins = make(map[string]interface{}) | ||||
| 	} | ||||
|  | ||||
| 	o.defaultWebrtcSettings() | ||||
| } | ||||
|  | ||||
| @@ -1184,6 +1509,10 @@ func (o *Config) IsValid() *AppError { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.restrict_direct_message.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if !(*o.TeamSettings.TeammateNameDisplay == SHOW_FULLNAME || *o.TeamSettings.TeammateNameDisplay == SHOW_NICKNAME_FULLNAME || *o.TeamSettings.TeammateNameDisplay == SHOW_USERNAME) { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.teammate_name_display.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if len(o.SqlSettings.AtRestEncryptKey) < 32 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.encrypt_sql.app_error", nil, "") | ||||
| 	} | ||||
| @@ -1196,6 +1525,10 @@ func (o *Config) IsValid() *AppError { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.sql_idle.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if *o.SqlSettings.QueryTimeout <= 0 { | ||||
| 		return NewAppError("Config.IsValid", "model.config.is_valid.sql_query_timeout.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.SqlSettings.DataSource) == 0 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.sql_data_src.app_error", nil, "") | ||||
| 	} | ||||
| @@ -1212,30 +1545,6 @@ func (o *Config) IsValid() *AppError { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_driver.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.PreviewHeight < 0 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_preview_height.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.PreviewWidth <= 0 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_preview_width.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.ProfileHeight <= 0 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_profile_height.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.ProfileWidth <= 0 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_profile_width.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.ThumbnailHeight <= 0 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_thumb_height.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if o.FileSettings.ThumbnailWidth <= 0 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_thumb_width.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if len(*o.FileSettings.PublicLinkSalt) < 32 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.file_salt.app_error", nil, "") | ||||
| 	} | ||||
| @@ -1248,10 +1557,6 @@ func (o *Config) IsValid() *AppError { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.email_salt.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if len(o.EmailSettings.PasswordResetSalt) < 32 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.email_reset_salt.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if *o.EmailSettings.EmailBatchingBufferSize <= 0 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.email_batching_buffer_size.app_error", nil, "") | ||||
| 	} | ||||
| @@ -1260,6 +1565,10 @@ func (o *Config) IsValid() *AppError { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.email_batching_interval.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if !(*o.EmailSettings.EmailNotificationContentsType == EMAIL_NOTIFICATION_CONTENTS_FULL || *o.EmailSettings.EmailNotificationContentsType == EMAIL_NOTIFICATION_CONTENTS_GENERIC) { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.email_notification_contents_type.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if o.RateLimitSettings.MemoryStoreSize <= 0 { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.rate_mem.app_error", nil, "") | ||||
| 	} | ||||
| @@ -1376,6 +1685,16 @@ func (o *Config) IsValid() *AppError { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.time_between_user_typing.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if *o.ElasticsearchSettings.EnableIndexing { | ||||
| 		if len(*o.ElasticsearchSettings.ConnectionUrl) == 0 { | ||||
| 			return NewLocAppError("Config.IsValid", "model.config.is_valid.elastic_search.connection_url.app_error", nil, "") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if *o.ElasticsearchSettings.EnableSearching && !*o.ElasticsearchSettings.EnableIndexing { | ||||
| 		return NewLocAppError("Config.IsValid", "model.config.is_valid.elastic_search.enable_searching.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -1398,7 +1717,6 @@ func (o *Config) Sanitize() { | ||||
| 	} | ||||
|  | ||||
| 	o.EmailSettings.InviteSalt = FAKE_SETTING | ||||
| 	o.EmailSettings.PasswordResetSalt = FAKE_SETTING | ||||
| 	if len(o.EmailSettings.SMTPPassword) > 0 { | ||||
| 		o.EmailSettings.SMTPPassword = FAKE_SETTING | ||||
| 	} | ||||
| @@ -1413,6 +1731,12 @@ func (o *Config) Sanitize() { | ||||
| 	for i := range o.SqlSettings.DataSourceReplicas { | ||||
| 		o.SqlSettings.DataSourceReplicas[i] = FAKE_SETTING | ||||
| 	} | ||||
|  | ||||
| 	for i := range o.SqlSettings.DataSourceSearchReplicas { | ||||
| 		o.SqlSettings.DataSourceSearchReplicas[i] = FAKE_SETTING | ||||
| 	} | ||||
|  | ||||
| 	*o.ElasticsearchSettings.Password = FAKE_SETTING | ||||
| } | ||||
|  | ||||
| func (o *Config) defaultWebrtcSettings() { | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/mattermost/platform/model/emoji.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/mattermost/platform/model/emoji.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -34,7 +34,7 @@ func (emoji *Emoji) IsValid() *AppError { | ||||
| 		return NewLocAppError("Emoji.IsValid", "model.emoji.user_id.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
| 	if len(emoji.Name) == 0 || len(emoji.Name) > 64 { | ||||
| 	if len(emoji.Name) == 0 || len(emoji.Name) > 64 || !IsValidAlphaNumHyphenUnderscore(emoji.Name, false) { | ||||
| 		return NewLocAppError("Emoji.IsValid", "model.emoji.name.app_error", nil, "") | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/file_info.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/file_info.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/gitlab.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/gitlab.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/gitlab/gitlab.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/gitlab/gitlab.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package oauthgitlab | ||||
|   | ||||
							
								
								
									
										58
									
								
								vendor/github.com/mattermost/platform/model/incoming_webhook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										58
									
								
								vendor/github.com/mattermost/platform/model/incoming_webhook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -6,10 +6,9 @@ package model | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -81,35 +80,36 @@ func IncomingWebhookListFromJson(data io.Reader) []*IncomingWebhook { | ||||
| func (o *IncomingWebhook) IsValid() *AppError { | ||||
|  | ||||
| 	if len(o.Id) != 26 { | ||||
| 		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.id.app_error", nil, "") | ||||
| 		return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.id.app_error", nil, "", http.StatusBadRequest) | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	if o.CreateAt == 0 { | ||||
| 		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.create_at.app_error", nil, "id="+o.Id) | ||||
| 		return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if o.UpdateAt == 0 { | ||||
| 		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.update_at.app_error", nil, "id="+o.Id) | ||||
| 		return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.UserId) != 26 { | ||||
| 		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.user_id.app_error", nil, "") | ||||
| 		return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.user_id.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.ChannelId) != 26 { | ||||
| 		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.channel_id.app_error", nil, "") | ||||
| 		return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.channel_id.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.TeamId) != 26 { | ||||
| 		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.team_id.app_error", nil, "") | ||||
| 		return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.team_id.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.DisplayName) > 64 { | ||||
| 		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.display_name.app_error", nil, "") | ||||
| 		return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.display_name.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.Description) > 128 { | ||||
| 		return NewLocAppError("IncomingWebhook.IsValid", "model.incoming_hook.description.app_error", nil, "") | ||||
| 		return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.description.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| @@ -193,39 +193,6 @@ func decodeIncomingWebhookRequest(by []byte) (*IncomingWebhookRequest, error) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // To mention @channel via a webhook in Slack, the message should contain | ||||
| // <!channel>, as explained at the bottom of this article: | ||||
| // https://get.slack.help/hc/en-us/articles/202009646-Making-announcements | ||||
| func expandAnnouncement(text string) string { | ||||
| 	c1 := "<!channel>" | ||||
| 	c2 := "@channel" | ||||
| 	if strings.Contains(text, c1) { | ||||
| 		return strings.Replace(text, c1, c2, -1) | ||||
| 	} | ||||
| 	return text | ||||
| } | ||||
|  | ||||
| // Expand announcements in incoming webhooks from Slack. Those announcements | ||||
| // can be found in the text attribute, or in the pretext, text, title and value | ||||
| // attributes of the attachment structure. The Slack attachment structure is | ||||
| // documented here: https://api.slack.com/docs/attachments | ||||
| func expandAnnouncements(i *IncomingWebhookRequest) { | ||||
| 	i.Text = expandAnnouncement(i.Text) | ||||
|  | ||||
| 	for _, attachment := range i.Attachments { | ||||
| 		attachment.Pretext = expandAnnouncement(attachment.Pretext) | ||||
| 		attachment.Text = expandAnnouncement(attachment.Text) | ||||
| 		attachment.Title = expandAnnouncement(attachment.Title) | ||||
|  | ||||
| 		for _, field := range attachment.Fields { | ||||
| 			if field.Value != nil { | ||||
| 				// Ensure the value is set to a string if it is set | ||||
| 				field.Value = expandAnnouncement(fmt.Sprintf("%v", field.Value)) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func IncomingWebhookRequestFromJson(data io.Reader) *IncomingWebhookRequest { | ||||
| 	buf := new(bytes.Buffer) | ||||
| 	buf.ReadFrom(data) | ||||
| @@ -241,7 +208,8 @@ func IncomingWebhookRequestFromJson(data io.Reader) *IncomingWebhookRequest { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	expandAnnouncements(o) | ||||
| 	o.Text = ExpandAnnouncement(o.Text) | ||||
| 	o.Attachments = ProcessSlackAttachments(o.Attachments) | ||||
|  | ||||
| 	return o | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/initial_load.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/initial_load.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										159
									
								
								vendor/github.com/mattermost/platform/model/job.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										159
									
								
								vendor/github.com/mattermost/platform/model/job.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,100 +1,117 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| type TaskFunc func() | ||||
| const ( | ||||
| 	JOB_TYPE_DATA_RETENTION              = "data_retention" | ||||
| 	JOB_TYPE_ELASTICSEARCH_POST_INDEXING = "elasticsearch_post_indexing" | ||||
|  | ||||
| type ScheduledTask struct { | ||||
| 	Name      string        `json:"name"` | ||||
| 	Interval  time.Duration `json:"interval"` | ||||
| 	Recurring bool          `json:"recurring"` | ||||
| 	function  TaskFunc | ||||
| 	timer     *time.Timer | ||||
| 	JOB_STATUS_PENDING          = "pending" | ||||
| 	JOB_STATUS_IN_PROGRESS      = "in_progress" | ||||
| 	JOB_STATUS_SUCCESS          = "success" | ||||
| 	JOB_STATUS_ERROR            = "error" | ||||
| 	JOB_STATUS_CANCEL_REQUESTED = "cancel_requested" | ||||
| 	JOB_STATUS_CANCELED         = "canceled" | ||||
| ) | ||||
|  | ||||
| type Job struct { | ||||
| 	Id             string                 `json:"id"` | ||||
| 	Type           string                 `json:"type"` | ||||
| 	Priority       int64                  `json:"priority"` | ||||
| 	CreateAt       int64                  `json:"create_at"` | ||||
| 	StartAt        int64                  `json:"start_at"` | ||||
| 	LastActivityAt int64                  `json:"last_activity_at"` | ||||
| 	Status         string                 `json:"status"` | ||||
| 	Progress       int64                  `json:"progress"` | ||||
| 	Data           map[string]interface{} `json:"data"` | ||||
| } | ||||
|  | ||||
| var tasks = make(map[string]*ScheduledTask) | ||||
|  | ||||
| func addTask(task *ScheduledTask) { | ||||
| 	tasks[task.Name] = task | ||||
| } | ||||
|  | ||||
| func removeTaskByName(name string) { | ||||
| 	delete(tasks, name) | ||||
| } | ||||
|  | ||||
| func GetTaskByName(name string) *ScheduledTask { | ||||
| 	if task, ok := tasks[name]; ok { | ||||
| 		return task | ||||
| func (j *Job) IsValid() *AppError { | ||||
| 	if len(j.Id) != 26 { | ||||
| 		return NewAppError("Job.IsValid", "model.job.is_valid.id.app_error", nil, "id="+j.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if j.CreateAt == 0 { | ||||
| 		return NewAppError("Job.IsValid", "model.job.is_valid.create_at.app_error", nil, "id="+j.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	switch j.Type { | ||||
| 	case JOB_TYPE_DATA_RETENTION: | ||||
| 	case JOB_TYPE_ELASTICSEARCH_POST_INDEXING: | ||||
| 	default: | ||||
| 		return NewAppError("Job.IsValid", "model.job.is_valid.type.app_error", nil, "id="+j.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	switch j.Status { | ||||
| 	case JOB_STATUS_PENDING: | ||||
| 	case JOB_STATUS_IN_PROGRESS: | ||||
| 	case JOB_STATUS_SUCCESS: | ||||
| 	case JOB_STATUS_ERROR: | ||||
| 	case JOB_STATUS_CANCEL_REQUESTED: | ||||
| 	case JOB_STATUS_CANCELED: | ||||
| 	default: | ||||
| 		return NewAppError("Job.IsValid", "model.job.is_valid.status.app_error", nil, "id="+j.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func GetAllTasks() *map[string]*ScheduledTask { | ||||
| 	return &tasks | ||||
| } | ||||
|  | ||||
| func CreateTask(name string, function TaskFunc, timeToExecution time.Duration) *ScheduledTask { | ||||
| 	task := &ScheduledTask{ | ||||
| 		Name:      name, | ||||
| 		Interval:  timeToExecution, | ||||
| 		Recurring: false, | ||||
| 		function:  function, | ||||
| func (js *Job) ToJson() string { | ||||
| 	if b, err := json.Marshal(js); err != nil { | ||||
| 		return "" | ||||
| 	} else { | ||||
| 		return string(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 	taskRunner := func() { | ||||
| 		go task.function() | ||||
| 		removeTaskByName(task.Name) | ||||
| func JobFromJson(data io.Reader) *Job { | ||||
| 	var job Job | ||||
| 	if err := json.NewDecoder(data).Decode(&job); err == nil { | ||||
| 		return &job | ||||
| 	} else { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	task.timer = time.AfterFunc(timeToExecution, taskRunner) | ||||
|  | ||||
| 	addTask(task) | ||||
|  | ||||
| 	return task | ||||
| } | ||||
|  | ||||
| func CreateRecurringTask(name string, function TaskFunc, interval time.Duration) *ScheduledTask { | ||||
| 	task := &ScheduledTask{ | ||||
| 		Name:      name, | ||||
| 		Interval:  interval, | ||||
| 		Recurring: true, | ||||
| 		function:  function, | ||||
| func JobsToJson(jobs []*Job) string { | ||||
| 	if b, err := json.Marshal(jobs); err != nil { | ||||
| 		return "" | ||||
| 	} else { | ||||
| 		return string(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 	taskRecurer := func() { | ||||
| 		go task.function() | ||||
| 		task.timer.Reset(task.Interval) | ||||
| func JobsFromJson(data io.Reader) []*Job { | ||||
| 	var jobs []*Job | ||||
| 	if err := json.NewDecoder(data).Decode(&jobs); err == nil { | ||||
| 		return jobs | ||||
| 	} else { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	task.timer = time.AfterFunc(interval, taskRecurer) | ||||
|  | ||||
| 	addTask(task) | ||||
|  | ||||
| 	return task | ||||
| } | ||||
|  | ||||
| func (task *ScheduledTask) Cancel() { | ||||
| 	task.timer.Stop() | ||||
| 	removeTaskByName(task.Name) | ||||
| func (js *Job) DataToJson() string { | ||||
| 	if b, err := json.Marshal(js.Data); err != nil { | ||||
| 		return "" | ||||
| 	} else { | ||||
| 		return string(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Executes the task immediatly. A recurring task will be run regularally after interval. | ||||
| func (task *ScheduledTask) Execute() { | ||||
| 	task.function() | ||||
| 	task.timer.Reset(task.Interval) | ||||
| type Worker interface { | ||||
| 	Run() | ||||
| 	Stop() | ||||
| 	JobChannel() chan<- Job | ||||
| } | ||||
|  | ||||
| func (task *ScheduledTask) String() string { | ||||
| 	return fmt.Sprintf( | ||||
| 		"%s\nInterval: %s\nRecurring: %t\n", | ||||
| 		task.Name, | ||||
| 		task.Interval.String(), | ||||
| 		task.Recurring, | ||||
| 	) | ||||
| type Scheduler interface { | ||||
| 	Run() | ||||
| 	Stop() | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/mattermost/platform/model/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/mattermost/platform/model/ldap.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|   | ||||
							
								
								
									
										71
									
								
								vendor/github.com/mattermost/platform/model/license.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/mattermost/platform/model/license.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -37,36 +37,42 @@ type Customer struct { | ||||
| } | ||||
|  | ||||
| type Features struct { | ||||
| 	Users                *int  `json:"users"` | ||||
| 	LDAP                 *bool `json:"ldap"` | ||||
| 	MFA                  *bool `json:"mfa"` | ||||
| 	GoogleOAuth          *bool `json:"google_oauth"` | ||||
| 	Office365OAuth       *bool `json:"office365_oauth"` | ||||
| 	Compliance           *bool `json:"compliance"` | ||||
| 	Cluster              *bool `json:"cluster"` | ||||
| 	Metrics              *bool `json:"metrics"` | ||||
| 	CustomBrand          *bool `json:"custom_brand"` | ||||
| 	MHPNS                *bool `json:"mhpns"` | ||||
| 	SAML                 *bool `json:"saml"` | ||||
| 	PasswordRequirements *bool `json:"password_requirements"` | ||||
| 	Users                     *int  `json:"users"` | ||||
| 	LDAP                      *bool `json:"ldap"` | ||||
| 	MFA                       *bool `json:"mfa"` | ||||
| 	GoogleOAuth               *bool `json:"google_oauth"` | ||||
| 	Office365OAuth            *bool `json:"office365_oauth"` | ||||
| 	Compliance                *bool `json:"compliance"` | ||||
| 	Cluster                   *bool `json:"cluster"` | ||||
| 	Metrics                   *bool `json:"metrics"` | ||||
| 	CustomBrand               *bool `json:"custom_brand"` | ||||
| 	MHPNS                     *bool `json:"mhpns"` | ||||
| 	SAML                      *bool `json:"saml"` | ||||
| 	PasswordRequirements      *bool `json:"password_requirements"` | ||||
| 	Elasticsearch             *bool `json:"elastic_search"` | ||||
| 	Announcement              *bool `json:"announcement"` | ||||
| 	EmailNotificationContents *bool `json:"email_notification_contents"` | ||||
|  | ||||
| 	// after we enabled more features for webrtc we'll need to control them with this | ||||
| 	FutureFeatures *bool `json:"future_features"` | ||||
| } | ||||
|  | ||||
| func (f *Features) ToMap() map[string]interface{} { | ||||
| 	return map[string]interface{}{ | ||||
| 		"ldap":         *f.LDAP, | ||||
| 		"mfa":          *f.MFA, | ||||
| 		"google":       *f.GoogleOAuth, | ||||
| 		"office365":    *f.Office365OAuth, | ||||
| 		"compliance":   *f.Compliance, | ||||
| 		"cluster":      *f.Cluster, | ||||
| 		"metrics":      *f.Metrics, | ||||
| 		"custom_brand": *f.CustomBrand, | ||||
| 		"mhpns":        *f.MHPNS, | ||||
| 		"saml":         *f.SAML, | ||||
| 		"password":     *f.PasswordRequirements, | ||||
| 		"future":       *f.FutureFeatures, | ||||
| 		"ldap":                        *f.LDAP, | ||||
| 		"mfa":                         *f.MFA, | ||||
| 		"google":                      *f.GoogleOAuth, | ||||
| 		"office365":                   *f.Office365OAuth, | ||||
| 		"compliance":                  *f.Compliance, | ||||
| 		"cluster":                     *f.Cluster, | ||||
| 		"metrics":                     *f.Metrics, | ||||
| 		"custom_brand":                *f.CustomBrand, | ||||
| 		"mhpns":                       *f.MHPNS, | ||||
| 		"saml":                        *f.SAML, | ||||
| 		"password":                    *f.PasswordRequirements, | ||||
| 		"elastic_search":              *f.Elasticsearch, | ||||
| 		"email_notification_contents": *f.EmailNotificationContents, | ||||
| 		"future":                      *f.FutureFeatures, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -135,6 +141,21 @@ func (f *Features) SetDefaults() { | ||||
| 		f.PasswordRequirements = new(bool) | ||||
| 		*f.PasswordRequirements = *f.FutureFeatures | ||||
| 	} | ||||
|  | ||||
| 	if f.Elasticsearch == nil { | ||||
| 		f.Elasticsearch = new(bool) | ||||
| 		*f.Elasticsearch = *f.FutureFeatures | ||||
| 	} | ||||
|  | ||||
| 	if f.Announcement == nil { | ||||
| 		f.Announcement = new(bool) | ||||
| 		*f.Announcement = true | ||||
| 	} | ||||
|  | ||||
| 	if f.EmailNotificationContents == nil { | ||||
| 		f.EmailNotificationContents = new(bool) | ||||
| 		*f.EmailNotificationContents = *f.FutureFeatures | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (l *License) IsExpired() bool { | ||||
|   | ||||
							
								
								
									
										34
									
								
								vendor/github.com/mattermost/platform/model/mfa_secret.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/mattermost/platform/model/mfa_secret.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"io" | ||||
| ) | ||||
|  | ||||
| type MfaSecret struct { | ||||
| 	Secret string `json:"secret"` | ||||
| 	QRCode string `json:"qr_code"` | ||||
| } | ||||
|  | ||||
| func (me *MfaSecret) ToJson() string { | ||||
| 	b, err := json.Marshal(me) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} else { | ||||
| 		return string(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func MfaSecretFromJson(data io.Reader) *MfaSecret { | ||||
| 	decoder := json.NewDecoder(data) | ||||
| 	var me MfaSecret | ||||
| 	err := decoder.Decode(&me) | ||||
| 	if err == nil { | ||||
| 		return &me | ||||
| 	} else { | ||||
| 		return nil | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										26
									
								
								vendor/github.com/mattermost/platform/model/oauth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/mattermost/platform/model/oauth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -7,6 +7,7 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"unicode/utf8" | ||||
| ) | ||||
|  | ||||
| @@ -15,6 +16,7 @@ const ( | ||||
| 	OAUTH_ACTION_LOGIN        = "login" | ||||
| 	OAUTH_ACTION_EMAIL_TO_SSO = "email_to_sso" | ||||
| 	OAUTH_ACTION_SSO_TO_EMAIL = "sso_to_email" | ||||
| 	OAUTH_ACTION_MOBILE       = "mobile" | ||||
| ) | ||||
|  | ||||
| type OAuthApp struct { | ||||
| @@ -36,50 +38,50 @@ type OAuthApp struct { | ||||
| func (a *OAuthApp) IsValid() *AppError { | ||||
|  | ||||
| 	if len(a.Id) != 26 { | ||||
| 		return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.app_id.app_error", nil, "") | ||||
| 		return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.app_id.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if a.CreateAt == 0 { | ||||
| 		return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.create_at.app_error", nil, "app_id="+a.Id) | ||||
| 		return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.create_at.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if a.UpdateAt == 0 { | ||||
| 		return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.update_at.app_error", nil, "app_id="+a.Id) | ||||
| 		return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.update_at.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(a.CreatorId) != 26 { | ||||
| 		return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.creator_id.app_error", nil, "app_id="+a.Id) | ||||
| 		return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.creator_id.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(a.ClientSecret) == 0 || len(a.ClientSecret) > 128 { | ||||
| 		return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.client_secret.app_error", nil, "app_id="+a.Id) | ||||
| 		return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.client_secret.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(a.Name) == 0 || len(a.Name) > 64 { | ||||
| 		return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.name.app_error", nil, "app_id="+a.Id) | ||||
| 		return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.name.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(a.CallbackUrls) == 0 || len(fmt.Sprintf("%s", a.CallbackUrls)) > 1024 { | ||||
| 		return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "app_id="+a.Id) | ||||
| 		return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	for _, callback := range a.CallbackUrls { | ||||
| 		if !IsValidHttpUrl(callback) { | ||||
| 			return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "") | ||||
| 			return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "", http.StatusBadRequest) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(a.Homepage) == 0 || len(a.Homepage) > 256 || !IsValidHttpUrl(a.Homepage) { | ||||
| 		return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.homepage.app_error", nil, "app_id="+a.Id) | ||||
| 		return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.homepage.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if utf8.RuneCountInString(a.Description) > 512 { | ||||
| 		return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.description.app_error", nil, "app_id="+a.Id) | ||||
| 		return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.description.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(a.IconURL) > 0 { | ||||
| 		if len(a.IconURL) > 512 || !IsValidHttpUrl(a.IconURL) { | ||||
| 			return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.icon_url.app_error", nil, "app_id="+a.Id) | ||||
| 			return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.icon_url.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										65
									
								
								vendor/github.com/mattermost/platform/model/outgoing_webhook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/mattermost/platform/model/outgoing_webhook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. | ||||
| // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. | ||||
| // See License.txt for license information. | ||||
|  | ||||
| package model | ||||
| @@ -7,6 +7,7 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| @@ -41,6 +42,7 @@ type OutgoingWebhookPayload struct { | ||||
| 	PostId      string `json:"post_id"` | ||||
| 	Text        string `json:"text"` | ||||
| 	TriggerWord string `json:"trigger_word"` | ||||
| 	FileIds     string `json:"file_ids"` | ||||
| } | ||||
|  | ||||
| func (o *OutgoingWebhookPayload) ToJSON() string { | ||||
| @@ -65,6 +67,7 @@ func (o *OutgoingWebhookPayload) ToFormValues() string { | ||||
| 	v.Set("post_id", o.PostId) | ||||
| 	v.Set("text", o.Text) | ||||
| 	v.Set("trigger_word", o.TriggerWord) | ||||
| 	v.Set("file_ids", o.FileIds) | ||||
|  | ||||
| 	return v.Encode() | ||||
| } | ||||
| @@ -112,69 +115,69 @@ func OutgoingWebhookListFromJson(data io.Reader) []*OutgoingWebhook { | ||||
| func (o *OutgoingWebhook) IsValid() *AppError { | ||||
|  | ||||
| 	if len(o.Id) != 26 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.id.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.id.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.Token) != 26 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.token.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.token.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if o.CreateAt == 0 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.create_at.app_error", nil, "id="+o.Id) | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if o.UpdateAt == 0 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.update_at.app_error", nil, "id="+o.Id) | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.CreatorId) != 26 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.user_id.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.ChannelId) != 0 && len(o.ChannelId) != 26 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.channel_id.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.TeamId) != 26 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.team_id.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.team_id.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(fmt.Sprintf("%s", o.TriggerWords)) > 1024 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.words.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.words.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.TriggerWords) != 0 { | ||||
| 		for _, triggerWord := range o.TriggerWords { | ||||
| 			if len(triggerWord) == 0 { | ||||
| 				return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.trigger_words.app_error", nil, "") | ||||
| 				return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.trigger_words.app_error", nil, "", http.StatusBadRequest) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(o.CallbackURLs) == 0 || len(fmt.Sprintf("%s", o.CallbackURLs)) > 1024 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.callback.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.callback.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	for _, callback := range o.CallbackURLs { | ||||
| 		if !IsValidHttpUrl(callback) { | ||||
| 			return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.url.app_error", nil, "") | ||||
| 			return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.url.app_error", nil, "", http.StatusBadRequest) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(o.DisplayName) > 64 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.display_name.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.display_name.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.Description) > 128 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.description.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.description.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if len(o.ContentType) > 128 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	if o.TriggerWhen > 1 { | ||||
| 		return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "") | ||||
| 		return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "", http.StatusBadRequest) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| @@ -197,8 +200,8 @@ func (o *OutgoingWebhook) PreUpdate() { | ||||
| 	o.UpdateAt = GetMillis() | ||||
| } | ||||
|  | ||||
| func (o *OutgoingWebhook) HasTriggerWord(word string) bool { | ||||
| 	if len(o.TriggerWords) == 0 || len(word) == 0 { | ||||
| func (o *OutgoingWebhook) TriggerWordExactMatch(word string) bool { | ||||
| 	if len(word) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| @@ -212,7 +215,7 @@ func (o *OutgoingWebhook) HasTriggerWord(word string) bool { | ||||
| } | ||||
|  | ||||
| func (o *OutgoingWebhook) TriggerWordStartsWith(word string) bool { | ||||
| 	if len(o.TriggerWords) == 0 || len(word) == 0 { | ||||
| 	if len(word) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| @@ -224,3 +227,27 @@ func (o *OutgoingWebhook) TriggerWordStartsWith(word string) bool { | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func (o *OutgoingWebhook) GetTriggerWord(word string, isExactMatch bool) (triggerWord string) { | ||||
| 	if len(word) == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if isExactMatch { | ||||
| 		for _, trigger := range o.TriggerWords { | ||||
| 			if trigger == word { | ||||
| 				triggerWord = trigger | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		for _, trigger := range o.TriggerWords { | ||||
| 			if strings.HasPrefix(word, trigger) { | ||||
| 				triggerWord = trigger | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return triggerWord | ||||
| } | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user