Merge branch 'master' into PLT-1429
Этот коммит содержится в:
@@ -9,7 +9,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/mattermost/platform/model"
|
||||
|
||||
@@ -5,7 +5,7 @@ package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
"html/template"
|
||||
@@ -46,6 +46,7 @@ func InitApi() {
|
||||
InitOAuth(r)
|
||||
InitWebhook(r)
|
||||
InitPreference(r)
|
||||
InitLicense(r)
|
||||
|
||||
templatesDir := utils.FindDir("api/templates")
|
||||
l4g.Debug("Parsing server templates at %v", templatesDir)
|
||||
|
||||
@@ -4,14 +4,19 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
"fmt"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultExtraMemberLimit = 100
|
||||
)
|
||||
|
||||
func InitChannel(r *mux.Router) {
|
||||
l4g.Debug("Initializing channel api routes")
|
||||
|
||||
@@ -27,6 +32,7 @@ func InitChannel(r *mux.Router) {
|
||||
sr.Handle("/update_notify_props", ApiUserRequired(updateNotifyProps)).Methods("POST")
|
||||
sr.Handle("/{id:[A-Za-z0-9]+}/", ApiUserRequiredActivity(getChannel, false)).Methods("GET")
|
||||
sr.Handle("/{id:[A-Za-z0-9]+}/extra_info", ApiUserRequired(getChannelExtraInfo)).Methods("GET")
|
||||
sr.Handle("/{id:[A-Za-z0-9]+}/extra_info/{member_limit:-?[0-9]+}", ApiUserRequired(getChannelExtraInfo)).Methods("GET")
|
||||
sr.Handle("/{id:[A-Za-z0-9]+}/join", ApiUserRequired(join)).Methods("POST")
|
||||
sr.Handle("/{id:[A-Za-z0-9]+}/leave", ApiUserRequired(leave)).Methods("POST")
|
||||
sr.Handle("/{id:[A-Za-z0-9]+}/delete", ApiUserRequired(deleteChannel)).Methods("POST")
|
||||
@@ -730,10 +736,19 @@ func getChannel(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func getChannelExtraInfo(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
params := mux.Vars(r)
|
||||
id := params["id"]
|
||||
|
||||
var memberLimit int
|
||||
if memberLimitString, ok := params["member_limit"]; !ok {
|
||||
memberLimit = defaultExtraMemberLimit
|
||||
} else if memberLimitInt64, err := strconv.ParseInt(memberLimitString, 10, 0); err != nil {
|
||||
c.Err = model.NewAppError("getChannelExtraInfo", "Failed to parse member limit", err.Error())
|
||||
return
|
||||
} else {
|
||||
memberLimit = int(memberLimitInt64)
|
||||
}
|
||||
|
||||
sc := Srv.Store.Channel().Get(id)
|
||||
var channel *model.Channel
|
||||
if cresult := <-sc; cresult.Err != nil {
|
||||
@@ -743,13 +758,13 @@ func getChannelExtraInfo(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
channel = cresult.Data.(*model.Channel)
|
||||
}
|
||||
|
||||
extraEtag := channel.ExtraEtag()
|
||||
extraEtag := channel.ExtraEtag(memberLimit)
|
||||
if HandleEtag(extraEtag, w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
scm := Srv.Store.Channel().GetMember(id, c.Session.UserId)
|
||||
ecm := Srv.Store.Channel().GetExtraMembers(id, 100)
|
||||
ecm := Srv.Store.Channel().GetExtraMembers(id, memberLimit)
|
||||
ccm := Srv.Store.Channel().GetMemberCount(id)
|
||||
|
||||
if cmresult := <-scm; cmresult.Err != nil {
|
||||
|
||||
@@ -189,7 +189,7 @@ func BenchmarkGetChannelExtraInfo(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := range channels {
|
||||
Client.Must(Client.GetChannelExtraInfo(channels[j].Id, ""))
|
||||
Client.Must(Client.GetChannelExtraInfo(channels[j].Id, -1, ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,7 +674,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
|
||||
rget := Client.Must(Client.GetChannelExtraInfo(channel1.Id, ""))
|
||||
rget := Client.Must(Client.GetChannelExtraInfo(channel1.Id, -1, ""))
|
||||
data := rget.Data.(*model.ChannelExtra)
|
||||
if data.Id != channel1.Id {
|
||||
t.Fatal("couldnt't get extra info")
|
||||
@@ -690,7 +690,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
|
||||
currentEtag := rget.Etag
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, currentEtag); err != nil {
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, -1, currentEtag); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cache_result.Data.(*model.ChannelExtra) != nil {
|
||||
t.Log(cache_result.Data)
|
||||
@@ -708,7 +708,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
Client2.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||
Client2.Must(Client2.JoinChannel(channel1.Id))
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, currentEtag); err != nil {
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, -1, currentEtag); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cache_result.Data.(*model.ChannelExtra) == nil {
|
||||
t.Log(cache_result.Data)
|
||||
@@ -717,7 +717,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
currentEtag = cache_result.Etag
|
||||
}
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, currentEtag); err != nil {
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, -1, currentEtag); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cache_result.Data.(*model.ChannelExtra) != nil {
|
||||
t.Log(cache_result.Data)
|
||||
@@ -728,7 +728,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
|
||||
Client2.Must(Client2.LeaveChannel(channel1.Id))
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, currentEtag); err != nil {
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, -1, currentEtag); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cache_result.Data.(*model.ChannelExtra) == nil {
|
||||
t.Log(cache_result.Data)
|
||||
@@ -737,7 +737,7 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
currentEtag = cache_result.Etag
|
||||
}
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, currentEtag); err != nil {
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, -1, currentEtag); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cache_result.Data.(*model.ChannelExtra) != nil {
|
||||
t.Log(cache_result.Data)
|
||||
@@ -745,6 +745,42 @@ func TestGetChannelExtraInfo(t *testing.T) {
|
||||
} else {
|
||||
currentEtag = cache_result.Etag
|
||||
}
|
||||
|
||||
Client2.Must(Client2.JoinChannel(channel1.Id))
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, 2, currentEtag); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if extra := cache_result.Data.(*model.ChannelExtra); extra == nil {
|
||||
t.Fatal("response should not be empty")
|
||||
} else if len(extra.Members) != 2 {
|
||||
t.Fatal("should've returned 2 members")
|
||||
} else if extra.MemberCount != 2 {
|
||||
t.Fatal("should've returned member count of 2")
|
||||
} else {
|
||||
currentEtag = cache_result.Etag
|
||||
}
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, 1, currentEtag); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if extra := cache_result.Data.(*model.ChannelExtra); extra == nil {
|
||||
t.Fatal("response should not be empty")
|
||||
} else if len(extra.Members) != 1 {
|
||||
t.Fatal("should've returned only 1 member")
|
||||
} else if extra.MemberCount != 2 {
|
||||
t.Fatal("should've returned member count of 2")
|
||||
} else {
|
||||
currentEtag = cache_result.Etag
|
||||
}
|
||||
|
||||
if cache_result, err := Client.GetChannelExtraInfo(channel1.Id, 1, currentEtag); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if cache_result.Data.(*model.ChannelExtra) != nil {
|
||||
t.Log(cache_result.Data)
|
||||
t.Fatal("response should be empty")
|
||||
} else {
|
||||
currentEtag = cache_result.Etag
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAddChannelMember(t *testing.T) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/store"
|
||||
"github.com/mattermost/platform/utils"
|
||||
@@ -35,6 +35,7 @@ type Page struct {
|
||||
TemplateName string
|
||||
Props map[string]string
|
||||
ClientCfg map[string]string
|
||||
ClientLicense map[string]string
|
||||
User *model.User
|
||||
Team *model.Team
|
||||
Channel *model.Channel
|
||||
|
||||
22
api/file.go
22
api/file.go
@@ -5,8 +5,8 @@ package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
l4g "code.google.com/p/log4go"
|
||||
"fmt"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/goamz/goamz/aws"
|
||||
"github.com/goamz/goamz/s3"
|
||||
@@ -541,12 +541,8 @@ func writeFile(f []byte, path string) *model.AppError {
|
||||
return model.NewAppError("writeFile", "Encountered an error writing to S3", err.Error())
|
||||
}
|
||||
} else if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_LOCAL {
|
||||
if err := os.MkdirAll(filepath.Dir(utils.Cfg.FileSettings.Directory+path), 0774); err != nil {
|
||||
return model.NewAppError("writeFile", "Encountered an error creating the directory for the new file", err.Error())
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(utils.Cfg.FileSettings.Directory+path, f, 0644); err != nil {
|
||||
return model.NewAppError("writeFile", "Encountered an error writing to local server storage", err.Error())
|
||||
if err := writeFileLocally(f, utils.Cfg.FileSettings.Directory+path); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return model.NewAppError("writeFile", "File storage not configured properly. Please configure for either S3 or local server file storage.", "")
|
||||
@@ -555,6 +551,18 @@ func writeFile(f []byte, path string) *model.AppError {
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeFileLocally(f []byte, path string) *model.AppError {
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0774); err != nil {
|
||||
return model.NewAppError("writeFile", "Encountered an error creating the directory for the new file", err.Error())
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(path, f, 0644); err != nil {
|
||||
return model.NewAppError("writeFile", "Encountered an error writing to local server storage", err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func readFile(path string) ([]byte, *model.AppError) {
|
||||
|
||||
if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
)
|
||||
|
||||
|
||||
100
api/license.go
Обычный файл
100
api/license.go
Обычный файл
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func InitLicense(r *mux.Router) {
|
||||
l4g.Debug("Initializing license api routes")
|
||||
|
||||
sr := r.PathPrefix("/license").Subrouter()
|
||||
sr.Handle("/add", ApiAdminSystemRequired(addLicense)).Methods("POST")
|
||||
sr.Handle("/remove", ApiAdminSystemRequired(removeLicense)).Methods("POST")
|
||||
}
|
||||
|
||||
func addLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.LogAudit("attempt")
|
||||
err := r.ParseMultipartForm(model.MAX_FILE_SIZE)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
m := r.MultipartForm
|
||||
|
||||
fileArray, ok := m.File["license"]
|
||||
if !ok {
|
||||
c.Err = model.NewAppError("addLicense", "No file under 'license' in request", "")
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
return
|
||||
}
|
||||
|
||||
if len(fileArray) <= 0 {
|
||||
c.Err = model.NewAppError("addLicense", "Empty array under 'license' in request", "")
|
||||
c.Err.StatusCode = http.StatusBadRequest
|
||||
return
|
||||
}
|
||||
|
||||
fileData := fileArray[0]
|
||||
|
||||
file, err := fileData.Open()
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
c.Err = model.NewAppError("addLicense", "Could not open license file", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
io.Copy(buf, file)
|
||||
|
||||
data := buf.Bytes()
|
||||
|
||||
var license *model.License
|
||||
if success, licenseStr := utils.ValidateLicense(data); success {
|
||||
license = model.LicenseFromJson(strings.NewReader(licenseStr))
|
||||
|
||||
if ok := utils.SetLicense(license); !ok {
|
||||
c.LogAudit("failed - expired or non-started license")
|
||||
c.Err = model.NewAppError("addLicense", "License is either expired or has not yet started.", "")
|
||||
return
|
||||
}
|
||||
|
||||
if err := writeFileLocally(data, utils.LicenseLocation()); err != nil {
|
||||
c.LogAudit("failed - could not save license file")
|
||||
c.Err = model.NewAppError("addLicense", "License did not save properly.", "path="+utils.LicenseLocation())
|
||||
utils.RemoveLicense()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
c.LogAudit("failed - invalid license")
|
||||
c.Err = model.NewAppError("addLicense", "Invalid license file.", "")
|
||||
return
|
||||
}
|
||||
|
||||
c.LogAudit("success")
|
||||
w.Write([]byte(license.ToJson()))
|
||||
}
|
||||
|
||||
func removeLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
c.LogAudit("")
|
||||
|
||||
if ok := utils.RemoveLicense(); !ok {
|
||||
c.LogAudit("failed - could not remove license file")
|
||||
c.Err = model.NewAppError("removeLicense", "License did not remove properly.", "")
|
||||
return
|
||||
}
|
||||
|
||||
rdata := map[string]string{}
|
||||
rdata["status"] = "ok"
|
||||
w.Write([]byte(model.MapToJson(rdata)))
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
"fmt"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
"fmt"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/store"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"net/http"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/braintree/manners"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/store"
|
||||
|
||||
@@ -6,8 +6,8 @@ package api
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
l4g "code.google.com/p/log4go"
|
||||
"encoding/json"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
|
||||
@@ -5,8 +5,8 @@ package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
l4g "code.google.com/p/log4go"
|
||||
"fmt"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/store"
|
||||
|
||||
37
api/user.go
37
api/user.go
@@ -5,9 +5,9 @@ package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
l4g "code.google.com/p/log4go"
|
||||
b64 "encoding/base64"
|
||||
"fmt"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/disintegration/imaging"
|
||||
"github.com/golang/freetype"
|
||||
"github.com/gorilla/mux"
|
||||
@@ -122,6 +122,11 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
user.EmailVerified = true
|
||||
}
|
||||
|
||||
if !CheckUserDomain(user, utils.Cfg.TeamSettings.RestrictCreationToDomains) {
|
||||
c.Err = model.NewAppError("createUser", "The email you provided does not belong to an accepted domain. Please contact your administrator or sign up with a different email.", "")
|
||||
return
|
||||
}
|
||||
|
||||
ruser, err := CreateUser(team, user)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
@@ -136,19 +141,29 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
func CheckUserDomain(user *model.User, domains string) bool {
|
||||
if len(domains) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
domainArray := strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(domains, "@", " ", -1), ",", " ", -1))))
|
||||
|
||||
matched := false
|
||||
for _, d := range domainArray {
|
||||
if strings.HasSuffix(user.Email, "@"+d) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return matched
|
||||
}
|
||||
|
||||
func IsVerifyHashRequired(user *model.User, team *model.Team, hash string) bool {
|
||||
shouldVerifyHash := true
|
||||
|
||||
if team.Type == model.TEAM_INVITE && len(team.AllowedDomains) > 0 && len(hash) == 0 && user != nil {
|
||||
domains := strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(team.AllowedDomains, "@", " ", -1), ",", " ", -1))))
|
||||
|
||||
matched := false
|
||||
for _, d := range domains {
|
||||
if strings.HasSuffix(user.Email, "@"+d) {
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
matched := CheckUserDomain(user, team.AllowedDomains)
|
||||
|
||||
if matched {
|
||||
shouldVerifyHash = false
|
||||
@@ -1794,7 +1809,7 @@ func GetAuthorizationCode(c *Context, service, teamName string, props map[string
|
||||
props["team"] = teamName
|
||||
state := b64.StdEncoding.EncodeToString([]byte(model.MapToJson(props)))
|
||||
|
||||
redirectUri := c.GetSiteURL() + "/" + service + "/complete"
|
||||
redirectUri := c.GetSiteURL() + "/signup/" + service + "/complete" // Remove /signup after a few releases (~1.8)
|
||||
|
||||
authUrl := endpoint + "?response_type=code&client_id=" + clientId + "&redirect_uri=" + url.QueryEscape(redirectUri) + "&state=" + url.QueryEscape(state)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/store"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/mattermost/platform/model"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/model"
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
l4g "code.google.com/p/log4go"
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
|
||||
Ссылка в новой задаче
Block a user