Sync with mattermost 3.1.0
This commit is contained in:
parent
e48db67649
commit
6ec77e06ea
|
@ -23,6 +23,7 @@ type MMhook struct {
|
||||||
type MMapi struct {
|
type MMapi struct {
|
||||||
mc *matterclient.MMClient
|
mc *matterclient.MMClient
|
||||||
mmMap map[string]string
|
mmMap map[string]string
|
||||||
|
mmIgnoreNicks []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MMirc struct {
|
type MMirc struct {
|
||||||
|
@ -30,6 +31,7 @@ type MMirc struct {
|
||||||
ircNick string
|
ircNick string
|
||||||
ircMap map[string]string
|
ircMap map[string]string
|
||||||
names map[string][]string
|
names map[string][]string
|
||||||
|
ircIgnoreNicks []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type MMMessage struct {
|
type MMMessage struct {
|
||||||
|
@ -53,6 +55,8 @@ type FancyLog struct {
|
||||||
|
|
||||||
var flog FancyLog
|
var flog FancyLog
|
||||||
|
|
||||||
|
const Legacy = "legacy"
|
||||||
|
|
||||||
func initFLog() {
|
func initFLog() {
|
||||||
flog.irc = log.WithFields(log.Fields{"module": "irc"})
|
flog.irc = log.WithFields(log.Fields{"module": "irc"})
|
||||||
flog.mm = log.WithFields(log.Fields{"module": "mattermost"})
|
flog.mm = log.WithFields(log.Fields{"module": "mattermost"})
|
||||||
|
@ -66,7 +70,9 @@ func NewBridge(name string, config *Config, kind string) *Bridge {
|
||||||
b.ircNick = b.Config.IRC.Nick
|
b.ircNick = b.Config.IRC.Nick
|
||||||
b.ircMap = make(map[string]string)
|
b.ircMap = make(map[string]string)
|
||||||
b.MMirc.names = make(map[string][]string)
|
b.MMirc.names = make(map[string][]string)
|
||||||
if kind == "legacy" {
|
b.ircIgnoreNicks = strings.Fields(b.Config.IRC.IgnoreNicks)
|
||||||
|
b.mmIgnoreNicks = strings.Fields(b.Config.Mattermost.IgnoreNicks)
|
||||||
|
if kind == Legacy {
|
||||||
if len(b.Config.Token) > 0 {
|
if len(b.Config.Token) > 0 {
|
||||||
for _, val := range b.Config.Token {
|
for _, val := range b.Config.Token {
|
||||||
b.ircMap[val.IRCChannel] = val.MMChannel
|
b.ircMap[val.IRCChannel] = val.MMChannel
|
||||||
|
@ -87,10 +93,14 @@ func NewBridge(name string, config *Config, kind string) *Bridge {
|
||||||
}
|
}
|
||||||
b.mc = matterclient.New(b.Config.Mattermost.Login, b.Config.Mattermost.Password,
|
b.mc = matterclient.New(b.Config.Mattermost.Login, b.Config.Mattermost.Password,
|
||||||
b.Config.Mattermost.Team, b.Config.Mattermost.Server)
|
b.Config.Mattermost.Team, b.Config.Mattermost.Server)
|
||||||
|
b.mc.SkipTLSVerify = b.Config.Mattermost.SkipTLSVerify
|
||||||
|
b.mc.NoTLS = b.Config.Mattermost.NoTLS
|
||||||
|
flog.mm.Infof("Trying login %s (team: %s) on %s", b.Config.Mattermost.Login, b.Config.Mattermost.Team, b.Config.Mattermost.Server)
|
||||||
err := b.mc.Login()
|
err := b.mc.Login()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
flog.mm.Fatal("can not connect", err)
|
flog.mm.Fatal("Can not connect", err)
|
||||||
}
|
}
|
||||||
|
flog.mm.Info("Login ok")
|
||||||
b.mc.JoinChannel(b.Config.Mattermost.Channel)
|
b.mc.JoinChannel(b.Config.Mattermost.Channel)
|
||||||
if len(b.Config.Channel) > 0 {
|
if len(b.Config.Channel) > 0 {
|
||||||
for _, val := range b.Config.Channel {
|
for _, val := range b.Config.Channel {
|
||||||
|
@ -99,7 +109,9 @@ func NewBridge(name string, config *Config, kind string) *Bridge {
|
||||||
}
|
}
|
||||||
go b.mc.WsReceiver()
|
go b.mc.WsReceiver()
|
||||||
}
|
}
|
||||||
|
flog.irc.Info("Trying IRC connection")
|
||||||
b.i = b.createIRC(name)
|
b.i = b.createIRC(name)
|
||||||
|
flog.irc.Info("Connection succeeded")
|
||||||
go b.handleMatter()
|
go b.handleMatter()
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
@ -111,37 +123,51 @@ func (b *Bridge) createIRC(name string) *irc.Connection {
|
||||||
if b.Config.IRC.Password != "" {
|
if b.Config.IRC.Password != "" {
|
||||||
i.Password = b.Config.IRC.Password
|
i.Password = b.Config.IRC.Password
|
||||||
}
|
}
|
||||||
i.AddCallback("*", b.handleOther)
|
i.AddCallback(ircm.RPL_WELCOME, b.handleNewConnection)
|
||||||
i.Connect(b.Config.IRC.Server + ":" + strconv.Itoa(b.Config.IRC.Port))
|
i.Connect(b.Config.IRC.Server + ":" + strconv.Itoa(b.Config.IRC.Port))
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) handleNewConnection(event *irc.Event) {
|
func (b *Bridge) handleNewConnection(event *irc.Event) {
|
||||||
|
flog.irc.Info("Registering callbacks")
|
||||||
|
i := b.i
|
||||||
b.ircNick = event.Arguments[0]
|
b.ircNick = event.Arguments[0]
|
||||||
|
i.AddCallback("PRIVMSG", b.handlePrivMsg)
|
||||||
|
i.AddCallback("CTCP_ACTION", b.handlePrivMsg)
|
||||||
|
i.AddCallback(ircm.RPL_ENDOFNAMES, b.endNames)
|
||||||
|
i.AddCallback(ircm.RPL_NAMREPLY, b.storeNames)
|
||||||
|
i.AddCallback(ircm.RPL_TOPICWHOTIME, b.handleTopicWhoTime)
|
||||||
|
i.AddCallback(ircm.NOTICE, b.handleNotice)
|
||||||
|
i.AddCallback(ircm.RPL_MYINFO, func(e *irc.Event) { flog.irc.Infof("%s: %s", e.Code, strings.Join(e.Arguments[1:], " ")) })
|
||||||
|
i.AddCallback("PING", func(e *irc.Event) {
|
||||||
|
i.SendRaw("PONG :" + e.Message())
|
||||||
|
flog.irc.Debugf("PING/PONG")
|
||||||
|
})
|
||||||
|
if b.Config.Mattermost.ShowJoinPart {
|
||||||
|
i.AddCallback("JOIN", b.handleJoinPart)
|
||||||
|
i.AddCallback("PART", b.handleJoinPart)
|
||||||
|
}
|
||||||
|
i.AddCallback("*", b.handleOther)
|
||||||
b.setupChannels()
|
b.setupChannels()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) setupChannels() {
|
func (b *Bridge) setupChannels() {
|
||||||
i := b.i
|
i := b.i
|
||||||
flog.irc.Info("Joining ", b.Config.IRC.Channel, " as ", b.ircNick)
|
if b.Config.IRC.Channel != "" {
|
||||||
|
flog.irc.Infof("Joining %s as %s", b.Config.IRC.Channel, b.ircNick)
|
||||||
i.Join(b.Config.IRC.Channel)
|
i.Join(b.Config.IRC.Channel)
|
||||||
if b.kind == "legacy" {
|
}
|
||||||
|
if b.kind == Legacy {
|
||||||
for _, val := range b.Config.Token {
|
for _, val := range b.Config.Token {
|
||||||
flog.irc.Info("Joining ", val.IRCChannel, " as ", b.ircNick)
|
flog.irc.Infof("Joining %s as %s", val.IRCChannel, b.ircNick)
|
||||||
i.Join(val.IRCChannel)
|
i.Join(val.IRCChannel)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for _, val := range b.Config.Channel {
|
for _, val := range b.Config.Channel {
|
||||||
flog.irc.Info("Joining ", val.IRC, " as ", b.ircNick)
|
flog.irc.Infof("Joining %s as %s", val.IRC, b.ircNick)
|
||||||
i.Join(val.IRC)
|
i.Join(val.IRC)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i.AddCallback("PRIVMSG", b.handlePrivMsg)
|
|
||||||
i.AddCallback("CTCP_ACTION", b.handlePrivMsg)
|
|
||||||
if b.Config.Mattermost.ShowJoinPart {
|
|
||||||
i.AddCallback("JOIN", b.handleJoinPart)
|
|
||||||
i.AddCallback("PART", b.handleJoinPart)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) handleIrcBotCommand(event *irc.Event) bool {
|
func (b *Bridge) handleIrcBotCommand(event *irc.Event) bool {
|
||||||
|
@ -177,6 +203,9 @@ func (b *Bridge) ircNickFormat(nick string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) handlePrivMsg(event *irc.Event) {
|
func (b *Bridge) handlePrivMsg(event *irc.Event) {
|
||||||
|
if b.ignoreMessage(event.Nick, event.Message(), "irc") {
|
||||||
|
return
|
||||||
|
}
|
||||||
if b.handleIrcBotCommand(event) {
|
if b.handleIrcBotCommand(event) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -238,81 +267,21 @@ func (b *Bridge) endNames(event *irc.Event) {
|
||||||
b.MMirc.names[channel] = nil
|
b.MMirc.names[channel] = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) handleTopicWhoTime(event *irc.Event) bool {
|
func (b *Bridge) handleTopicWhoTime(event *irc.Event) {
|
||||||
parts := strings.Split(event.Arguments[2], "!")
|
parts := strings.Split(event.Arguments[2], "!")
|
||||||
t_i, err := strconv.ParseInt(event.Arguments[3], 10, 64)
|
t, err := strconv.ParseInt(event.Arguments[3], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
flog.irc.Errorf("Invalid time stamp: %s", event.Arguments[3])
|
flog.irc.Errorf("Invalid time stamp: %s", event.Arguments[3])
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
user := parts[0]
|
user := parts[0]
|
||||||
if len(parts) > 1 {
|
if len(parts) > 1 {
|
||||||
user += " [" + parts[1] + "]"
|
user += " [" + parts[1] + "]"
|
||||||
}
|
}
|
||||||
flog.irc.Infof("%s: Topic set by %s [%s]", event.Code, user, time.Unix(t_i, 0))
|
flog.irc.Infof("%s: Topic set by %s [%s]", event.Code, user, time.Unix(t, 0))
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) handleOther(event *irc.Event) {
|
func (b *Bridge) handleOther(event *irc.Event) {
|
||||||
flog.irc.Debugf("%#v", event)
|
flog.irc.Debugf("%#v", event)
|
||||||
switch event.Code {
|
|
||||||
case ircm.RPL_WELCOME:
|
|
||||||
b.handleNewConnection(event)
|
|
||||||
case ircm.RPL_ENDOFNAMES:
|
|
||||||
b.endNames(event)
|
|
||||||
case ircm.RPL_NAMREPLY:
|
|
||||||
b.storeNames(event)
|
|
||||||
case ircm.RPL_ISUPPORT:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_LUSEROP:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_LUSERUNKNOWN:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_LUSERCHANNELS:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_MYINFO:
|
|
||||||
flog.irc.Infof("%s: %s", event.Code, strings.Join(event.Arguments[1:], " "))
|
|
||||||
case ircm.RPL_YOURHOST:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_CREATED:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_STATSDLINE:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_LUSERCLIENT:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_LUSERME:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_LOCALUSERS:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_GLOBALUSERS:
|
|
||||||
fallthrough
|
|
||||||
case ircm.RPL_MOTD:
|
|
||||||
flog.irc.Infof("%s: %s", event.Code, event.Message())
|
|
||||||
// flog.irc.Info(event.Message())
|
|
||||||
case ircm.RPL_TOPIC:
|
|
||||||
flog.irc.Infof("%s: Topic for %s: %s", event.Code, event.Arguments[1], event.Message())
|
|
||||||
case ircm.RPL_TOPICWHOTIME:
|
|
||||||
if !b.handleTopicWhoTime(event) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case ircm.MODE:
|
|
||||||
flog.irc.Infof("%s: %s %s", event.Code, event.Arguments[1], event.Arguments[0])
|
|
||||||
case ircm.JOIN:
|
|
||||||
fallthrough
|
|
||||||
case ircm.PING:
|
|
||||||
fallthrough
|
|
||||||
case ircm.PONG:
|
|
||||||
flog.irc.Infof("%s: %s", event.Code, event.Message())
|
|
||||||
case ircm.RPL_ENDOFMOTD:
|
|
||||||
case ircm.RPL_MOTDSTART:
|
|
||||||
case ircm.ERR_NICKNAMEINUSE:
|
|
||||||
flog.irc.Warn(event.Message())
|
|
||||||
case ircm.NOTICE:
|
|
||||||
b.handleNotice(event)
|
|
||||||
default:
|
|
||||||
flog.irc.Infof("UNKNOWN EVENT: %#v", event)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) Send(nick string, message string, channel string) error {
|
func (b *Bridge) Send(nick string, message string, channel string) error {
|
||||||
|
@ -327,7 +296,7 @@ func (b *Bridge) SendType(nick string, message string, channel string, mtype str
|
||||||
message = nick + " " + message
|
message = nick + " " + message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if b.kind == "legacy" {
|
if b.kind == Legacy {
|
||||||
matterMessage := matterhook.OMessage{IconURL: b.Config.Mattermost.IconURL}
|
matterMessage := matterhook.OMessage{IconURL: b.Config.Mattermost.IconURL}
|
||||||
matterMessage.Channel = channel
|
matterMessage.Channel = channel
|
||||||
matterMessage.UserName = nick
|
matterMessage.UserName = nick
|
||||||
|
@ -371,24 +340,34 @@ func (b *Bridge) handleMatterClient(mchan chan *MMMessage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) handleMatter() {
|
func (b *Bridge) handleMatter() {
|
||||||
|
flog.mm.Infof("Choosing Mattermost connection type %s", b.kind)
|
||||||
mchan := make(chan *MMMessage)
|
mchan := make(chan *MMMessage)
|
||||||
if b.kind == "legacy" {
|
if b.kind == Legacy {
|
||||||
go b.handleMatterHook(mchan)
|
go b.handleMatterHook(mchan)
|
||||||
} else {
|
} else {
|
||||||
go b.handleMatterClient(mchan)
|
go b.handleMatterClient(mchan)
|
||||||
}
|
}
|
||||||
|
flog.mm.Info("Start listening for Mattermost messages")
|
||||||
for message := range mchan {
|
for message := range mchan {
|
||||||
var username string
|
var username string
|
||||||
|
if b.ignoreMessage(message.Username, message.Text, "mattermost") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
username = message.Username + ": "
|
username = message.Username + ": "
|
||||||
if b.Config.IRC.RemoteNickFormat != "" {
|
if b.Config.IRC.RemoteNickFormat != "" {
|
||||||
username = strings.Replace(b.Config.IRC.RemoteNickFormat, "{NICK}", message.Username, -1)
|
username = strings.Replace(b.Config.IRC.RemoteNickFormat, "{NICK}", message.Username, -1)
|
||||||
} else if b.Config.IRC.UseSlackCircumfix {
|
} else if b.Config.IRC.UseSlackCircumfix {
|
||||||
username = "<" + message.Username + "> "
|
username = "<" + message.Username + "> "
|
||||||
}
|
}
|
||||||
cmd := strings.Fields(message.Text)[0]
|
cmds := strings.Fields(message.Text)
|
||||||
|
// empty message
|
||||||
|
if len(cmds) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmd := cmds[0]
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case "!users":
|
case "!users":
|
||||||
flog.mm.Info("received !users from ", message.Username)
|
flog.mm.Info("Received !users from ", message.Username)
|
||||||
b.i.SendRaw("NAMES " + b.getIRCChannel(message.Channel))
|
b.i.SendRaw("NAMES " + b.getIRCChannel(message.Channel))
|
||||||
continue
|
continue
|
||||||
case "!gif":
|
case "!gif":
|
||||||
|
@ -425,7 +404,7 @@ func (b *Bridge) getMMChannel(ircChannel string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Bridge) getIRCChannel(channel string) string {
|
func (b *Bridge) getIRCChannel(channel string) string {
|
||||||
if b.kind == "legacy" {
|
if b.kind == Legacy {
|
||||||
ircchannel := b.Config.IRC.Channel
|
ircchannel := b.Config.IRC.Channel
|
||||||
_, ok := b.Config.Token[channel]
|
_, ok := b.Config.Token[channel]
|
||||||
if ok {
|
if ok {
|
||||||
|
@ -439,3 +418,17 @@ func (b *Bridge) getIRCChannel(channel string) string {
|
||||||
}
|
}
|
||||||
return ircchannel
|
return ircchannel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Bridge) ignoreMessage(nick string, message string, protocol string) bool {
|
||||||
|
var ignoreNicks = b.mmIgnoreNicks
|
||||||
|
if protocol == "irc" {
|
||||||
|
ignoreNicks = b.ircIgnoreNicks
|
||||||
|
}
|
||||||
|
// should we discard messages ?
|
||||||
|
for _, entry := range ignoreNicks {
|
||||||
|
if nick == entry {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ type Config struct {
|
||||||
NickServNick string
|
NickServNick string
|
||||||
NickServPassword string
|
NickServPassword string
|
||||||
RemoteNickFormat string
|
RemoteNickFormat string
|
||||||
|
IgnoreNicks string
|
||||||
}
|
}
|
||||||
Mattermost struct {
|
Mattermost struct {
|
||||||
URL string
|
URL string
|
||||||
|
@ -37,6 +38,8 @@ type Config struct {
|
||||||
Login string
|
Login string
|
||||||
Password string
|
Password string
|
||||||
RemoteNickFormat *string
|
RemoteNickFormat *string
|
||||||
|
IgnoreNicks string
|
||||||
|
NoTLS bool
|
||||||
}
|
}
|
||||||
Token map[string]*struct {
|
Token map[string]*struct {
|
||||||
IRCChannel string
|
IRCChannel string
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package matterclient
|
package matterclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/cookiejar"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -18,6 +21,7 @@ type Credentials struct {
|
||||||
Pass string
|
Pass string
|
||||||
Server string
|
Server string
|
||||||
NoTLS bool
|
NoTLS bool
|
||||||
|
SkipTLSVerify bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
|
@ -33,6 +37,8 @@ type MMClient struct {
|
||||||
*Credentials
|
*Credentials
|
||||||
Client *model.Client
|
Client *model.Client
|
||||||
WsClient *websocket.Conn
|
WsClient *websocket.Conn
|
||||||
|
WsQuit bool
|
||||||
|
WsAway bool
|
||||||
Channels *model.ChannelList
|
Channels *model.ChannelList
|
||||||
MoreChannels *model.ChannelList
|
MoreChannels *model.ChannelList
|
||||||
User *model.User
|
User *model.User
|
||||||
|
@ -60,6 +66,9 @@ func (m *MMClient) SetLogLevel(level string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MMClient) Login() error {
|
func (m *MMClient) Login() error {
|
||||||
|
if m.WsQuit {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
b := &backoff.Backoff{
|
b := &backoff.Backoff{
|
||||||
Min: time.Second,
|
Min: time.Second,
|
||||||
Max: 5 * time.Minute,
|
Max: 5 * time.Minute,
|
||||||
|
@ -73,12 +82,25 @@ func (m *MMClient) Login() error {
|
||||||
}
|
}
|
||||||
// login to mattermost
|
// login to mattermost
|
||||||
m.Client = model.NewClient(uriScheme + m.Credentials.Server)
|
m.Client = model.NewClient(uriScheme + m.Credentials.Server)
|
||||||
|
m.Client.HttpClient.Transport = &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}}
|
||||||
var myinfo *model.Result
|
var myinfo *model.Result
|
||||||
var appErr *model.AppError
|
var appErr *model.AppError
|
||||||
var logmsg = "trying login"
|
var logmsg = "trying login"
|
||||||
for {
|
for {
|
||||||
m.log.Debugf(logmsg+" %s %s %s", m.Credentials.Team, m.Credentials.Login, m.Credentials.Server)
|
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 ", model.SESSION_COOKIE_TOKEN)
|
||||||
|
token := strings.Split(m.Credentials.Pass, model.SESSION_COOKIE_TOKEN+"=")
|
||||||
|
m.Client.HttpClient.Jar = m.createCookieJar(token[1])
|
||||||
|
m.Client.MockSession(token[1])
|
||||||
|
myinfo, appErr = m.Client.GetMe("")
|
||||||
|
if myinfo.Data.(*model.User) == nil {
|
||||||
|
m.log.Errorf("LOGIN TOKEN: %s is invalid", m.Credentials.Pass)
|
||||||
|
return errors.New("invalid " + model.SESSION_COOKIE_TOKEN)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
myinfo, appErr = m.Client.Login(m.Credentials.Login, m.Credentials.Pass)
|
myinfo, appErr = m.Client.Login(m.Credentials.Login, m.Credentials.Pass)
|
||||||
|
}
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
d := b.Duration()
|
d := b.Duration()
|
||||||
m.log.Debug(appErr.DetailedError)
|
m.log.Debug(appErr.DetailedError)
|
||||||
|
@ -89,7 +111,7 @@ func (m *MMClient) Login() error {
|
||||||
}
|
}
|
||||||
return errors.New(appErr.Message)
|
return errors.New(appErr.Message)
|
||||||
}
|
}
|
||||||
m.log.Debug("LOGIN: %s, reconnecting in %s", appErr, d)
|
m.log.Debugf("LOGIN: %s, reconnecting in %s", appErr, d)
|
||||||
time.Sleep(d)
|
time.Sleep(d)
|
||||||
logmsg = "retrying login"
|
logmsg = "retrying login"
|
||||||
continue
|
continue
|
||||||
|
@ -98,15 +120,16 @@ func (m *MMClient) Login() error {
|
||||||
}
|
}
|
||||||
// reset timer
|
// reset timer
|
||||||
b.Reset()
|
b.Reset()
|
||||||
m.User = myinfo.Data.(*model.User)
|
|
||||||
|
|
||||||
teamdata, _ := m.Client.GetAllTeamListings()
|
initLoad, _ := m.Client.GetInitialLoad()
|
||||||
teams := teamdata.Data.(map[string]*model.Team)
|
initData := initLoad.Data.(*model.InitialLoad)
|
||||||
for k, v := range teams {
|
m.User = initData.User
|
||||||
|
for _, v := range initData.Teams {
|
||||||
|
m.log.Debugf("trying %s (id: %s)", v.Name, v.Id)
|
||||||
if v.Name == m.Credentials.Team {
|
if v.Name == m.Credentials.Team {
|
||||||
m.Client.SetTeamId(k)
|
m.Client.SetTeamId(v.Id)
|
||||||
m.Team = v
|
m.Team = v
|
||||||
m.log.Debug("GetallTeamListings: found id ", k)
|
m.log.Debugf("GetallTeamListings: found id %s for team %s", v.Id, v.Name)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,13 +142,14 @@ func (m *MMClient) Login() error {
|
||||||
header := http.Header{}
|
header := http.Header{}
|
||||||
header.Set(model.HEADER_AUTH, "BEARER "+m.Client.AuthToken)
|
header.Set(model.HEADER_AUTH, "BEARER "+m.Client.AuthToken)
|
||||||
|
|
||||||
var WsClient *websocket.Conn
|
m.log.Debug("WsClient: making connection")
|
||||||
var err error
|
var err error
|
||||||
for {
|
for {
|
||||||
WsClient, _, err = websocket.DefaultDialer.Dial(wsurl, header)
|
wsDialer := &websocket.Dialer{Proxy: http.ProxyFromEnvironment, TLSClientConfig: &tls.Config{InsecureSkipVerify: m.SkipTLSVerify}}
|
||||||
|
m.WsClient, _, err = wsDialer.Dial(wsurl, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d := b.Duration()
|
d := b.Duration()
|
||||||
log.Printf("WSS: %s, reconnecting in %s", err, d)
|
m.log.Debugf("WSS: %s, reconnecting in %s", err, d)
|
||||||
time.Sleep(d)
|
time.Sleep(d)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -133,8 +157,6 @@ func (m *MMClient) Login() error {
|
||||||
}
|
}
|
||||||
b.Reset()
|
b.Reset()
|
||||||
|
|
||||||
m.WsClient = WsClient
|
|
||||||
|
|
||||||
// populating users
|
// populating users
|
||||||
m.UpdateUsers()
|
m.UpdateUsers()
|
||||||
|
|
||||||
|
@ -147,12 +169,19 @@ func (m *MMClient) Login() error {
|
||||||
func (m *MMClient) WsReceiver() {
|
func (m *MMClient) WsReceiver() {
|
||||||
var rmsg model.Message
|
var rmsg model.Message
|
||||||
for {
|
for {
|
||||||
|
if m.WsQuit {
|
||||||
|
m.log.Debug("exiting WsReceiver")
|
||||||
|
return
|
||||||
|
}
|
||||||
if err := m.WsClient.ReadJSON(&rmsg); err != nil {
|
if err := m.WsClient.ReadJSON(&rmsg); err != nil {
|
||||||
log.Println("error:", err)
|
m.log.Error("error:", err)
|
||||||
// reconnect
|
// reconnect
|
||||||
m.Login()
|
m.Login()
|
||||||
}
|
}
|
||||||
//log.Printf("WsReceiver: %#v", rmsg)
|
if rmsg.Action == "ping" {
|
||||||
|
m.handleWsPing()
|
||||||
|
continue
|
||||||
|
}
|
||||||
msg := &Message{Raw: &rmsg, Team: m.Credentials.Team}
|
msg := &Message{Raw: &rmsg, Team: m.Credentials.Team}
|
||||||
m.parseMessage(msg)
|
m.parseMessage(msg)
|
||||||
m.MessageChan <- msg
|
m.MessageChan <- msg
|
||||||
|
@ -160,6 +189,14 @@ func (m *MMClient) WsReceiver() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MMClient) handleWsPing() {
|
||||||
|
m.log.Debug("Ws PING")
|
||||||
|
if !m.WsQuit && !m.WsAway {
|
||||||
|
m.log.Debug("Ws PONG")
|
||||||
|
m.WsClient.WriteMessage(websocket.PongMessage, []byte{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MMClient) parseMessage(rmsg *Message) {
|
func (m *MMClient) parseMessage(rmsg *Message) {
|
||||||
switch rmsg.Raw.Action {
|
switch rmsg.Raw.Action {
|
||||||
case model.ACTION_POSTED:
|
case model.ACTION_POSTED:
|
||||||
|
@ -198,7 +235,7 @@ func (m *MMClient) parseActionPost(rmsg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MMClient) UpdateUsers() error {
|
func (m *MMClient) UpdateUsers() error {
|
||||||
mmusers, _ := m.Client.GetProfiles(m.Client.GetTeamId(), "")
|
mmusers, _ := m.Client.GetProfilesForDirectMessageList(m.Team.Id)
|
||||||
m.Users = mmusers.Data.(map[string]*model.User)
|
m.Users = mmusers.Data.(map[string]*model.User)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -294,29 +331,49 @@ func (m *MMClient) GetPosts(channelId string, limit int) *model.PostList {
|
||||||
return res.Data.(*model.PostList)
|
return res.Data.(*model.PostList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MMClient) GetPublicLink(filename string) string {
|
||||||
|
res, err := m.Client.GetPublicLink(filename)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return res.Data.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MMClient) GetPublicLinks(filenames []string) []string {
|
||||||
|
var output []string
|
||||||
|
for _, f := range filenames {
|
||||||
|
res, err := m.Client.GetPublicLink(f)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
output = append(output, res.Data.(string))
|
||||||
|
}
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MMClient) UpdateChannelHeader(channelId string, header string) {
|
func (m *MMClient) UpdateChannelHeader(channelId string, header string) {
|
||||||
data := make(map[string]string)
|
data := make(map[string]string)
|
||||||
data["channel_id"] = channelId
|
data["channel_id"] = channelId
|
||||||
data["channel_header"] = header
|
data["channel_header"] = header
|
||||||
log.Printf("updating channelheader %#v, %#v", channelId, header)
|
m.log.Debugf("updating channelheader %#v, %#v", channelId, header)
|
||||||
_, err := m.Client.UpdateChannelHeader(data)
|
_, err := m.Client.UpdateChannelHeader(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MMClient) UpdateLastViewed(channelId string) {
|
func (m *MMClient) UpdateLastViewed(channelId string) {
|
||||||
log.Printf("posting lastview %#v", channelId)
|
m.log.Debugf("posting lastview %#v", channelId)
|
||||||
_, err := m.Client.UpdateLastViewedAt(channelId)
|
_, err := m.Client.UpdateLastViewedAt(channelId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Print(err)
|
m.log.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MMClient) UsernamesInChannel(channelName string) []string {
|
func (m *MMClient) UsernamesInChannel(channelName string) []string {
|
||||||
ceiRes, err := m.Client.GetChannelExtraInfo(m.GetChannelId(channelName), 5000, "")
|
ceiRes, err := m.Client.GetChannelExtraInfo(m.GetChannelId(channelName), 5000, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("UsernamesInChannel(%s) failed: %s", channelName, err)
|
m.log.Errorf("UsernamesInChannel(%s) failed: %s", channelName, err)
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
extra := ceiRes.Data.(*model.ChannelExtra)
|
extra := ceiRes.Data.(*model.ChannelExtra)
|
||||||
|
@ -326,3 +383,59 @@ func (m *MMClient) UsernamesInChannel(channelName string) []string {
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *MMClient) createCookieJar(token string) *cookiejar.Jar {
|
||||||
|
var cookies []*http.Cookie
|
||||||
|
jar, _ := cookiejar.New(nil)
|
||||||
|
firstCookie := &http.Cookie{
|
||||||
|
Name: "MMAUTHTOKEN",
|
||||||
|
Value: token,
|
||||||
|
Path: "/",
|
||||||
|
Domain: m.Credentials.Server,
|
||||||
|
}
|
||||||
|
cookies = append(cookies, firstCookie)
|
||||||
|
cookieURL, _ := url.Parse("https://" + m.Credentials.Server)
|
||||||
|
jar.SetCookies(cookieURL, cookies)
|
||||||
|
return jar
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MMClient) GetOtherUserDM(channel string) *model.User {
|
||||||
|
m.UpdateUsers()
|
||||||
|
var rcvuser *model.User
|
||||||
|
if strings.Contains(channel, "__") {
|
||||||
|
rcvusers := strings.Split(channel, "__")
|
||||||
|
if rcvusers[0] != m.User.Id {
|
||||||
|
rcvuser = m.Users[rcvusers[0]]
|
||||||
|
} else {
|
||||||
|
rcvuser = m.Users[rcvusers[1]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rcvuser
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MMClient) SendDirectMessage(toUserId string, msg string) {
|
||||||
|
m.log.Debugf("SendDirectMessage to %s, msg %s", toUserId, msg)
|
||||||
|
var channel string
|
||||||
|
// We don't have a DM with this user yet.
|
||||||
|
if m.GetChannelId(toUserId+"__"+m.User.Id) == "" && m.GetChannelId(m.User.Id+"__"+toUserId) == "" {
|
||||||
|
// create DM channel
|
||||||
|
_, err := m.Client.CreateDirectChannel(toUserId)
|
||||||
|
if err != nil {
|
||||||
|
m.log.Debugf("SendDirectMessage to %#v failed: %s", toUserId, err)
|
||||||
|
}
|
||||||
|
// update our channels
|
||||||
|
mmchannels, _ := m.Client.GetChannels("")
|
||||||
|
m.Channels = mmchannels.Data.(*model.ChannelList)
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the channel name
|
||||||
|
if toUserId > m.User.Id {
|
||||||
|
channel = m.User.Id + "__" + toUserId
|
||||||
|
} else {
|
||||||
|
channel = toUserId + "__" + m.User.Id
|
||||||
|
}
|
||||||
|
// build & send the message
|
||||||
|
msg = strings.Replace(msg, "\r", "", -1)
|
||||||
|
post := &model.Post{ChannelId: m.GetChannelId(channel), Message: msg}
|
||||||
|
m.Client.CreatePost(post)
|
||||||
|
}
|
||||||
|
|
|
@ -1,202 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
|
@ -1,154 +0,0 @@
|
||||||
//Package matterhook provides interaction with mattermost incoming/outgoing webhooks
|
|
||||||
package matterhook
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"github.com/gorilla/schema"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// IMessage for mattermost outgoing webhook. (received from mattermost)
|
|
||||||
type IMessage struct {
|
|
||||||
Token string `schema:"token"`
|
|
||||||
TeamID string `schema:"team_id"`
|
|
||||||
TeamDomain string `schema:"team_domain"`
|
|
||||||
ChannelID string `schema:"channel_id"`
|
|
||||||
ServiceID string `schema:"service_id"`
|
|
||||||
ChannelName string `schema:"channel_name"`
|
|
||||||
Timestamp string `schema:"timestamp"`
|
|
||||||
UserID string `schema:"user_id"`
|
|
||||||
UserName string `schema:"user_name"`
|
|
||||||
Text string `schema:"text"`
|
|
||||||
TriggerWord string `schema:"trigger_word"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client for Mattermost.
|
|
||||||
type Client struct {
|
|
||||||
Url string // URL for incoming webhooks on mattermost.
|
|
||||||
In chan IMessage
|
|
||||||
Out chan OMessage
|
|
||||||
httpclient *http.Client
|
|
||||||
Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config for client.
|
|
||||||
type Config struct {
|
|
||||||
Port int // Port to listen on.
|
|
||||||
BindAddress string // Address to listen on
|
|
||||||
Token string // Only allow this token from Mattermost. (Allow everything when empty)
|
|
||||||
InsecureSkipVerify bool // disable certificate checking
|
|
||||||
DisableServer bool // Do not start server for outgoing webhooks from Mattermost.
|
|
||||||
}
|
|
||||||
|
|
||||||
// New Mattermost client.
|
|
||||||
func New(url string, config Config) *Client {
|
|
||||||
c := &Client{Url: url, In: make(chan IMessage), Out: make(chan OMessage), Config: config}
|
|
||||||
if c.Port == 0 {
|
|
||||||
c.Port = 9999
|
|
||||||
}
|
|
||||||
c.BindAddress += ":"
|
|
||||||
tr := &http.Transport{
|
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify},
|
|
||||||
}
|
|
||||||
c.httpclient = &http.Client{Transport: tr}
|
|
||||||
if !c.DisableServer {
|
|
||||||
go c.StartServer()
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartServer starts a webserver listening for incoming mattermost POSTS.
|
|
||||||
func (c *Client) StartServer() {
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
mux.Handle("/", c)
|
|
||||||
log.Printf("Listening on http://%v:%v...\n", c.BindAddress, c.Port)
|
|
||||||
if err := http.ListenAndServe((c.BindAddress + strconv.Itoa(c.Port)), mux); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServeHTTP implementation.
|
|
||||||
func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method != "POST" {
|
|
||||||
log.Println("invalid " + r.Method + " connection from " + r.RemoteAddr)
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
msg := IMessage{}
|
|
||||||
err := r.ParseForm()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer r.Body.Close()
|
|
||||||
decoder := schema.NewDecoder()
|
|
||||||
err = decoder.Decode(&msg, r.PostForm)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if msg.Token == "" {
|
|
||||||
log.Println("no token from " + r.RemoteAddr)
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if c.Token != "" {
|
|
||||||
if msg.Token != c.Token {
|
|
||||||
log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr)
|
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.In <- msg
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receive returns an incoming message from mattermost outgoing webhooks URL.
|
|
||||||
func (c *Client) Receive() IMessage {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case msg := <-c.In:
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send sends a msg to mattermost incoming webhooks URL.
|
|
||||||
func (c *Client) Send(msg OMessage) error {
|
|
||||||
buf, err := json.Marshal(msg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
resp, err := c.httpclient.Post(c.Url, "application/json", bytes.NewReader(buf))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
// Read entire body to completion to re-use keep-alive connections.
|
|
||||||
io.Copy(ioutil.Discard, resp.Body)
|
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -13,6 +13,8 @@ type LdapInterface interface {
|
||||||
CheckPassword(id string, password string) *model.AppError
|
CheckPassword(id string, password string) *model.AppError
|
||||||
SwitchToLdap(userId, ldapId, ldapPassword string) *model.AppError
|
SwitchToLdap(userId, ldapId, ldapPassword string) *model.AppError
|
||||||
ValidateFilter(filter string) *model.AppError
|
ValidateFilter(filter string) *model.AppError
|
||||||
|
Syncronize() *model.AppError
|
||||||
|
StartLdapSyncJob()
|
||||||
}
|
}
|
||||||
|
|
||||||
var theLdapInterface LdapInterface
|
var theLdapInterface LdapInterface
|
||||||
|
|
|
@ -28,6 +28,8 @@ const (
|
||||||
HEADER_AUTH = "Authorization"
|
HEADER_AUTH = "Authorization"
|
||||||
HEADER_REQUESTED_WITH = "X-Requested-With"
|
HEADER_REQUESTED_WITH = "X-Requested-With"
|
||||||
HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
|
HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
|
||||||
|
STATUS = "status"
|
||||||
|
STATUS_OK = "OK"
|
||||||
|
|
||||||
API_URL_SUFFIX_V1 = "/api/v1"
|
API_URL_SUFFIX_V1 = "/api/v1"
|
||||||
API_URL_SUFFIX_V3 = "/api/v3"
|
API_URL_SUFFIX_V3 = "/api/v3"
|
||||||
|
@ -47,12 +49,22 @@ type Client struct {
|
||||||
AuthToken string
|
AuthToken string
|
||||||
AuthType string
|
AuthType string
|
||||||
TeamId string
|
TeamId string
|
||||||
|
RequestId string
|
||||||
|
Etag string
|
||||||
|
ServerVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient constructs a new client with convienence methods for talking to
|
// NewClient constructs a new client with convienence methods for talking to
|
||||||
// the server.
|
// the server.
|
||||||
func NewClient(url string) *Client {
|
func NewClient(url string) *Client {
|
||||||
return &Client{url, url + API_URL_SUFFIX, &http.Client{}, "", "", ""}
|
return &Client{url, url + API_URL_SUFFIX, &http.Client{}, "", "", "", "", "", ""}
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeBody(r *http.Response) {
|
||||||
|
if r.Body != nil {
|
||||||
|
ioutil.ReadAll(r.Body)
|
||||||
|
r.Body.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) SetOAuthToken(token string) {
|
func (c *Client) SetOAuthToken(token string) {
|
||||||
|
@ -94,6 +106,10 @@ func (c *Client) GetChannelNameRoute(channelName string) string {
|
||||||
return fmt.Sprintf("/teams/%v/channels/name/%v", c.GetTeamId(), channelName)
|
return fmt.Sprintf("/teams/%v/channels/name/%v", c.GetTeamId(), channelName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetGeneralRoute() string {
|
||||||
|
return "/general"
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppError) {
|
func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppError) {
|
||||||
rq, _ := http.NewRequest("POST", c.Url+url, strings.NewReader(data))
|
rq, _ := http.NewRequest("POST", c.Url+url, strings.NewReader(data))
|
||||||
rq.Header.Set("Content-Type", contentType)
|
rq.Header.Set("Content-Type", contentType)
|
||||||
|
@ -101,6 +117,7 @@ func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppErro
|
||||||
if rp, err := c.HttpClient.Do(rq); err != nil {
|
if rp, err := c.HttpClient.Do(rq); err != nil {
|
||||||
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
|
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
|
||||||
} else if rp.StatusCode >= 300 {
|
} else if rp.StatusCode >= 300 {
|
||||||
|
defer closeBody(rp)
|
||||||
return nil, AppErrorFromJson(rp.Body)
|
return nil, AppErrorFromJson(rp.Body)
|
||||||
} else {
|
} else {
|
||||||
return rp, nil
|
return rp, nil
|
||||||
|
@ -117,6 +134,7 @@ func (c *Client) DoApiPost(url string, data string) (*http.Response, *AppError)
|
||||||
if rp, err := c.HttpClient.Do(rq); err != nil {
|
if rp, err := c.HttpClient.Do(rq); err != nil {
|
||||||
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
|
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
|
||||||
} else if rp.StatusCode >= 300 {
|
} else if rp.StatusCode >= 300 {
|
||||||
|
defer closeBody(rp)
|
||||||
return nil, AppErrorFromJson(rp.Body)
|
return nil, AppErrorFromJson(rp.Body)
|
||||||
} else {
|
} else {
|
||||||
return rp, nil
|
return rp, nil
|
||||||
|
@ -139,6 +157,7 @@ func (c *Client) DoApiGet(url string, data string, etag string) (*http.Response,
|
||||||
} else if rp.StatusCode == 304 {
|
} else if rp.StatusCode == 304 {
|
||||||
return rp, nil
|
return rp, nil
|
||||||
} else if rp.StatusCode >= 300 {
|
} else if rp.StatusCode >= 300 {
|
||||||
|
defer closeBody(rp)
|
||||||
return rp, AppErrorFromJson(rp.Body)
|
return rp, AppErrorFromJson(rp.Body)
|
||||||
} else {
|
} else {
|
||||||
return rp, nil
|
return rp, nil
|
||||||
|
@ -155,6 +174,7 @@ func getCookie(name string, resp *http.Response) *http.Cookie {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Must is a convenience function used for testing.
|
||||||
func (c *Client) Must(result *Result, err *AppError) *Result {
|
func (c *Client) Must(result *Result, err *AppError) *Result {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l4g.Close()
|
l4g.Close()
|
||||||
|
@ -165,6 +185,80 @@ func (c *Client) Must(result *Result, err *AppError) *Result {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckStatusOK is a convenience function for checking the return of Web Service
|
||||||
|
// call that return the a map of status=OK.
|
||||||
|
func (c *Client) CheckStatusOK(r *http.Response) bool {
|
||||||
|
m := MapFromJson(r.Body)
|
||||||
|
defer closeBody(r)
|
||||||
|
|
||||||
|
if m != nil && m[STATUS] == STATUS_OK {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) fillInExtraProperties(r *http.Response) {
|
||||||
|
c.RequestId = r.Header.Get(HEADER_REQUEST_ID)
|
||||||
|
c.Etag = r.Header.Get(HEADER_ETAG_SERVER)
|
||||||
|
c.ServerVersion = r.Header.Get(HEADER_VERSION_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) clearExtraProperties() {
|
||||||
|
c.RequestId = ""
|
||||||
|
c.Etag = ""
|
||||||
|
c.ServerVersion = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// General Routes Section
|
||||||
|
|
||||||
|
// GetClientProperties returns properties needed by the client to show/hide
|
||||||
|
// certian features. It returns a map of strings.
|
||||||
|
func (c *Client) GetClientProperties() (map[string]string, *AppError) {
|
||||||
|
c.clearExtraProperties()
|
||||||
|
if r, err := c.DoApiGet(c.GetGeneralRoute()+"/client_props", "", ""); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
|
c.fillInExtraProperties(r)
|
||||||
|
return MapFromJson(r.Body), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogClient is a convenience Web Service call so clients can log messages into
|
||||||
|
// the server-side logs. For example we typically log javascript error messages
|
||||||
|
// into the server-side. It returns true if the logging was successful.
|
||||||
|
func (c *Client) LogClient(message string) (bool, *AppError) {
|
||||||
|
c.clearExtraProperties()
|
||||||
|
m := make(map[string]string)
|
||||||
|
m["level"] = "ERROR"
|
||||||
|
m["message"] = message
|
||||||
|
|
||||||
|
if r, err := c.DoApiPost(c.GetGeneralRoute()+"/log_client", MapToJson(m)); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
|
c.fillInExtraProperties(r)
|
||||||
|
return c.CheckStatusOK(r), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPing returns a map of strings with server time, server version, and node Id.
|
||||||
|
// Systems that want to check on health status of the server should check the
|
||||||
|
// url /api/v3/ping for a 200 status response.
|
||||||
|
func (c *Client) GetPing() (map[string]string, *AppError) {
|
||||||
|
c.clearExtraProperties()
|
||||||
|
if r, err := c.DoApiGet(c.GetGeneralRoute()+"/ping", "", ""); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
|
c.fillInExtraProperties(r)
|
||||||
|
return MapFromJson(r.Body), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Team Routes Section
|
||||||
|
|
||||||
func (c *Client) SignupTeam(email string, displayName string) (*Result, *AppError) {
|
func (c *Client) SignupTeam(email string, displayName string) (*Result, *AppError) {
|
||||||
m := make(map[string]string)
|
m := make(map[string]string)
|
||||||
m["email"] = email
|
m["email"] = email
|
||||||
|
@ -172,6 +266,7 @@ func (c *Client) SignupTeam(email string, displayName string) (*Result, *AppErro
|
||||||
if r, err := c.DoApiPost("/teams/signup", MapToJson(m)); err != nil {
|
if r, err := c.DoApiPost("/teams/signup", MapToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -181,6 +276,7 @@ func (c *Client) CreateTeamFromSignup(teamSignup *TeamSignup) (*Result, *AppErro
|
||||||
if r, err := c.DoApiPost("/teams/create_from_signup", teamSignup.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/teams/create_from_signup", teamSignup.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), TeamSignupFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), TeamSignupFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -190,6 +286,7 @@ func (c *Client) CreateTeam(team *Team) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/teams/create", team.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/teams/create", team.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -199,7 +296,7 @@ func (c *Client) GetAllTeams() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/teams/all", "", ""); err != nil {
|
if r, err := c.DoApiGet("/teams/all", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), TeamMapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), TeamMapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -209,7 +306,7 @@ func (c *Client) GetAllTeamListings() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/teams/all_team_listings", "", ""); err != nil {
|
if r, err := c.DoApiGet("/teams/all_team_listings", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), TeamMapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), TeamMapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -225,7 +322,7 @@ func (c *Client) FindTeamByName(name string) (*Result, *AppError) {
|
||||||
if body, _ := ioutil.ReadAll(r.Body); string(body) == "true" {
|
if body, _ := ioutil.ReadAll(r.Body); string(body) == "true" {
|
||||||
val = true
|
val = true
|
||||||
}
|
}
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), val}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), val}, nil
|
||||||
}
|
}
|
||||||
|
@ -237,6 +334,7 @@ func (c *Client) AddUserToTeam(userId string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/add_user_to_team", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/add_user_to_team", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -250,6 +348,7 @@ func (c *Client) AddUserToTeamFromInvite(hash, dataToHash, inviteId string) (*Re
|
||||||
if r, err := c.DoApiPost("/teams/add_user_to_team_from_invite", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/teams/add_user_to_team_from_invite", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -259,6 +358,7 @@ func (c *Client) InviteMembers(invites *Invites) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/invite_members", invites.ToJson()); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/invite_members", invites.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), InvitesFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), InvitesFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -268,6 +368,7 @@ func (c *Client) UpdateTeam(team *Team) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/update", team.ToJson()); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/update", team.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -277,6 +378,7 @@ func (c *Client) CreateUser(user *User, hash string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/create", user.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/users/create", user.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -289,6 +391,7 @@ func (c *Client) CreateUserWithInvite(user *User, hash string, data string, invi
|
||||||
if r, err := c.DoApiPost(url, user.ToJson()); err != nil {
|
if r, err := c.DoApiPost(url, user.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -298,6 +401,7 @@ func (c *Client) CreateUserFromSignup(user *User, data string, hash string) (*Re
|
||||||
if r, err := c.DoApiPost("/users/create?d="+url.QueryEscape(data)+"&h="+hash, user.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/users/create?d="+url.QueryEscape(data)+"&h="+hash, user.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -307,6 +411,7 @@ func (c *Client) GetUser(id string, etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/"+id+"/get", "", etag); err != nil {
|
if r, err := c.DoApiGet("/users/"+id+"/get", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -316,6 +421,7 @@ func (c *Client) GetMe(etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/me", "", etag); err != nil {
|
if r, err := c.DoApiGet("/users/me", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -325,6 +431,7 @@ func (c *Client) GetProfilesForDirectMessageList(teamId string) (*Result, *AppEr
|
||||||
if r, err := c.DoApiGet("/users/profiles_for_dm_list/"+teamId, "", ""); err != nil {
|
if r, err := c.DoApiGet("/users/profiles_for_dm_list/"+teamId, "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -334,6 +441,7 @@ func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/profiles/"+teamId, "", etag); err != nil {
|
if r, err := c.DoApiGet("/users/profiles/"+teamId, "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -343,6 +451,7 @@ func (c *Client) GetDirectProfiles(etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/direct_profiles", "", etag); err != nil {
|
if r, err := c.DoApiGet("/users/direct_profiles", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -390,6 +499,7 @@ func (c *Client) login(m map[string]string) (*Result, *AppError) {
|
||||||
NewLocAppError("/users/login", "model.client.login.app_error", nil, "")
|
NewLocAppError("/users/login", "model.client.login.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -403,6 +513,7 @@ func (c *Client) Logout() (*Result, *AppError) {
|
||||||
c.AuthType = HEADER_BEARER
|
c.AuthType = HEADER_BEARER
|
||||||
c.TeamId = ""
|
c.TeamId = ""
|
||||||
|
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -415,6 +526,7 @@ func (c *Client) CheckMfa(loginId string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/mfa", MapToJson(m)); err != nil {
|
if r, err := c.DoApiPost("/users/mfa", MapToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -424,6 +536,7 @@ func (c *Client) GenerateMfaQrCode() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/generate_mfa_qr", "", ""); err != nil {
|
if r, err := c.DoApiGet("/users/generate_mfa_qr", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), r.Body}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), r.Body}, nil
|
||||||
}
|
}
|
||||||
|
@ -437,6 +550,7 @@ func (c *Client) UpdateMfa(activate bool, token string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/update_mfa", StringInterfaceToJson(m)); err != nil {
|
if r, err := c.DoApiPost("/users/update_mfa", StringInterfaceToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -449,6 +563,7 @@ func (c *Client) AdminResetMfa(userId string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/admin/reset_mfa", MapToJson(m)); err != nil {
|
if r, err := c.DoApiPost("/admin/reset_mfa", MapToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -461,6 +576,7 @@ func (c *Client) RevokeSession(sessionAltId string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/revoke_session", MapToJson(m)); err != nil {
|
if r, err := c.DoApiPost("/users/revoke_session", MapToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -470,6 +586,7 @@ func (c *Client) GetSessions(id string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/"+id+"/sessions", "", ""); err != nil {
|
if r, err := c.DoApiGet("/users/"+id+"/sessions", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), SessionsFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), SessionsFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -479,6 +596,7 @@ func (c *Client) EmailToOAuth(m map[string]string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/claim/email_to_sso", MapToJson(m)); err != nil {
|
if r, err := c.DoApiPost("/users/claim/email_to_sso", MapToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -488,6 +606,7 @@ func (c *Client) OAuthToEmail(m map[string]string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/claim/oauth_to_email", MapToJson(m)); err != nil {
|
if r, err := c.DoApiPost("/users/claim/oauth_to_email", MapToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -497,6 +616,7 @@ func (c *Client) LDAPToEmail(m map[string]string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/claim/ldap_to_email", MapToJson(m)); err != nil {
|
if r, err := c.DoApiPost("/users/claim/ldap_to_email", MapToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -506,6 +626,7 @@ func (c *Client) EmailToLDAP(m map[string]string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/claim/ldap_to_email", MapToJson(m)); err != nil {
|
if r, err := c.DoApiPost("/users/claim/ldap_to_email", MapToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -519,6 +640,7 @@ func (c *Client) Command(channelId string, command string, suggest bool) (*Resul
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/execute", MapToJson(m)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/execute", MapToJson(m)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), CommandResponseFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), CommandResponseFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -528,6 +650,7 @@ func (c *Client) ListCommands() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list", "", ""); err != nil {
|
if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -537,6 +660,7 @@ func (c *Client) ListTeamCommands() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list_team_commands", "", ""); err != nil {
|
if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list_team_commands", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -546,6 +670,7 @@ func (c *Client) CreateCommand(cmd *Command) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/create", cmd.ToJson()); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/create", cmd.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -555,6 +680,7 @@ func (c *Client) RegenCommandToken(data map[string]string) (*Result, *AppError)
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/regen_token", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/regen_token", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -564,6 +690,7 @@ func (c *Client) DeleteCommand(data map[string]string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/delete", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/delete", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -573,6 +700,7 @@ func (c *Client) GetAudits(id string, etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/"+id+"/audits", "", etag); err != nil {
|
if r, err := c.DoApiGet("/users/"+id+"/audits", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), AuditsFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), AuditsFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -582,6 +710,7 @@ func (c *Client) GetLogs() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/admin/logs", "", ""); err != nil {
|
if r, err := c.DoApiGet("/admin/logs", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ArrayFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ArrayFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -591,42 +720,64 @@ func (c *Client) GetAllAudits() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/admin/audits", "", ""); err != nil {
|
if r, err := c.DoApiGet("/admin/audits", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), AuditsFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), AuditsFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetClientProperties() (*Result, *AppError) {
|
|
||||||
if r, err := c.DoApiGet("/admin/client_props", "", ""); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) GetConfig() (*Result, *AppError) {
|
func (c *Client) GetConfig() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/admin/config", "", ""); err != nil {
|
if r, err := c.DoApiGet("/admin/config", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ConfigFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ConfigFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReloadConfig will reload the config.json file from disk. Properties
|
||||||
|
// requiring a server restart will still need a server restart. You must
|
||||||
|
// have the system admin role to call this method. It will return status=OK
|
||||||
|
// if it's successfully reloaded the config file, otherwise check the returned error.
|
||||||
|
func (c *Client) ReloadConfig() (bool, *AppError) {
|
||||||
|
c.clearExtraProperties()
|
||||||
|
if r, err := c.DoApiGet("/admin/reload_config", "", ""); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else {
|
||||||
|
c.fillInExtraProperties(r)
|
||||||
|
return c.CheckStatusOK(r), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) SaveConfig(config *Config) (*Result, *AppError) {
|
func (c *Client) SaveConfig(config *Config) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/admin/save_config", config.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/admin/save_config", config.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RecycleDatabaseConnection will attempt to recycle the database connections.
|
||||||
|
// You must have the system admin role to call this method. It will return status=OK
|
||||||
|
// if it's successfully recycled the connections, otherwise check the returned error.
|
||||||
|
func (c *Client) RecycleDatabaseConnection() (bool, *AppError) {
|
||||||
|
c.clearExtraProperties()
|
||||||
|
if r, err := c.DoApiGet("/admin/recycle_db_conn", "", ""); err != nil {
|
||||||
|
return false, err
|
||||||
|
} else {
|
||||||
|
c.fillInExtraProperties(r)
|
||||||
|
return c.CheckStatusOK(r), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) TestEmail(config *Config) (*Result, *AppError) {
|
func (c *Client) TestEmail(config *Config) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/admin/test_email", config.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/admin/test_email", config.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -636,6 +787,7 @@ func (c *Client) GetComplianceReports() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/admin/compliance_reports", "", ""); err != nil {
|
if r, err := c.DoApiGet("/admin/compliance_reports", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), CompliancesFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), CompliancesFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -645,6 +797,7 @@ func (c *Client) SaveComplianceReport(job *Compliance) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/admin/save_compliance_report", job.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/admin/save_compliance_report", job.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ComplianceFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ComplianceFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -661,8 +814,10 @@ func (c *Client) DownloadComplianceReport(id string) (*Result, *AppError) {
|
||||||
if rp, err := c.HttpClient.Do(rq); err != nil {
|
if rp, err := c.HttpClient.Do(rq); err != nil {
|
||||||
return nil, NewLocAppError("/admin/download_compliance_report", "model.client.connecting.app_error", nil, err.Error())
|
return nil, NewLocAppError("/admin/download_compliance_report", "model.client.connecting.app_error", nil, err.Error())
|
||||||
} else if rp.StatusCode >= 300 {
|
} else if rp.StatusCode >= 300 {
|
||||||
|
defer rp.Body.Close()
|
||||||
return nil, AppErrorFromJson(rp.Body)
|
return nil, AppErrorFromJson(rp.Body)
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(rp)
|
||||||
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
||||||
rp.Header.Get(HEADER_ETAG_SERVER), rp.Body}, nil
|
rp.Header.Get(HEADER_ETAG_SERVER), rp.Body}, nil
|
||||||
}
|
}
|
||||||
|
@ -672,6 +827,7 @@ func (c *Client) GetTeamAnalytics(teamId, name string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/admin/analytics/"+teamId+"/"+name, "", ""); err != nil {
|
if r, err := c.DoApiGet("/admin/analytics/"+teamId+"/"+name, "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), AnalyticsRowsFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), AnalyticsRowsFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -681,6 +837,7 @@ func (c *Client) GetSystemAnalytics(name string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/admin/analytics/"+name, "", ""); err != nil {
|
if r, err := c.DoApiGet("/admin/analytics/"+name, "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), AnalyticsRowsFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), AnalyticsRowsFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -690,6 +847,7 @@ func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create", channel.ToJson()); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create", channel.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -701,6 +859,7 @@ func (c *Client) CreateDirectChannel(userId string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create_direct", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create_direct", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -710,6 +869,7 @@ func (c *Client) UpdateChannel(channel *Channel) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update", channel.ToJson()); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update", channel.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -719,6 +879,7 @@ func (c *Client) UpdateChannelHeader(data map[string]string) (*Result, *AppError
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_header", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_header", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -728,6 +889,7 @@ func (c *Client) UpdateChannelPurpose(data map[string]string) (*Result, *AppErro
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_purpose", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_purpose", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -737,6 +899,7 @@ func (c *Client) UpdateNotifyProps(data map[string]string) (*Result, *AppError)
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_notify_props", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_notify_props", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -746,6 +909,7 @@ func (c *Client) GetChannels(etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/", "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -755,6 +919,7 @@ func (c *Client) GetChannel(id, etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/", "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelDataFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelDataFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -764,6 +929,7 @@ func (c *Client) GetMoreChannels(etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/more", "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/more", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -773,6 +939,7 @@ func (c *Client) GetChannelCounts(etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/counts", "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/counts", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelCountsFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelCountsFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -849,6 +1016,7 @@ func (c *Client) GetChannelExtraInfo(id string, memberLimit int, etag string) (*
|
||||||
if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/extra_info/"+strconv.FormatInt(int64(memberLimit), 10), "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/extra_info/"+strconv.FormatInt(int64(memberLimit), 10), "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelExtraFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), ChannelExtraFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -858,6 +1026,7 @@ func (c *Client) CreatePost(post *Post) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/create", post.ToJson()); err != nil {
|
if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/create", post.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -867,6 +1036,7 @@ func (c *Client) UpdatePost(post *Post) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/update", post.ToJson()); err != nil {
|
if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/update", post.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -876,6 +1046,7 @@ func (c *Client) GetPosts(channelId string, offset int, limit int, etag string)
|
||||||
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/page/%v/%v", offset, limit), "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/page/%v/%v", offset, limit), "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -885,6 +1056,7 @@ func (c *Client) GetPostsSince(channelId string, time int64) (*Result, *AppError
|
||||||
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/since/%v", time), "", ""); err != nil {
|
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/since/%v", time), "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -894,6 +1066,7 @@ func (c *Client) GetPostsBefore(channelId string, postid string, offset int, lim
|
||||||
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/before/%v/%v", postid, offset, limit), "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/before/%v/%v", postid, offset, limit), "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -903,6 +1076,7 @@ func (c *Client) GetPostsAfter(channelId string, postid string, offset int, limi
|
||||||
if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/posts/%v/after/%v/%v", postid, offset, limit), "", etag); err != nil {
|
if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/posts/%v/after/%v/%v", postid, offset, limit), "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -912,6 +1086,7 @@ func (c *Client) GetPost(channelId string, postId string, etag string) (*Result,
|
||||||
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/get", postId), "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/get", postId), "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -921,6 +1096,7 @@ func (c *Client) DeletePost(channelId string, postId string) (*Result, *AppError
|
||||||
if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/delete", postId), ""); err != nil {
|
if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/delete", postId), ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -933,6 +1109,7 @@ func (c *Client) SearchPosts(terms string, isOrSearch bool) (*Result, *AppError)
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/posts/search", StringInterfaceToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/posts/search", StringInterfaceToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -959,6 +1136,7 @@ func (c *Client) uploadFile(url string, data []byte, contentType string) (*Resul
|
||||||
} else if rp.StatusCode >= 300 {
|
} else if rp.StatusCode >= 300 {
|
||||||
return nil, AppErrorFromJson(rp.Body)
|
return nil, AppErrorFromJson(rp.Body)
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(rp)
|
||||||
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
||||||
rp.Header.Get(HEADER_ETAG_SERVER), FileUploadResponseFromJson(rp.Body)}, nil
|
rp.Header.Get(HEADER_ETAG_SERVER), FileUploadResponseFromJson(rp.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -981,6 +1159,7 @@ func (c *Client) GetFile(url string, isFullUrl bool) (*Result, *AppError) {
|
||||||
} else if rp.StatusCode >= 300 {
|
} else if rp.StatusCode >= 300 {
|
||||||
return nil, AppErrorFromJson(rp.Body)
|
return nil, AppErrorFromJson(rp.Body)
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(rp)
|
||||||
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
||||||
rp.Header.Get(HEADER_ETAG_SERVER), rp.Body}, nil
|
rp.Header.Get(HEADER_ETAG_SERVER), rp.Body}, nil
|
||||||
}
|
}
|
||||||
|
@ -999,6 +1178,7 @@ func (c *Client) GetFileInfo(url string) (*Result, *AppError) {
|
||||||
} else if rp.StatusCode >= 300 {
|
} else if rp.StatusCode >= 300 {
|
||||||
return nil, AppErrorFromJson(rp.Body)
|
return nil, AppErrorFromJson(rp.Body)
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(rp)
|
||||||
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
||||||
rp.Header.Get(HEADER_ETAG_SERVER), FileInfoFromJson(rp.Body)}, nil
|
rp.Header.Get(HEADER_ETAG_SERVER), FileInfoFromJson(rp.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1008,6 +1188,7 @@ func (c *Client) GetPublicLink(filename string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/files/get_public_link", MapToJson(map[string]string{"filename": filename})); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/files/get_public_link", MapToJson(map[string]string{"filename": filename})); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), StringFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), StringFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1017,6 +1198,7 @@ func (c *Client) UpdateUser(user *User) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/update", user.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/users/update", user.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1026,6 +1208,7 @@ func (c *Client) UpdateUserRoles(data map[string]string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/update_roles", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/users/update_roles", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1037,6 +1220,7 @@ func (c *Client) AttachDeviceId(deviceId string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/attach_device", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/users/attach_device", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1049,6 +1233,7 @@ func (c *Client) UpdateActive(userId string, active bool) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/update_active", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/users/update_active", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1058,6 +1243,7 @@ func (c *Client) UpdateUserNotify(data map[string]string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/update_notify", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/users/update_notify", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1072,6 +1258,7 @@ func (c *Client) UpdateUserPassword(userId, currentPassword, newPassword string)
|
||||||
if r, err := c.DoApiPost("/users/newpassword", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/users/newpassword", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1083,6 +1270,7 @@ func (c *Client) SendPasswordReset(email string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/send_password_reset", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/users/send_password_reset", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1095,6 +1283,7 @@ func (c *Client) ResetPassword(code, newPassword string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/reset_password", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/users/reset_password", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1107,6 +1296,7 @@ func (c *Client) AdminResetPassword(userId, newPassword string) (*Result, *AppEr
|
||||||
if r, err := c.DoApiPost("/admin/reset_password", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/admin/reset_password", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1116,6 +1306,7 @@ func (c *Client) GetStatuses(data []string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/status", ArrayToJson(data)); err != nil {
|
if r, err := c.DoApiPost("/users/status", ArrayToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1125,6 +1316,7 @@ func (c *Client) GetMyTeam(etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetTeamRoute()+"/me", "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetTeamRoute()+"/me", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1134,6 +1326,7 @@ func (c *Client) GetTeamMembers(teamId string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/teams/members/"+teamId, "", ""); err != nil {
|
if r, err := c.DoApiGet("/teams/members/"+teamId, "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1143,6 +1336,7 @@ func (c *Client) RegisterApp(app *OAuthApp) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/oauth/register", app.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/oauth/register", app.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1152,6 +1346,7 @@ func (c *Client) AllowOAuth(rspType, clientId, redirect, scope, state string) (*
|
||||||
if r, err := c.DoApiGet("/oauth/allow?response_type="+rspType+"&client_id="+clientId+"&redirect_uri="+url.QueryEscape(redirect)+"&scope="+scope+"&state="+url.QueryEscape(state), "", ""); err != nil {
|
if r, err := c.DoApiGet("/oauth/allow?response_type="+rspType+"&client_id="+clientId+"&redirect_uri="+url.QueryEscape(redirect)+"&scope="+scope+"&state="+url.QueryEscape(state), "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1161,6 +1356,7 @@ func (c *Client) GetAccessToken(data url.Values) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/oauth/access_token", data.Encode()); err != nil {
|
if r, err := c.DoApiPost("/oauth/access_token", data.Encode()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), AccessResponseFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), AccessResponseFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1170,6 +1366,7 @@ func (c *Client) CreateIncomingWebhook(hook *IncomingWebhook) (*Result, *AppErro
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/create", hook.ToJson()); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/create", hook.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1190,6 +1387,7 @@ func (c *Client) DeleteIncomingWebhook(id string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/delete", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/delete", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1199,6 +1397,7 @@ func (c *Client) ListIncomingWebhooks() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/incoming/list", "", ""); err != nil {
|
if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/incoming/list", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1208,6 +1407,7 @@ func (c *Client) GetAllPreferences() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/preferences/", "", ""); err != nil {
|
if r, err := c.DoApiGet("/preferences/", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
preferences, _ := PreferencesFromJson(r.Body)
|
preferences, _ := PreferencesFromJson(r.Body)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
|
return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
|
||||||
}
|
}
|
||||||
|
@ -1226,6 +1426,7 @@ func (c *Client) GetPreference(category string, name string) (*Result, *AppError
|
||||||
if r, err := c.DoApiGet("/preferences/"+category+"/"+name, "", ""); err != nil {
|
if r, err := c.DoApiGet("/preferences/"+category+"/"+name, "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), PreferenceFromJson(r.Body)}, nil
|
return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), PreferenceFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1234,6 +1435,7 @@ func (c *Client) GetPreferenceCategory(category string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/preferences/"+category, "", ""); err != nil {
|
if r, err := c.DoApiGet("/preferences/"+category, "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
preferences, _ := PreferencesFromJson(r.Body)
|
preferences, _ := PreferencesFromJson(r.Body)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
|
return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
|
||||||
}
|
}
|
||||||
|
@ -1243,6 +1445,7 @@ func (c *Client) CreateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppErro
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/create", hook.ToJson()); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/create", hook.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1254,6 +1457,7 @@ func (c *Client) DeleteOutgoingWebhook(id string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/delete", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/delete", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1263,6 +1467,7 @@ func (c *Client) ListOutgoingWebhooks() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/outgoing/list", "", ""); err != nil {
|
if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/outgoing/list", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookListFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookListFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1274,6 +1479,7 @@ func (c *Client) RegenOutgoingWebhookToken(id string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/regen_token", MapToJson(data)); err != nil {
|
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/regen_token", MapToJson(data)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1288,6 +1494,7 @@ func (c *Client) GetClientLicenceConfig(etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/license/client_config", "", etag); err != nil {
|
if r, err := c.DoApiGet("/license/client_config", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
@ -1297,6 +1504,7 @@ func (c *Client) GetInitialLoad() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/initial_load", "", ""); err != nil {
|
if r, err := c.DoApiGet("/users/initial_load", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), InitialLoadFromJson(r.Body)}, nil
|
r.Header.Get(HEADER_ETAG_SERVER), InitialLoadFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,14 @@ package model
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
COMMAND_METHOD_POST = "P"
|
COMMAND_METHOD_POST = "P"
|
||||||
COMMAND_METHOD_GET = "G"
|
COMMAND_METHOD_GET = "G"
|
||||||
|
MIN_TRIGGER_LENGTH = 1
|
||||||
|
MAX_TRIGGER_LENGTH = 128
|
||||||
)
|
)
|
||||||
|
|
||||||
type Command struct {
|
type Command struct {
|
||||||
|
@ -99,7 +102,7 @@ func (o *Command) IsValid() *AppError {
|
||||||
return NewLocAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "")
|
return NewLocAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(o.Trigger) == 0 || len(o.Trigger) > 128 {
|
if len(o.Trigger) < MIN_TRIGGER_LENGTH || len(o.Trigger) > MAX_TRIGGER_LENGTH || strings.Index(o.Trigger, "/") == 0 || strings.Contains(o.Trigger, " ") {
|
||||||
return NewLocAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "")
|
return NewLocAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ package model
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -35,6 +36,15 @@ const (
|
||||||
FAKE_SETTING = "********************************"
|
FAKE_SETTING = "********************************"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// should match the values in webapp/i18n/i18n.jsx
|
||||||
|
var LOCALES = []string{
|
||||||
|
"en",
|
||||||
|
"es",
|
||||||
|
"fr",
|
||||||
|
"ja",
|
||||||
|
"pt-BR",
|
||||||
|
}
|
||||||
|
|
||||||
type ServiceSettings struct {
|
type ServiceSettings struct {
|
||||||
ListenAddress string
|
ListenAddress string
|
||||||
MaximumLoginAttempts int
|
MaximumLoginAttempts int
|
||||||
|
@ -92,6 +102,7 @@ type LogSettings struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileSettings struct {
|
type FileSettings struct {
|
||||||
|
MaxFileSize *int64
|
||||||
DriverName string
|
DriverName string
|
||||||
Directory string
|
Directory string
|
||||||
EnablePublicLink bool
|
EnablePublicLink bool
|
||||||
|
@ -189,6 +200,9 @@ type LdapSettings struct {
|
||||||
NicknameAttribute *string
|
NicknameAttribute *string
|
||||||
IdAttribute *string
|
IdAttribute *string
|
||||||
|
|
||||||
|
// Syncronization
|
||||||
|
SyncIntervalMinutes *int
|
||||||
|
|
||||||
// Advanced
|
// Advanced
|
||||||
SkipCertificateVerification *bool
|
SkipCertificateVerification *bool
|
||||||
QueryTimeout *int
|
QueryTimeout *int
|
||||||
|
@ -203,6 +217,12 @@ type ComplianceSettings struct {
|
||||||
EnableDaily *bool
|
EnableDaily *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LocalizationSettings struct {
|
||||||
|
DefaultServerLocale *string
|
||||||
|
DefaultClientLocale *string
|
||||||
|
AvailableLocales *string
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ServiceSettings ServiceSettings
|
ServiceSettings ServiceSettings
|
||||||
TeamSettings TeamSettings
|
TeamSettings TeamSettings
|
||||||
|
@ -217,6 +237,7 @@ type Config struct {
|
||||||
GoogleSettings SSOSettings
|
GoogleSettings SSOSettings
|
||||||
LdapSettings LdapSettings
|
LdapSettings LdapSettings
|
||||||
ComplianceSettings ComplianceSettings
|
ComplianceSettings ComplianceSettings
|
||||||
|
LocalizationSettings LocalizationSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Config) ToJson() string {
|
func (o *Config) ToJson() string {
|
||||||
|
@ -256,6 +277,11 @@ func (o *Config) SetDefaults() {
|
||||||
o.SqlSettings.AtRestEncryptKey = NewRandomString(32)
|
o.SqlSettings.AtRestEncryptKey = NewRandomString(32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.FileSettings.MaxFileSize == nil {
|
||||||
|
o.FileSettings.MaxFileSize = new(int64)
|
||||||
|
*o.FileSettings.MaxFileSize = 52428800 // 50 MB
|
||||||
|
}
|
||||||
|
|
||||||
if len(o.FileSettings.PublicLinkSalt) == 0 {
|
if len(o.FileSettings.PublicLinkSalt) == 0 {
|
||||||
o.FileSettings.PublicLinkSalt = NewRandomString(32)
|
o.FileSettings.PublicLinkSalt = NewRandomString(32)
|
||||||
}
|
}
|
||||||
|
@ -403,26 +429,86 @@ func (o *Config) SetDefaults() {
|
||||||
*o.SupportSettings.SupportEmail = "feedback@mattermost.com"
|
*o.SupportSettings.SupportEmail = "feedback@mattermost.com"
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.LdapPort == nil {
|
|
||||||
o.LdapSettings.LdapPort = new(int)
|
|
||||||
*o.LdapSettings.LdapPort = 389
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.LdapSettings.QueryTimeout == nil {
|
|
||||||
o.LdapSettings.QueryTimeout = new(int)
|
|
||||||
*o.LdapSettings.QueryTimeout = 60
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.LdapSettings.Enable == nil {
|
if o.LdapSettings.Enable == nil {
|
||||||
o.LdapSettings.Enable = new(bool)
|
o.LdapSettings.Enable = new(bool)
|
||||||
*o.LdapSettings.Enable = false
|
*o.LdapSettings.Enable = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.LdapServer == nil {
|
||||||
|
o.LdapSettings.LdapServer = new(string)
|
||||||
|
*o.LdapSettings.LdapServer = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.LdapPort == nil {
|
||||||
|
o.LdapSettings.LdapPort = new(int)
|
||||||
|
*o.LdapSettings.LdapPort = 389
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.ConnectionSecurity == nil {
|
||||||
|
o.LdapSettings.ConnectionSecurity = new(string)
|
||||||
|
*o.LdapSettings.ConnectionSecurity = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.BaseDN == nil {
|
||||||
|
o.LdapSettings.BaseDN = new(string)
|
||||||
|
*o.LdapSettings.BaseDN = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.BindUsername == nil {
|
||||||
|
o.LdapSettings.BindUsername = new(string)
|
||||||
|
*o.LdapSettings.BindUsername = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.BindPassword == nil {
|
||||||
|
o.LdapSettings.BindPassword = new(string)
|
||||||
|
*o.LdapSettings.BindPassword = ""
|
||||||
|
}
|
||||||
|
|
||||||
if o.LdapSettings.UserFilter == nil {
|
if o.LdapSettings.UserFilter == nil {
|
||||||
o.LdapSettings.UserFilter = new(string)
|
o.LdapSettings.UserFilter = new(string)
|
||||||
*o.LdapSettings.UserFilter = ""
|
*o.LdapSettings.UserFilter = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.FirstNameAttribute == nil {
|
||||||
|
o.LdapSettings.FirstNameAttribute = new(string)
|
||||||
|
*o.LdapSettings.FirstNameAttribute = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.LastNameAttribute == nil {
|
||||||
|
o.LdapSettings.LastNameAttribute = new(string)
|
||||||
|
*o.LdapSettings.LastNameAttribute = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.EmailAttribute == nil {
|
||||||
|
o.LdapSettings.EmailAttribute = new(string)
|
||||||
|
*o.LdapSettings.EmailAttribute = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.NicknameAttribute == nil {
|
||||||
|
o.LdapSettings.NicknameAttribute = new(string)
|
||||||
|
*o.LdapSettings.NicknameAttribute = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.IdAttribute == nil {
|
||||||
|
o.LdapSettings.IdAttribute = new(string)
|
||||||
|
*o.LdapSettings.IdAttribute = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.SyncIntervalMinutes == nil {
|
||||||
|
o.LdapSettings.SyncIntervalMinutes = new(int)
|
||||||
|
*o.LdapSettings.SyncIntervalMinutes = 60
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.SkipCertificateVerification == nil {
|
||||||
|
o.LdapSettings.SkipCertificateVerification = new(bool)
|
||||||
|
*o.LdapSettings.SkipCertificateVerification = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if o.LdapSettings.QueryTimeout == nil {
|
||||||
|
o.LdapSettings.QueryTimeout = new(int)
|
||||||
|
*o.LdapSettings.QueryTimeout = 60
|
||||||
|
}
|
||||||
|
|
||||||
if o.LdapSettings.LoginFieldName == nil {
|
if o.LdapSettings.LoginFieldName == nil {
|
||||||
o.LdapSettings.LoginFieldName = new(string)
|
o.LdapSettings.LoginFieldName = new(string)
|
||||||
*o.LdapSettings.LoginFieldName = ""
|
*o.LdapSettings.LoginFieldName = ""
|
||||||
|
@ -493,19 +579,19 @@ func (o *Config) SetDefaults() {
|
||||||
*o.ComplianceSettings.EnableDaily = false
|
*o.ComplianceSettings.EnableDaily = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.ConnectionSecurity == nil {
|
if o.LocalizationSettings.DefaultServerLocale == nil {
|
||||||
o.LdapSettings.ConnectionSecurity = new(string)
|
o.LocalizationSettings.DefaultServerLocale = new(string)
|
||||||
*o.LdapSettings.ConnectionSecurity = ""
|
*o.LocalizationSettings.DefaultServerLocale = DEFAULT_LOCALE
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.SkipCertificateVerification == nil {
|
if o.LocalizationSettings.DefaultClientLocale == nil {
|
||||||
o.LdapSettings.SkipCertificateVerification = new(bool)
|
o.LocalizationSettings.DefaultClientLocale = new(string)
|
||||||
*o.LdapSettings.SkipCertificateVerification = false
|
*o.LocalizationSettings.DefaultClientLocale = DEFAULT_LOCALE
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.LdapSettings.NicknameAttribute == nil {
|
if o.LocalizationSettings.AvailableLocales == nil {
|
||||||
o.LdapSettings.NicknameAttribute = new(string)
|
o.LocalizationSettings.AvailableLocales = new(string)
|
||||||
*o.LdapSettings.NicknameAttribute = ""
|
*o.LocalizationSettings.AvailableLocales = strings.Join(LOCALES, ",")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,6 +633,10 @@ func (o *Config) IsValid() *AppError {
|
||||||
return NewLocAppError("Config.IsValid", "model.config.is_valid.sql_max_conn.app_error", nil, "")
|
return NewLocAppError("Config.IsValid", "model.config.is_valid.sql_max_conn.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *o.FileSettings.MaxFileSize <= 0 {
|
||||||
|
return NewLocAppError("Config.IsValid", "model.config.is_valid.max_file_size.app_error", nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
if !(o.FileSettings.DriverName == IMAGE_DRIVER_LOCAL || o.FileSettings.DriverName == IMAGE_DRIVER_S3) {
|
if !(o.FileSettings.DriverName == IMAGE_DRIVER_LOCAL || o.FileSettings.DriverName == IMAGE_DRIVER_S3) {
|
||||||
return NewLocAppError("Config.IsValid", "model.config.is_valid.file_driver.app_error", nil, "")
|
return NewLocAppError("Config.IsValid", "model.config.is_valid.file_driver.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
@ -603,6 +693,10 @@ func (o *Config) IsValid() *AppError {
|
||||||
return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_security.app_error", nil, "")
|
return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_security.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *o.LdapSettings.SyncIntervalMinutes <= 0 {
|
||||||
|
return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_sync_interval.app_error", nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,7 +709,7 @@ func (o *Config) GetSanitizeOptions() map[string]bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Config) Sanitize() {
|
func (o *Config) Sanitize() {
|
||||||
if &o.LdapSettings != nil && len(*o.LdapSettings.BindPassword) > 0 {
|
if o.LdapSettings.BindPassword != nil && len(*o.LdapSettings.BindPassword) > 0 {
|
||||||
*o.LdapSettings.BindPassword = FAKE_SETTING
|
*o.LdapSettings.BindPassword = FAKE_SETTING
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
MAX_FILE_SIZE = 50000000 // 50 MB
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
IMAGE_EXTENSIONS = [5]string{".jpg", ".jpeg", ".gif", ".bmp", ".png"}
|
IMAGE_EXTENSIONS = [5]string{".jpg", ".jpeg", ".gif", ".bmp", ".png"}
|
||||||
IMAGE_MIME_TYPES = map[string]string{".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".bmp": "image/bmp", ".png": "image/png", ".tiff": "image/tiff"}
|
IMAGE_MIME_TYPES = map[string]string{".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".bmp": "image/bmp", ".png": "image/png", ".tiff": "image/tiff"}
|
||||||
|
|
|
@ -47,7 +47,8 @@ func userFromGitLabUser(glu *GitLabUser) *model.User {
|
||||||
}
|
}
|
||||||
strings.TrimSpace(user.Email)
|
strings.TrimSpace(user.Email)
|
||||||
user.Email = glu.Email
|
user.Email = glu.Email
|
||||||
*user.AuthData = strconv.FormatInt(glu.Id, 10)
|
userId := strconv.FormatInt(glu.Id, 10)
|
||||||
|
user.AuthData = &userId
|
||||||
user.AuthService = model.USER_AUTH_SERVICE_GITLAB
|
user.AuthService = model.USER_AUTH_SERVICE_GITLAB
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
|
@ -4,13 +4,15 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DEFAULT_WEBHOOK_USERNAME = "webhook"
|
DEFAULT_WEBHOOK_USERNAME = "webhook"
|
||||||
DEFAULT_WEBHOOK_ICON = "/static/images/webhook_icon.jpg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type IncomingWebhook struct {
|
type IncomingWebhook struct {
|
||||||
|
@ -125,13 +127,136 @@ func (o *IncomingWebhook) PreUpdate() {
|
||||||
o.UpdateAt = GetMillis()
|
o.UpdateAt = GetMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
func IncomingWebhookRequestFromJson(data io.Reader) *IncomingWebhookRequest {
|
// escapeControlCharsFromPayload escapes control chars (\n, \t) from a byte slice.
|
||||||
decoder := json.NewDecoder(data)
|
// Context:
|
||||||
|
// JSON strings are not supposed to contain control characters such as \n, \t,
|
||||||
|
// ... but some incoming webhooks might still send invalid JSON and we want to
|
||||||
|
// try to handle that. An example invalid JSON string from an incoming webhook
|
||||||
|
// might look like this (strings for both "text" and "fallback" attributes are
|
||||||
|
// invalid JSON strings because they contain unescaped newlines and tabs):
|
||||||
|
// `{
|
||||||
|
// "text": "this is a test
|
||||||
|
// that contains a newline and tabs",
|
||||||
|
// "attachments": [
|
||||||
|
// {
|
||||||
|
// "fallback": "Required plain-text summary of the attachment
|
||||||
|
// that contains a newline and tabs",
|
||||||
|
// "color": "#36a64f",
|
||||||
|
// ...
|
||||||
|
// "text": "Optional text that appears within the attachment
|
||||||
|
// that contains a newline and tabs",
|
||||||
|
// ...
|
||||||
|
// "thumb_url": "http://example.com/path/to/thumb.png"
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }`
|
||||||
|
// This function will search for `"key": "value"` pairs, and escape \n, \t
|
||||||
|
// from the value.
|
||||||
|
func escapeControlCharsFromPayload(by []byte) []byte {
|
||||||
|
// we'll search for `"text": "..."` or `"fallback": "..."`, ...
|
||||||
|
keys := "text|fallback|pretext|author_name|title|value"
|
||||||
|
|
||||||
|
// the regexp reads like this:
|
||||||
|
// (?s): this flag let . match \n (default is false)
|
||||||
|
// "(keys)": we search for the keys defined above
|
||||||
|
// \s*:\s*: followed by 0..n spaces/tabs, a colon then 0..n spaces/tabs
|
||||||
|
// ": a double-quote
|
||||||
|
// (\\"|[^"])*: any number of times the `\"` string or any char but a double-quote
|
||||||
|
// ": a double-quote
|
||||||
|
r := `(?s)"(` + keys + `)"\s*:\s*"(\\"|[^"])*"`
|
||||||
|
re := regexp.MustCompile(r)
|
||||||
|
|
||||||
|
// the function that will escape \n and \t on the regexp matches
|
||||||
|
repl := func(b []byte) []byte {
|
||||||
|
if bytes.Contains(b, []byte("\n")) {
|
||||||
|
b = bytes.Replace(b, []byte("\n"), []byte("\\n"), -1)
|
||||||
|
}
|
||||||
|
if bytes.Contains(b, []byte("\t")) {
|
||||||
|
b = bytes.Replace(b, []byte("\t"), []byte("\\t"), -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
return re.ReplaceAllFunc(by, repl)
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeIncomingWebhookRequest(by []byte) (*IncomingWebhookRequest, error) {
|
||||||
|
decoder := json.NewDecoder(bytes.NewReader(by))
|
||||||
var o IncomingWebhookRequest
|
var o IncomingWebhookRequest
|
||||||
err := decoder.Decode(&o)
|
err := decoder.Decode(&o)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return &o
|
return &o, nil
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
if i.Attachments != nil {
|
||||||
|
attachments := i.Attachments.([]interface{})
|
||||||
|
for _, attachment := range attachments {
|
||||||
|
a := attachment.(map[string]interface{})
|
||||||
|
|
||||||
|
if a["pretext"] != nil {
|
||||||
|
a["pretext"] = expandAnnouncement(a["pretext"].(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
if a["text"] != nil {
|
||||||
|
a["text"] = expandAnnouncement(a["text"].(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
if a["title"] != nil {
|
||||||
|
a["title"] = expandAnnouncement(a["title"].(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
if a["fields"] != nil {
|
||||||
|
fields := a["fields"].([]interface{})
|
||||||
|
for _, field := range fields {
|
||||||
|
f := field.(map[string]interface{})
|
||||||
|
if f["value"] != nil {
|
||||||
|
f["value"] = expandAnnouncement(f["value"].(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IncomingWebhookRequestFromJson(data io.Reader) *IncomingWebhookRequest {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
buf.ReadFrom(data)
|
||||||
|
by := buf.Bytes()
|
||||||
|
|
||||||
|
// Try to decode the JSON data. Only if it fails, try to escape control
|
||||||
|
// characters from the strings contained in the JSON data.
|
||||||
|
o, err := decodeIncomingWebhookRequest(by)
|
||||||
|
if err != nil {
|
||||||
|
o, err = decodeIncomingWebhookRequest(escapeControlCharsFromPayload(by))
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expandAnnouncements(o)
|
||||||
|
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TaskFunc func()
|
||||||
|
|
||||||
|
type ScheduledTask struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Interval time.Duration `json:"interval"`
|
||||||
|
Recurring bool `json:"recurring"`
|
||||||
|
function TaskFunc `json:",omitempty"`
|
||||||
|
timer *time.Timer `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
return tasks[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
taskRunner := func() {
|
||||||
|
go task.function()
|
||||||
|
removeTaskByName(task.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
taskRecurer := func() {
|
||||||
|
go task.function()
|
||||||
|
task.timer.Reset(task.Interval)
|
||||||
|
}
|
||||||
|
|
||||||
|
task.timer = time.AfterFunc(interval, taskRecurer)
|
||||||
|
|
||||||
|
addTask(task)
|
||||||
|
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
func (task *ScheduledTask) Cancel() {
|
||||||
|
task.timer.Stop()
|
||||||
|
removeTaskByName(task.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (task *ScheduledTask) String() string {
|
||||||
|
return fmt.Sprintf(
|
||||||
|
"%s\nInterval: %s\nRecurring: %t\n",
|
||||||
|
task.Name,
|
||||||
|
task.Interval.String(),
|
||||||
|
task.Recurring,
|
||||||
|
)
|
||||||
|
}
|
|
@ -7,6 +7,8 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OutgoingWebhook struct {
|
type OutgoingWebhook struct {
|
||||||
|
@ -22,6 +24,47 @@ type OutgoingWebhook struct {
|
||||||
CallbackURLs StringArray `json:"callback_urls"`
|
CallbackURLs StringArray `json:"callback_urls"`
|
||||||
DisplayName string `json:"display_name"`
|
DisplayName string `json:"display_name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
ContentType string `json:"content_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OutgoingWebhookPayload struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
TeamId string `json:"team_id"`
|
||||||
|
TeamDomain string `json:"team_domain"`
|
||||||
|
ChannelId string `json:"channel_id"`
|
||||||
|
ChannelName string `json:"channel_name"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
UserName string `json:"user_name"`
|
||||||
|
PostId string `json:"post_id"`
|
||||||
|
Text string `json:"text"`
|
||||||
|
TriggerWord string `json:"trigger_word"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OutgoingWebhookPayload) ToJSON() string {
|
||||||
|
b, err := json.Marshal(o)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
} else {
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OutgoingWebhookPayload) ToFormValues() string {
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("token", o.Token)
|
||||||
|
v.Set("team_id", o.TeamId)
|
||||||
|
v.Set("team_domain", o.TeamDomain)
|
||||||
|
v.Set("channel_id", o.ChannelId)
|
||||||
|
v.Set("channel_name", o.ChannelName)
|
||||||
|
v.Set("timestamp", strconv.FormatInt(o.Timestamp/1000, 10))
|
||||||
|
v.Set("user_id", o.UserId)
|
||||||
|
v.Set("user_name", o.UserName)
|
||||||
|
v.Set("post_id", o.PostId)
|
||||||
|
v.Set("text", o.Text)
|
||||||
|
v.Set("trigger_word", o.TriggerWord)
|
||||||
|
|
||||||
|
return v.Encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OutgoingWebhook) ToJson() string {
|
func (o *OutgoingWebhook) ToJson() string {
|
||||||
|
@ -124,6 +167,10 @@ func (o *OutgoingWebhook) IsValid() *AppError {
|
||||||
return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.description.app_error", nil, "")
|
return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.description.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(o.ContentType) > 128 {
|
||||||
|
return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,9 @@ const (
|
||||||
PREFERENCE_CATEGORY_TUTORIAL_STEPS = "tutorial_step"
|
PREFERENCE_CATEGORY_TUTORIAL_STEPS = "tutorial_step"
|
||||||
PREFERENCE_CATEGORY_ADVANCED_SETTINGS = "advanced_settings"
|
PREFERENCE_CATEGORY_ADVANCED_SETTINGS = "advanced_settings"
|
||||||
|
|
||||||
|
PREFERENCE_CATEGORY_DISPLAY_SETTINGS = "display_settings"
|
||||||
|
PREFERENCE_NAME_COLLAPSE_SETTING = "collapse_previews"
|
||||||
|
|
||||||
PREFERENCE_CATEGORY_LAST = "last"
|
PREFERENCE_CATEGORY_LAST = "last"
|
||||||
PREFERENCE_NAME_LAST_CHANNEL = "channel"
|
PREFERENCE_NAME_LAST_CHANNEL = "channel"
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,9 +4,13 @@
|
||||||
package model
|
package model
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var searchTermPuncStart = regexp.MustCompile(`^[^\pL\d\s#"]+`)
|
||||||
|
var searchTermPuncEnd = regexp.MustCompile(`[^\pL\d\s*"]+$`)
|
||||||
|
|
||||||
type SearchParams struct {
|
type SearchParams struct {
|
||||||
Terms string
|
Terms string
|
||||||
IsHashtag bool
|
IsHashtag bool
|
||||||
|
@ -91,8 +95,8 @@ func parseSearchFlags(input []string) ([]string, [][2]string) {
|
||||||
|
|
||||||
if !isFlag {
|
if !isFlag {
|
||||||
// trim off surrounding punctuation (note that we leave trailing asterisks to allow wildcards)
|
// trim off surrounding punctuation (note that we leave trailing asterisks to allow wildcards)
|
||||||
word = puncStart.ReplaceAllString(word, "")
|
word = searchTermPuncStart.ReplaceAllString(word, "")
|
||||||
word = puncEndWildcard.ReplaceAllString(word, "")
|
word = searchTermPuncEnd.ReplaceAllString(word, "")
|
||||||
|
|
||||||
// and remove extra pound #s
|
// and remove extra pound #s
|
||||||
word = hashtagStart.ReplaceAllString(word, "#")
|
word = hashtagStart.ReplaceAllString(word, "#")
|
||||||
|
|
|
@ -136,7 +136,6 @@ func (u *User) PreSave() {
|
||||||
|
|
||||||
u.Username = strings.ToLower(u.Username)
|
u.Username = strings.ToLower(u.Username)
|
||||||
u.Email = strings.ToLower(u.Email)
|
u.Email = strings.ToLower(u.Email)
|
||||||
u.Locale = strings.ToLower(u.Locale)
|
|
||||||
|
|
||||||
u.CreateAt = GetMillis()
|
u.CreateAt = GetMillis()
|
||||||
u.UpdateAt = u.CreateAt
|
u.UpdateAt = u.CreateAt
|
||||||
|
@ -166,7 +165,6 @@ func (u *User) PreSave() {
|
||||||
func (u *User) PreUpdate() {
|
func (u *User) PreUpdate() {
|
||||||
u.Username = strings.ToLower(u.Username)
|
u.Username = strings.ToLower(u.Username)
|
||||||
u.Email = strings.ToLower(u.Email)
|
u.Email = strings.ToLower(u.Email)
|
||||||
u.Locale = strings.ToLower(u.Locale)
|
|
||||||
u.UpdateAt = GetMillis()
|
u.UpdateAt = GetMillis()
|
||||||
|
|
||||||
if u.AuthData != nil && *u.AuthData == "" {
|
if u.AuthData != nil && *u.AuthData == "" {
|
||||||
|
@ -186,11 +184,27 @@ func (u *User) PreUpdate() {
|
||||||
}
|
}
|
||||||
u.NotifyProps["mention_keys"] = strings.Join(goodKeys, ",")
|
u.NotifyProps["mention_keys"] = strings.Join(goodKeys, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u.ThemeProps != nil {
|
||||||
|
colorPattern := regexp.MustCompile(`^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$`)
|
||||||
|
|
||||||
|
// blank out any invalid theme values
|
||||||
|
for name, value := range u.ThemeProps {
|
||||||
|
if name == "image" || name == "type" || name == "codeTheme" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !colorPattern.MatchString(value) {
|
||||||
|
u.ThemeProps[name] = "#ffffff"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) SetDefaultNotifications() {
|
func (u *User) SetDefaultNotifications() {
|
||||||
u.NotifyProps = make(map[string]string)
|
u.NotifyProps = make(map[string]string)
|
||||||
u.NotifyProps["email"] = "true"
|
u.NotifyProps["email"] = "true"
|
||||||
|
u.NotifyProps["push"] = USER_NOTIFY_MENTION
|
||||||
u.NotifyProps["desktop"] = USER_NOTIFY_ALL
|
u.NotifyProps["desktop"] = USER_NOTIFY_ALL
|
||||||
u.NotifyProps["desktop_sound"] = "true"
|
u.NotifyProps["desktop_sound"] = "true"
|
||||||
u.NotifyProps["mention_keys"] = u.Username + ",@" + u.Username
|
u.NotifyProps["mention_keys"] = u.Username + ",@" + u.Username
|
||||||
|
|
|
@ -315,10 +315,9 @@ func Etag(parts ...interface{}) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
var validHashtag = regexp.MustCompile(`^(#[A-Za-zäöüÄÖÜß]+[A-Za-z0-9äöüÄÖÜß_\-]*[A-Za-z0-9äöüÄÖÜß])$`)
|
var validHashtag = regexp.MustCompile(`^(#[A-Za-zäöüÄÖÜß]+[A-Za-z0-9äöüÄÖÜß_\-]*[A-Za-z0-9äöüÄÖÜß])$`)
|
||||||
var puncStart = regexp.MustCompile(`^[.,()&$!\?\[\]{}':;\\<>\-+=%^*|]+`)
|
var puncStart = regexp.MustCompile(`^[^\pL\d\s#]+`)
|
||||||
var hashtagStart = regexp.MustCompile(`^#{2,}`)
|
var hashtagStart = regexp.MustCompile(`^#{2,}`)
|
||||||
var puncEnd = regexp.MustCompile(`[.,()&$#!\?\[\]{}':;\\<>\-+=%^*|]+$`)
|
var puncEnd = regexp.MustCompile(`[^\pL\d\s]+$`)
|
||||||
var puncEndWildcard = regexp.MustCompile(`[.,()&$#!\?\[\]{}':;\\<>\-+=%^|]+$`)
|
|
||||||
|
|
||||||
func ParseHashtags(text string) (string, string) {
|
func ParseHashtags(text string) (string, string) {
|
||||||
words := strings.Fields(text)
|
words := strings.Fields(text)
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
// It should be maitained in chronological order with most current
|
// It should be maitained in chronological order with most current
|
||||||
// release at the front of the list.
|
// release at the front of the list.
|
||||||
var versions = []string{
|
var versions = []string{
|
||||||
|
"3.1.0",
|
||||||
"3.0.0",
|
"3.0.0",
|
||||||
"2.2.0",
|
"2.2.0",
|
||||||
"2.1.0",
|
"2.1.0",
|
||||||
|
@ -33,6 +34,7 @@ var CurrentVersion string = versions[0]
|
||||||
var BuildNumber string
|
var BuildNumber string
|
||||||
var BuildDate string
|
var BuildDate string
|
||||||
var BuildHash string
|
var BuildHash string
|
||||||
|
var BuildHashEnterprise string
|
||||||
var BuildEnterpriseReady string
|
var BuildEnterpriseReady string
|
||||||
var versionsWithoutHotFixes []string
|
var versionsWithoutHotFixes []string
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following disclaimer
|
||||||
|
in the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,312 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package httplex contains rules around lexical matters of various
|
||||||
|
// HTTP-related specifications.
|
||||||
|
//
|
||||||
|
// This package is shared by the standard library (which vendors it)
|
||||||
|
// and x/net/http2. It comes with no API stability promise.
|
||||||
|
package httplex
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
var isTokenTable = [127]bool{
|
||||||
|
'!': true,
|
||||||
|
'#': true,
|
||||||
|
'$': true,
|
||||||
|
'%': true,
|
||||||
|
'&': true,
|
||||||
|
'\'': true,
|
||||||
|
'*': true,
|
||||||
|
'+': true,
|
||||||
|
'-': true,
|
||||||
|
'.': true,
|
||||||
|
'0': true,
|
||||||
|
'1': true,
|
||||||
|
'2': true,
|
||||||
|
'3': true,
|
||||||
|
'4': true,
|
||||||
|
'5': true,
|
||||||
|
'6': true,
|
||||||
|
'7': true,
|
||||||
|
'8': true,
|
||||||
|
'9': true,
|
||||||
|
'A': true,
|
||||||
|
'B': true,
|
||||||
|
'C': true,
|
||||||
|
'D': true,
|
||||||
|
'E': true,
|
||||||
|
'F': true,
|
||||||
|
'G': true,
|
||||||
|
'H': true,
|
||||||
|
'I': true,
|
||||||
|
'J': true,
|
||||||
|
'K': true,
|
||||||
|
'L': true,
|
||||||
|
'M': true,
|
||||||
|
'N': true,
|
||||||
|
'O': true,
|
||||||
|
'P': true,
|
||||||
|
'Q': true,
|
||||||
|
'R': true,
|
||||||
|
'S': true,
|
||||||
|
'T': true,
|
||||||
|
'U': true,
|
||||||
|
'W': true,
|
||||||
|
'V': true,
|
||||||
|
'X': true,
|
||||||
|
'Y': true,
|
||||||
|
'Z': true,
|
||||||
|
'^': true,
|
||||||
|
'_': true,
|
||||||
|
'`': true,
|
||||||
|
'a': true,
|
||||||
|
'b': true,
|
||||||
|
'c': true,
|
||||||
|
'd': true,
|
||||||
|
'e': true,
|
||||||
|
'f': true,
|
||||||
|
'g': true,
|
||||||
|
'h': true,
|
||||||
|
'i': true,
|
||||||
|
'j': true,
|
||||||
|
'k': true,
|
||||||
|
'l': true,
|
||||||
|
'm': true,
|
||||||
|
'n': true,
|
||||||
|
'o': true,
|
||||||
|
'p': true,
|
||||||
|
'q': true,
|
||||||
|
'r': true,
|
||||||
|
's': true,
|
||||||
|
't': true,
|
||||||
|
'u': true,
|
||||||
|
'v': true,
|
||||||
|
'w': true,
|
||||||
|
'x': true,
|
||||||
|
'y': true,
|
||||||
|
'z': true,
|
||||||
|
'|': true,
|
||||||
|
'~': true,
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsTokenRune(r rune) bool {
|
||||||
|
i := int(r)
|
||||||
|
return i < len(isTokenTable) && isTokenTable[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNotToken(r rune) bool {
|
||||||
|
return !IsTokenRune(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeaderValuesContainsToken reports whether any string in values
|
||||||
|
// contains the provided token, ASCII case-insensitively.
|
||||||
|
func HeaderValuesContainsToken(values []string, token string) bool {
|
||||||
|
for _, v := range values {
|
||||||
|
if headerValueContainsToken(v, token) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isOWS reports whether b is an optional whitespace byte, as defined
|
||||||
|
// by RFC 7230 section 3.2.3.
|
||||||
|
func isOWS(b byte) bool { return b == ' ' || b == '\t' }
|
||||||
|
|
||||||
|
// trimOWS returns x with all optional whitespace removes from the
|
||||||
|
// beginning and end.
|
||||||
|
func trimOWS(x string) string {
|
||||||
|
// TODO: consider using strings.Trim(x, " \t") instead,
|
||||||
|
// if and when it's fast enough. See issue 10292.
|
||||||
|
// But this ASCII-only code will probably always beat UTF-8
|
||||||
|
// aware code.
|
||||||
|
for len(x) > 0 && isOWS(x[0]) {
|
||||||
|
x = x[1:]
|
||||||
|
}
|
||||||
|
for len(x) > 0 && isOWS(x[len(x)-1]) {
|
||||||
|
x = x[:len(x)-1]
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// headerValueContainsToken reports whether v (assumed to be a
|
||||||
|
// 0#element, in the ABNF extension described in RFC 7230 section 7)
|
||||||
|
// contains token amongst its comma-separated tokens, ASCII
|
||||||
|
// case-insensitively.
|
||||||
|
func headerValueContainsToken(v string, token string) bool {
|
||||||
|
v = trimOWS(v)
|
||||||
|
if comma := strings.IndexByte(v, ','); comma != -1 {
|
||||||
|
return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
|
||||||
|
}
|
||||||
|
return tokenEqual(v, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
// lowerASCII returns the ASCII lowercase version of b.
|
||||||
|
func lowerASCII(b byte) byte {
|
||||||
|
if 'A' <= b && b <= 'Z' {
|
||||||
|
return b + ('a' - 'A')
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
|
||||||
|
func tokenEqual(t1, t2 string) bool {
|
||||||
|
if len(t1) != len(t2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i, b := range t1 {
|
||||||
|
if b >= utf8.RuneSelf {
|
||||||
|
// No UTF-8 or non-ASCII allowed in tokens.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// isLWS reports whether b is linear white space, according
|
||||||
|
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
|
||||||
|
// LWS = [CRLF] 1*( SP | HT )
|
||||||
|
func isLWS(b byte) bool { return b == ' ' || b == '\t' }
|
||||||
|
|
||||||
|
// isCTL reports whether b is a control byte, according
|
||||||
|
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
|
||||||
|
// CTL = <any US-ASCII control character
|
||||||
|
// (octets 0 - 31) and DEL (127)>
|
||||||
|
func isCTL(b byte) bool {
|
||||||
|
const del = 0x7f // a CTL
|
||||||
|
return b < ' ' || b == del
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name.
|
||||||
|
// HTTP/2 imposes the additional restriction that uppercase ASCII
|
||||||
|
// letters are not allowed.
|
||||||
|
//
|
||||||
|
// RFC 7230 says:
|
||||||
|
// header-field = field-name ":" OWS field-value OWS
|
||||||
|
// field-name = token
|
||||||
|
// token = 1*tchar
|
||||||
|
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
||||||
|
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
||||||
|
func ValidHeaderFieldName(v string) bool {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, r := range v {
|
||||||
|
if !IsTokenRune(r) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidHostHeader reports whether h is a valid host header.
|
||||||
|
func ValidHostHeader(h string) bool {
|
||||||
|
// The latest spec is actually this:
|
||||||
|
//
|
||||||
|
// http://tools.ietf.org/html/rfc7230#section-5.4
|
||||||
|
// Host = uri-host [ ":" port ]
|
||||||
|
//
|
||||||
|
// Where uri-host is:
|
||||||
|
// http://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||||
|
//
|
||||||
|
// But we're going to be much more lenient for now and just
|
||||||
|
// search for any byte that's not a valid byte in any of those
|
||||||
|
// expressions.
|
||||||
|
for i := 0; i < len(h); i++ {
|
||||||
|
if !validHostByte[h[i]] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// See the validHostHeader comment.
|
||||||
|
var validHostByte = [256]bool{
|
||||||
|
'0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true,
|
||||||
|
'8': true, '9': true,
|
||||||
|
|
||||||
|
'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true,
|
||||||
|
'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true,
|
||||||
|
'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true,
|
||||||
|
'y': true, 'z': true,
|
||||||
|
|
||||||
|
'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true,
|
||||||
|
'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true,
|
||||||
|
'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true,
|
||||||
|
'Y': true, 'Z': true,
|
||||||
|
|
||||||
|
'!': true, // sub-delims
|
||||||
|
'$': true, // sub-delims
|
||||||
|
'%': true, // pct-encoded (and used in IPv6 zones)
|
||||||
|
'&': true, // sub-delims
|
||||||
|
'(': true, // sub-delims
|
||||||
|
')': true, // sub-delims
|
||||||
|
'*': true, // sub-delims
|
||||||
|
'+': true, // sub-delims
|
||||||
|
',': true, // sub-delims
|
||||||
|
'-': true, // unreserved
|
||||||
|
'.': true, // unreserved
|
||||||
|
':': true, // IPv6address + Host expression's optional port
|
||||||
|
';': true, // sub-delims
|
||||||
|
'=': true, // sub-delims
|
||||||
|
'[': true,
|
||||||
|
'\'': true, // sub-delims
|
||||||
|
']': true,
|
||||||
|
'_': true, // unreserved
|
||||||
|
'~': true, // unreserved
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidHeaderFieldValue reports whether v is a valid "field-value" according to
|
||||||
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
|
||||||
|
//
|
||||||
|
// message-header = field-name ":" [ field-value ]
|
||||||
|
// field-value = *( field-content | LWS )
|
||||||
|
// field-content = <the OCTETs making up the field-value
|
||||||
|
// and consisting of either *TEXT or combinations
|
||||||
|
// of token, separators, and quoted-string>
|
||||||
|
//
|
||||||
|
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
|
||||||
|
//
|
||||||
|
// TEXT = <any OCTET except CTLs,
|
||||||
|
// but including LWS>
|
||||||
|
// LWS = [CRLF] 1*( SP | HT )
|
||||||
|
// CTL = <any US-ASCII control character
|
||||||
|
// (octets 0 - 31) and DEL (127)>
|
||||||
|
//
|
||||||
|
// RFC 7230 says:
|
||||||
|
// field-value = *( field-content / obs-fold )
|
||||||
|
// obj-fold = N/A to http2, and deprecated
|
||||||
|
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
|
||||||
|
// field-vchar = VCHAR / obs-text
|
||||||
|
// obs-text = %x80-FF
|
||||||
|
// VCHAR = "any visible [USASCII] character"
|
||||||
|
//
|
||||||
|
// http2 further says: "Similarly, HTTP/2 allows header field values
|
||||||
|
// that are not valid. While most of the values that can be encoded
|
||||||
|
// will not alter header field parsing, carriage return (CR, ASCII
|
||||||
|
// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
|
||||||
|
// 0x0) might be exploited by an attacker if they are translated
|
||||||
|
// verbatim. Any request or response that contains a character not
|
||||||
|
// permitted in a header field value MUST be treated as malformed
|
||||||
|
// (Section 8.1.2.6). Valid characters are defined by the
|
||||||
|
// field-content ABNF rule in Section 3.2 of [RFC7230]."
|
||||||
|
//
|
||||||
|
// This function does not (yet?) properly handle the rejection of
|
||||||
|
// strings that begin or end with SP or HTAB.
|
||||||
|
func ValidHeaderFieldValue(v string) bool {
|
||||||
|
for i := 0; i < len(v); i++ {
|
||||||
|
b := v[i]
|
||||||
|
if isCTL(b) && !isLWS(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
"importpath": "github.com/42wim/matterbridge-plus/bridge",
|
"importpath": "github.com/42wim/matterbridge-plus/bridge",
|
||||||
"repository": "https://github.com/42wim/matterbridge-plus",
|
"repository": "https://github.com/42wim/matterbridge-plus",
|
||||||
"vcs": "git",
|
"vcs": "git",
|
||||||
"revision": "e48ce1d820967506c7ea21539f6c88f7a1377d0f",
|
"revision": "63c7caabf4b92fa47060cf37beb0ed814cefbaea",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"path": "/bridge",
|
"path": "/bridge",
|
||||||
"notests": true
|
"notests": true
|
||||||
|
@ -14,20 +14,11 @@
|
||||||
"importpath": "github.com/42wim/matterbridge-plus/matterclient",
|
"importpath": "github.com/42wim/matterbridge-plus/matterclient",
|
||||||
"repository": "https://github.com/42wim/matterbridge-plus",
|
"repository": "https://github.com/42wim/matterbridge-plus",
|
||||||
"vcs": "git",
|
"vcs": "git",
|
||||||
"revision": "e48ce1d820967506c7ea21539f6c88f7a1377d0f",
|
"revision": "63c7caabf4b92fa47060cf37beb0ed814cefbaea",
|
||||||
"branch": "master",
|
"branch": "master",
|
||||||
"path": "/matterclient",
|
"path": "/matterclient",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"importpath": "github.com/42wim/matterbridge/matterhook",
|
|
||||||
"repository": "https://github.com/42wim/matterbridge",
|
|
||||||
"vcs": "",
|
|
||||||
"revision": "6b18257185b1830bd2eff83fae30bdd2055f78b0",
|
|
||||||
"branch": "master",
|
|
||||||
"path": "/matterhook",
|
|
||||||
"notests": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"importpath": "github.com/Sirupsen/logrus",
|
"importpath": "github.com/Sirupsen/logrus",
|
||||||
"repository": "https://github.com/Sirupsen/logrus",
|
"repository": "https://github.com/Sirupsen/logrus",
|
||||||
|
@ -72,8 +63,8 @@
|
||||||
"importpath": "github.com/mattermost/platform/einterfaces",
|
"importpath": "github.com/mattermost/platform/einterfaces",
|
||||||
"repository": "https://github.com/mattermost/platform",
|
"repository": "https://github.com/mattermost/platform",
|
||||||
"vcs": "git",
|
"vcs": "git",
|
||||||
"revision": "9d94869cc6a0fb9f051879437c104ccd76094380",
|
"revision": "974238231b9cdbd39a825ec8e9299fbb0b51f6b8",
|
||||||
"branch": "HEAD",
|
"branch": "release-3.1",
|
||||||
"path": "/einterfaces",
|
"path": "/einterfaces",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
@ -81,8 +72,8 @@
|
||||||
"importpath": "github.com/mattermost/platform/model",
|
"importpath": "github.com/mattermost/platform/model",
|
||||||
"repository": "https://github.com/mattermost/platform",
|
"repository": "https://github.com/mattermost/platform",
|
||||||
"vcs": "git",
|
"vcs": "git",
|
||||||
"revision": "9d94869cc6a0fb9f051879437c104ccd76094380",
|
"revision": "974238231b9cdbd39a825ec8e9299fbb0b51f6b8",
|
||||||
"branch": "HEAD",
|
"branch": "release-3.1",
|
||||||
"path": "/model",
|
"path": "/model",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
@ -154,6 +145,15 @@
|
||||||
"path": "/http2/hpack",
|
"path": "/http2/hpack",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"importpath": "golang.org/x/net/lex/httplex",
|
||||||
|
"repository": "https://go.googlesource.com/net",
|
||||||
|
"vcs": "git",
|
||||||
|
"revision": "bc3663df0ac92f928d419e31e0d2af22e683a5a2",
|
||||||
|
"branch": "master",
|
||||||
|
"path": "/lex/httplex",
|
||||||
|
"notests": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"importpath": "gopkg.in/gcfg.v1",
|
"importpath": "gopkg.in/gcfg.v1",
|
||||||
"repository": "https://gopkg.in/gcfg.v1",
|
"repository": "https://gopkg.in/gcfg.v1",
|
||||||
|
|
Loading…
Reference in New Issue