Merge pull request #27 from mattermost/mm-1240
fixes mm-1240 adds ability to turn valet feature on
Этот коммит содержится в:
@@ -9,6 +9,8 @@ import (
|
|||||||
"github.com/mattermost/platform/model"
|
"github.com/mattermost/platform/model"
|
||||||
"github.com/mattermost/platform/utils"
|
"github.com/mattermost/platform/utils"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -19,16 +21,13 @@ var commands = []commandHandler{
|
|||||||
logoutCommand,
|
logoutCommand,
|
||||||
joinCommand,
|
joinCommand,
|
||||||
loadTestCommand,
|
loadTestCommand,
|
||||||
|
echoCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitCommand(r *mux.Router) {
|
func InitCommand(r *mux.Router) {
|
||||||
l4g.Debug("Initializing command api routes")
|
l4g.Debug("Initializing command api routes")
|
||||||
r.Handle("/command", ApiUserRequired(command)).Methods("POST")
|
r.Handle("/command", ApiUserRequired(command)).Methods("POST")
|
||||||
|
|
||||||
if utils.Cfg.TeamSettings.AllowValet {
|
|
||||||
commands = append(commands, echoCommand)
|
|
||||||
}
|
|
||||||
|
|
||||||
hub.Start()
|
hub.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +58,8 @@ func checkCommand(c *Context, command *model.Command) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tchan := Srv.Store.Team().Get(c.Session.TeamId)
|
||||||
|
|
||||||
if len(command.ChannelId) > 0 {
|
if len(command.ChannelId) > 0 {
|
||||||
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, command.ChannelId, c.Session.UserId)
|
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, command.ChannelId, c.Session.UserId)
|
||||||
|
|
||||||
@@ -67,7 +68,21 @@ func checkCommand(c *Context, command *model.Command) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allowValet := false
|
||||||
|
if tResult := <-tchan; tResult.Err != nil {
|
||||||
|
c.Err = model.NewAppError("checkCommand", "Could not find the team for this session, team_id="+c.Session.TeamId, "")
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
allowValet = tResult.Data.(*model.Team).AllowValet
|
||||||
|
}
|
||||||
|
|
||||||
|
ec := runtime.FuncForPC(reflect.ValueOf(echoCommand).Pointer()).Name()
|
||||||
|
|
||||||
for _, v := range commands {
|
for _, v := range commands {
|
||||||
|
if !allowValet && ec == runtime.FuncForPC(reflect.ValueOf(v).Pointer()).Name() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if v(c, command) {
|
if v(c, command) {
|
||||||
return true
|
return true
|
||||||
} else if c.Err != nil {
|
} else if c.Err != nil {
|
||||||
|
|||||||
20
api/post.go
20
api/post.go
@@ -58,11 +58,7 @@ func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func createValetPost(c *Context, w http.ResponseWriter, r *http.Request) {
|
func createValetPost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
if !utils.Cfg.TeamSettings.AllowValet {
|
tchan := Srv.Store.Team().Get(c.Session.TeamId)
|
||||||
c.Err = model.NewAppError("createValetPost", "The valet feature is currently turned off. Please contact your system administrator for details.", "")
|
|
||||||
c.Err.StatusCode = http.StatusNotImplemented
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
post := model.PostFromJson(r.Body)
|
post := model.PostFromJson(r.Body)
|
||||||
if post == nil {
|
if post == nil {
|
||||||
@@ -70,13 +66,25 @@ func createValetPost(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Any one with access to the team can post as valet to any open channel
|
|
||||||
cchan := Srv.Store.Channel().CheckOpenChannelPermissions(c.Session.TeamId, post.ChannelId)
|
cchan := Srv.Store.Channel().CheckOpenChannelPermissions(c.Session.TeamId, post.ChannelId)
|
||||||
|
|
||||||
|
// Any one with access to the team can post as valet to any open channel
|
||||||
if !c.HasPermissionsToChannel(cchan, "createValetPost") {
|
if !c.HasPermissionsToChannel(cchan, "createValetPost") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure this team has the valet feature enabled
|
||||||
|
if tResult := <-tchan; tResult.Err != nil {
|
||||||
|
c.Err = model.NewAppError("createValetPost", "Could not find the team for this session, team_id="+c.Session.TeamId, "")
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
if !tResult.Data.(*model.Team).AllowValet {
|
||||||
|
c.Err = model.NewAppError("createValetPost", "The valet feature is currently turned off. Please contact your team administrator for details.", "")
|
||||||
|
c.Err.StatusCode = http.StatusNotImplemented
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if rp, err := CreateValetPost(c, post); err != nil {
|
if rp, err := CreateValetPost(c, post); err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
|
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ func TestCreateValetPost(t *testing.T) {
|
|||||||
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||||
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
|
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
|
||||||
|
|
||||||
if utils.Cfg.TeamSettings.AllowValet {
|
if utils.Cfg.TeamSettings.AllowValetDefault {
|
||||||
post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a"}
|
post1 := &model.Post{ChannelId: channel1.Id, Message: "#hashtag a" + model.NewId() + "a"}
|
||||||
rpost1, err := Client.CreateValetPost(post1)
|
rpost1, err := Client.CreateValetPost(post1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
82
api/team.go
82
api/team.go
@@ -29,6 +29,8 @@ func InitTeam(r *mux.Router) {
|
|||||||
sr.Handle("/email_teams", ApiAppHandler(emailTeams)).Methods("POST")
|
sr.Handle("/email_teams", ApiAppHandler(emailTeams)).Methods("POST")
|
||||||
sr.Handle("/invite_members", ApiUserRequired(inviteMembers)).Methods("POST")
|
sr.Handle("/invite_members", ApiUserRequired(inviteMembers)).Methods("POST")
|
||||||
sr.Handle("/update_name", ApiUserRequired(updateTeamName)).Methods("POST")
|
sr.Handle("/update_name", ApiUserRequired(updateTeamName)).Methods("POST")
|
||||||
|
sr.Handle("/update_valet_feature", ApiUserRequired(updateValetFeature)).Methods("POST")
|
||||||
|
sr.Handle("/me", ApiUserRequired(getMyTeam)).Methods("GET")
|
||||||
}
|
}
|
||||||
|
|
||||||
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -136,6 +138,8 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
teamSignup.Team.AllowValet = utils.Cfg.TeamSettings.AllowValetDefault
|
||||||
|
|
||||||
if result := <-Srv.Store.Team().Save(&teamSignup.Team); result.Err != nil {
|
if result := <-Srv.Store.Team().Save(&teamSignup.Team); result.Err != nil {
|
||||||
c.Err = result.Err
|
c.Err = result.Err
|
||||||
return
|
return
|
||||||
@@ -157,7 +161,7 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if utils.Cfg.TeamSettings.AllowValet {
|
if teamSignup.Team.AllowValet {
|
||||||
CreateValet(c, rteam)
|
CreateValet(c, rteam)
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
return
|
return
|
||||||
@@ -200,6 +204,13 @@ func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if rteam.AllowValet {
|
||||||
|
CreateValet(c, rteam)
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
w.Write([]byte(rteam.ToJson()))
|
w.Write([]byte(rteam.ToJson()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -542,3 +553,72 @@ func updateTeamName(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Write([]byte(model.MapToJson(props)))
|
w.Write([]byte(model.MapToJson(props)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateValetFeature(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
props := model.MapFromJson(r.Body)
|
||||||
|
|
||||||
|
allowValetStr := props["allow_valet"]
|
||||||
|
if len(allowValetStr) == 0 {
|
||||||
|
c.SetInvalidParam("updateValetFeature", "allow_valet")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
allowValet := allowValetStr == "true"
|
||||||
|
|
||||||
|
teamId := props["team_id"]
|
||||||
|
if len(teamId) > 0 && len(teamId) != 26 {
|
||||||
|
c.SetInvalidParam("updateValetFeature", "team_id")
|
||||||
|
return
|
||||||
|
} else if len(teamId) == 0 {
|
||||||
|
teamId = c.Session.TeamId
|
||||||
|
}
|
||||||
|
|
||||||
|
tchan := Srv.Store.Team().Get(teamId)
|
||||||
|
|
||||||
|
if !c.HasPermissionsToTeam(teamId, "updateValetFeature") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(c.Session.Roles, model.ROLE_ADMIN) {
|
||||||
|
c.Err = model.NewAppError("updateValetFeature", "You do not have the appropriate permissions", "userId="+c.Session.UserId)
|
||||||
|
c.Err.StatusCode = http.StatusForbidden
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var team *model.Team
|
||||||
|
if tResult := <-tchan; tResult.Err != nil {
|
||||||
|
c.Err = tResult.Err
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
team = tResult.Data.(*model.Team)
|
||||||
|
}
|
||||||
|
|
||||||
|
team.AllowValet = allowValet
|
||||||
|
|
||||||
|
if result := <-Srv.Store.Team().Update(team); result.Err != nil {
|
||||||
|
c.Err = result.Err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(model.MapToJson(props)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
if len(c.Session.TeamId) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := <-Srv.Store.Team().Get(c.Session.TeamId); result.Err != nil {
|
||||||
|
c.Err = result.Err
|
||||||
|
return
|
||||||
|
} else if HandleEtag(result.Data.(*model.Team).Etag(), w, r) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
w.Header().Set(model.HEADER_ETAG_SERVER, result.Data.(*model.Team).Etag())
|
||||||
|
w.Header().Set("Expires", "-1")
|
||||||
|
w.Write([]byte(result.Data.(*model.Team).ToJson()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
103
api/team_test.go
103
api/team_test.go
@@ -286,3 +286,106 @@ func TestFuzzyTeamCreate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetMyTeam(t *testing.T) {
|
||||||
|
Setup()
|
||||||
|
|
||||||
|
team := model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||||
|
rteam, _ := Client.CreateTeam(&team)
|
||||||
|
|
||||||
|
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||||
|
ruser, _ := Client.CreateUser(&user, "")
|
||||||
|
Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id)
|
||||||
|
|
||||||
|
Client.LoginByEmail(team.Domain, user.Email, user.Password)
|
||||||
|
|
||||||
|
if result, err := Client.GetMyTeam(""); err != nil {
|
||||||
|
t.Fatal("Failed to get user")
|
||||||
|
} else {
|
||||||
|
if result.Data.(*model.Team).Name != team.Name {
|
||||||
|
t.Fatal("team names did not match")
|
||||||
|
}
|
||||||
|
if result.Data.(*model.Team).Domain != team.Domain {
|
||||||
|
t.Fatal("team domains did not match")
|
||||||
|
}
|
||||||
|
if result.Data.(*model.Team).Type != team.Type {
|
||||||
|
t.Fatal("team types did not match")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateValetFeature(t *testing.T) {
|
||||||
|
Setup()
|
||||||
|
|
||||||
|
team := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||||
|
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||||
|
|
||||||
|
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||||
|
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
|
||||||
|
Srv.Store.User().VerifyEmail(user.Id)
|
||||||
|
|
||||||
|
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||||
|
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||||
|
Srv.Store.User().VerifyEmail(user2.Id)
|
||||||
|
|
||||||
|
team2 := &model.Team{Name: "Name", Domain: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||||
|
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
|
||||||
|
|
||||||
|
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "corey@test.com", FullName: "Corey Hulen", Password: "pwd"}
|
||||||
|
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
|
||||||
|
Srv.Store.User().VerifyEmail(user3.Id)
|
||||||
|
|
||||||
|
Client.LoginByEmail(team.Domain, user2.Email, "pwd")
|
||||||
|
|
||||||
|
data := make(map[string]string)
|
||||||
|
data["allow_valet"] = "true"
|
||||||
|
if _, err := Client.UpdateValetFeature(data); err == nil {
|
||||||
|
t.Fatal("Should have errored, not admin")
|
||||||
|
}
|
||||||
|
|
||||||
|
Client.LoginByEmail(team.Domain, user.Email, "pwd")
|
||||||
|
|
||||||
|
data["allow_valet"] = ""
|
||||||
|
if _, err := Client.UpdateValetFeature(data); err == nil {
|
||||||
|
t.Fatal("Should have errored, empty allow_valet field")
|
||||||
|
}
|
||||||
|
|
||||||
|
data["allow_valet"] = "true"
|
||||||
|
if _, err := Client.UpdateValetFeature(data); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rteam := Client.Must(Client.GetMyTeam("")).Data.(*model.Team)
|
||||||
|
if rteam.AllowValet != true {
|
||||||
|
t.Fatal("Should have errored - allow valet property not updated")
|
||||||
|
}
|
||||||
|
|
||||||
|
data["team_id"] = "junk"
|
||||||
|
if _, err := Client.UpdateValetFeature(data); err == nil {
|
||||||
|
t.Fatal("Should have errored, junk team id")
|
||||||
|
}
|
||||||
|
|
||||||
|
data["team_id"] = "12345678901234567890123456"
|
||||||
|
if _, err := Client.UpdateValetFeature(data); err == nil {
|
||||||
|
t.Fatal("Should have errored, bad team id")
|
||||||
|
}
|
||||||
|
|
||||||
|
data["team_id"] = team.Id
|
||||||
|
data["allow_valet"] = "false"
|
||||||
|
if _, err := Client.UpdateValetFeature(data); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rteam = Client.Must(Client.GetMyTeam("")).Data.(*model.Team)
|
||||||
|
if rteam.AllowValet != false {
|
||||||
|
t.Fatal("Should have errored - allow valet property not updated")
|
||||||
|
}
|
||||||
|
|
||||||
|
Client.LoginByEmail(team2.Domain, user3.Email, "pwd")
|
||||||
|
|
||||||
|
data["team_id"] = team.Id
|
||||||
|
data["allow_valet"] = "true"
|
||||||
|
if _, err := Client.UpdateValetFeature(data); err == nil {
|
||||||
|
t.Fatal("Should have errored, not part of team")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -145,10 +145,6 @@ func createUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateValet(c *Context, team *model.Team) *model.User {
|
func CreateValet(c *Context, team *model.Team) *model.User {
|
||||||
if !utils.Cfg.TeamSettings.AllowValet {
|
|
||||||
return &model.User{}
|
|
||||||
}
|
|
||||||
|
|
||||||
valet := &model.User{}
|
valet := &model.User{}
|
||||||
valet.TeamId = team.Id
|
valet.TeamId = team.Id
|
||||||
valet.Email = utils.Cfg.EmailSettings.FeedbackEmail
|
valet.Email = utils.Cfg.EmailSettings.FeedbackEmail
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
"TeamSettings": {
|
"TeamSettings": {
|
||||||
"MaxUsersPerTeam": 150,
|
"MaxUsersPerTeam": 150,
|
||||||
"AllowPublicLink": true,
|
"AllowPublicLink": true,
|
||||||
"AllowValet": false,
|
"AllowValetDefault": false,
|
||||||
"TermsLink": "/static/help/configure_links.html",
|
"TermsLink": "/static/help/configure_links.html",
|
||||||
"PrivacyLink": "/static/help/configure_links.html",
|
"PrivacyLink": "/static/help/configure_links.html",
|
||||||
"AboutLink": "/static/help/configure_links.html",
|
"AboutLink": "/static/help/configure_links.html",
|
||||||
|
|||||||
@@ -186,6 +186,15 @@ func (c *Client) UpdateTeamName(data map[string]string) (*Result, *AppError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) UpdateValetFeature(data map[string]string) (*Result, *AppError) {
|
||||||
|
if r, err := c.DoPost("/teams/update_valet_feature", MapToJson(data)); 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) CreateUser(user *User, hash string) (*Result, *AppError) {
|
func (c *Client) CreateUser(user *User, hash string) (*Result, *AppError) {
|
||||||
if r, err := c.DoPost("/users/create", user.ToJson()); err != nil {
|
if r, err := c.DoPost("/users/create", user.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -647,6 +656,15 @@ func (c *Client) GetStatuses() (*Result, *AppError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetMyTeam(etag string) (*Result, *AppError) {
|
||||||
|
if r, err := c.DoGet("/teams/me", "", etag); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
|
r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) MockSession(sessionToken string) {
|
func (c *Client) MockSession(sessionToken string) {
|
||||||
c.AuthToken = sessionToken
|
c.AuthToken = sessionToken
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type Team struct {
|
|||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
CompanyName string `json:"company_name"`
|
CompanyName string `json:"company_name"`
|
||||||
AllowedDomains string `json:"allowed_domains"`
|
AllowedDomains string `json:"allowed_domains"`
|
||||||
|
AllowValet bool `json:"allow_valet"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Invites struct {
|
type Invites struct {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package store
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/mattermost/platform/model"
|
"github.com/mattermost/platform/model"
|
||||||
|
"github.com/mattermost/platform/utils"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,6 +30,11 @@ func NewSqlTeamStore(sqlStore *SqlStore) TeamStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s SqlTeamStore) UpgradeSchemaIfNeeded() {
|
func (s SqlTeamStore) UpgradeSchemaIfNeeded() {
|
||||||
|
defaultValue := "0"
|
||||||
|
if utils.Cfg.TeamSettings.AllowValetDefault {
|
||||||
|
defaultValue = "1"
|
||||||
|
}
|
||||||
|
s.CreateColumnIfNotExists("Teams", "AllowValet", "AllowedDomains", "tinyint(1)", defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SqlTeamStore) CreateIndexesIfNotExists() {
|
func (s SqlTeamStore) CreateIndexesIfNotExists() {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ type PrivacySettings struct {
|
|||||||
type TeamSettings struct {
|
type TeamSettings struct {
|
||||||
MaxUsersPerTeam int
|
MaxUsersPerTeam int
|
||||||
AllowPublicLink bool
|
AllowPublicLink bool
|
||||||
AllowValet bool
|
AllowValetDefault bool
|
||||||
TermsLink string
|
TermsLink string
|
||||||
PrivacyLink string
|
PrivacyLink string
|
||||||
AboutLink string
|
AboutLink string
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ module.exports = React.createClass({
|
|||||||
AsyncClient.getChannelExtraInfo(true);
|
AsyncClient.getChannelExtraInfo(true);
|
||||||
AsyncClient.findTeams();
|
AsyncClient.findTeams();
|
||||||
AsyncClient.getStatuses();
|
AsyncClient.getStatuses();
|
||||||
|
AsyncClient.getMyTeam();
|
||||||
/* End of async loads */
|
/* End of async loads */
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
var utils = require('../utils/utils.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
updateTab: function(tab) {
|
updateTab: function(tab) {
|
||||||
this.props.updateTab(tab);
|
this.props.updateTab(tab);
|
||||||
@@ -11,16 +13,11 @@ module.exports = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div className="">
|
<div className="">
|
||||||
<ul className="nav nav-pills nav-stacked">
|
<ul className="nav nav-pills nav-stacked">
|
||||||
<li className={this.props.activeTab == 'general' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("general");}}><i className="glyphicon glyphicon-cog"></i>General</a></li>
|
{this.props.tabs.map(function(tab) {
|
||||||
<li className={this.props.activeTab == 'security' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("security");}}><i className="glyphicon glyphicon-lock"></i>Security</a></li>
|
return <li className={self.props.activeTab == tab.name ? 'active' : ''}><a href="#" onClick={function(){self.updateTab(tab.name);}}><i className={tab.icon}></i>{tab.ui_name}</a></li>
|
||||||
<li className={this.props.activeTab == 'notifications' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("notifications");}}><i className="glyphicon glyphicon-exclamation-sign"></i>Notifications</a></li>
|
})}
|
||||||
<li className={this.props.activeTab == 'appearance' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("appearance");}}><i className="glyphicon glyphicon-wrench"></i>Appearance</a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
/* Temporarily removing sessions and activity logs
|
|
||||||
<li className={this.props.activeTab == 'sessions' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("sessions");}}><i className="glyphicon glyphicon-globe"></i>Sessions</a></li>
|
|
||||||
<li className={this.props.activeTab == 'activity_log' ? 'active' : ''}><a href="#" onClick={function(){self.updateTab("activity_log");}}><i className="glyphicon glyphicon-time"></i>Activity Log</a></li>
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -94,7 +94,8 @@ var NavbarDropdown = React.createClass({
|
|||||||
<i className="dropdown__icon"></i>
|
<i className="dropdown__icon"></i>
|
||||||
</a>
|
</a>
|
||||||
<ul className="dropdown-menu" role="menu">
|
<ul className="dropdown-menu" role="menu">
|
||||||
<li><a href="#" data-toggle="modal" data-target="#settings_modal">Account Settings</a></li>
|
<li><a href="#" data-toggle="modal" data-target="#user_settings1">Account Settings</a></li>
|
||||||
|
{ isAdmin ? <li><a href="#" data-toggle="modal" data-target="#team_settings">Team Settings</a></li> : "" }
|
||||||
{ invite_link }
|
{ invite_link }
|
||||||
{ team_link }
|
{ team_link }
|
||||||
{ manage_link }
|
{ manage_link }
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
<div className="nav-pills__container">
|
<div className="nav-pills__container">
|
||||||
<ul className="nav nav-pills nav-stacked">
|
<ul className="nav nav-pills nav-stacked">
|
||||||
<li><a href="#" data-toggle="modal" data-target="#settings_modal"><i className="glyphicon glyphicon-cog"></i>Account Settings</a></li>
|
<li><a href="#" data-toggle="modal" data-target="#user_settings1"><i className="glyphicon glyphicon-cog"></i>Account Settings</a></li>
|
||||||
{ invite_link }
|
{ invite_link }
|
||||||
{ team_link }
|
{ team_link }
|
||||||
{ manage_link }
|
{ manage_link }
|
||||||
|
|||||||
161
web/react/components/team_settings.jsx
Обычный файл
161
web/react/components/team_settings.jsx
Обычный файл
@@ -0,0 +1,161 @@
|
|||||||
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
|
var TeamStore = require('../stores/team_store.jsx');
|
||||||
|
var SettingItemMin = require('./setting_item_min.jsx');
|
||||||
|
var SettingItemMax = require('./setting_item_max.jsx');
|
||||||
|
var SettingPicture = require('./setting_picture.jsx');
|
||||||
|
var utils = require('../utils/utils.jsx');
|
||||||
|
|
||||||
|
var client = require('../utils/client.jsx');
|
||||||
|
var AsyncClient = require('../utils/async_client.jsx');
|
||||||
|
var Constants = require('../utils/constants.jsx');
|
||||||
|
|
||||||
|
var FeatureTab = React.createClass({
|
||||||
|
submitValetFeature: function() {
|
||||||
|
data = {};
|
||||||
|
data['allow_valet'] = this.state.allow_valet;
|
||||||
|
|
||||||
|
client.updateValetFeature(data,
|
||||||
|
function(data) {
|
||||||
|
this.props.updateSection("");
|
||||||
|
AsyncClient.getMyTeam();
|
||||||
|
}.bind(this),
|
||||||
|
function(err) {
|
||||||
|
state = this.getInitialState();
|
||||||
|
state.server_error = err;
|
||||||
|
this.setState(state);
|
||||||
|
}.bind(this)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
handleValetRadio: function(val) {
|
||||||
|
this.setState({ allow_valet: val });
|
||||||
|
this.refs.wrapper.getDOMNode().focus();
|
||||||
|
},
|
||||||
|
componentWillReceiveProps: function(newProps) {
|
||||||
|
var team = newProps.team;
|
||||||
|
|
||||||
|
var allow_valet = "false";
|
||||||
|
if (team && team.allow_valet) {
|
||||||
|
allow_valet = "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ allow_valet: allow_valet });
|
||||||
|
},
|
||||||
|
getInitialState: function() {
|
||||||
|
var team = this.props.team;
|
||||||
|
|
||||||
|
var allow_valet = "false";
|
||||||
|
if (team && team.allow_valet) {
|
||||||
|
allow_valet = "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
return { allow_valet: allow_valet };
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var team = this.props.team;
|
||||||
|
|
||||||
|
var client_error = this.state.client_error ? this.state.client_error : null;
|
||||||
|
var server_error = this.state.server_error ? this.state.server_error : null;
|
||||||
|
|
||||||
|
var valetSection;
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (this.props.activeSection === 'valet') {
|
||||||
|
var valetActive = ["",""];
|
||||||
|
if (this.state.allow_valet === "false") {
|
||||||
|
valetActive[1] = "active";
|
||||||
|
} else {
|
||||||
|
valetActive[0] = "active";
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputs = [];
|
||||||
|
|
||||||
|
inputs.push(
|
||||||
|
<div className="col-sm-12">
|
||||||
|
<div className="btn-group" data-toggle="buttons-radio">
|
||||||
|
<button className={"btn btn-default "+valetActive[0]} onClick={function(){self.handleValetRadio("true")}}>On</button>
|
||||||
|
<button className={"btn btn-default "+valetActive[1]} onClick={function(){self.handleValetRadio("false")}}>Off</button>
|
||||||
|
</div>
|
||||||
|
<div><br/>Warning: Turning on the Valet feature and using it with any third party software increases the risk of a security breach.</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
valetSection = (
|
||||||
|
<SettingItemMax
|
||||||
|
title="Valet"
|
||||||
|
inputs={inputs}
|
||||||
|
submit={this.submitValetFeature}
|
||||||
|
server_error={server_error}
|
||||||
|
client_error={client_error}
|
||||||
|
updateSection={function(e){self.props.updateSection("");e.preventDefault();}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
var describe = "";
|
||||||
|
if (this.state.allow_valet === "false") {
|
||||||
|
describe = "Off";
|
||||||
|
} else {
|
||||||
|
describe = "On";
|
||||||
|
}
|
||||||
|
|
||||||
|
valetSection = (
|
||||||
|
<SettingItemMin
|
||||||
|
title="Valet"
|
||||||
|
describe={describe}
|
||||||
|
updateSection={function(){self.props.updateSection("valet");}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="modal-header">
|
||||||
|
<button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 className="modal-title" ref="title"><i className="modal-back"></i>General Settings</h4>
|
||||||
|
</div>
|
||||||
|
<div ref="wrapper" className="user-settings">
|
||||||
|
<h3 className="tab-header">Feature Settings</h3>
|
||||||
|
<div className="divider-dark first"/>
|
||||||
|
{valetSection}
|
||||||
|
<div className="divider-dark"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
componentDidMount: function() {
|
||||||
|
TeamStore.addChangeListener(this._onChange);
|
||||||
|
},
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
TeamStore.removeChangeListener(this._onChange);
|
||||||
|
},
|
||||||
|
_onChange: function () {
|
||||||
|
var team = TeamStore.getCurrent();
|
||||||
|
if (!utils.areStatesEqual(this.state.team, team)) {
|
||||||
|
this.setState({ team: team });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getInitialState: function() {
|
||||||
|
return { team: TeamStore.getCurrent() };
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
if (this.props.activeTab === 'general') {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else if (this.props.activeTab === 'feature') {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<FeatureTab team={this.state.team} activeSection={this.props.activeSection} updateSection={this.props.updateSection} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <div/>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
var SettingsSidebar = require('./settings_sidebar.jsx');
|
var SettingsSidebar = require('./settings_sidebar.jsx');
|
||||||
var UserSettings = require('./user_settings.jsx');
|
var TeamSettings = require('./team_settings.jsx');
|
||||||
|
|
||||||
module.exports = React.createClass({
|
module.exports = React.createClass({
|
||||||
componentDidMount: function() {
|
componentDidMount: function() {
|
||||||
@@ -22,27 +22,31 @@ module.exports = React.createClass({
|
|||||||
this.setState({ active_section: section });
|
this.setState({ active_section: section });
|
||||||
},
|
},
|
||||||
getInitialState: function() {
|
getInitialState: function() {
|
||||||
return { active_tab: "general", active_section: "" };
|
return { active_tab: "feature", active_section: "" };
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
|
var tabs = [];
|
||||||
|
tabs.push({name: "feature", ui_name: "Features", icon: "glyphicon glyphicon-wrench"});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="modal fade" ref="modal" id="settings_modal" role="dialog" aria-hidden="true">
|
<div className="modal fade" ref="modal" id="team_settings" role="dialog" aria-hidden="true">
|
||||||
<div className="modal-dialog settings-modal">
|
<div className="modal-dialog settings-modal">
|
||||||
<div className="modal-content">
|
<div className="modal-content">
|
||||||
<div className="modal-header">
|
<div className="modal-header">
|
||||||
<button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
<h4 className="modal-title" ref="title">Account Settings</h4>
|
<h4 className="modal-title" ref="title">Team Settings</h4>
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-body">
|
<div className="modal-body">
|
||||||
<div className="settings-table">
|
<div className="settings-table">
|
||||||
<div className="settings-links">
|
<div className="settings-links">
|
||||||
<SettingsSidebar
|
<SettingsSidebar
|
||||||
|
tabs={tabs}
|
||||||
activeTab={this.state.active_tab}
|
activeTab={this.state.active_tab}
|
||||||
updateTab={this.updateTab}
|
updateTab={this.updateTab}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="settings-content">
|
<div className="settings-content">
|
||||||
<UserSettings
|
<TeamSettings
|
||||||
activeTab={this.state.active_tab}
|
activeTab={this.state.active_tab}
|
||||||
activeSection={this.state.active_section}
|
activeSection={this.state.active_section}
|
||||||
updateSection={this.updateSection}
|
updateSection={this.updateSection}
|
||||||
68
web/react/components/user_settings_modal.jsx
Обычный файл
68
web/react/components/user_settings_modal.jsx
Обычный файл
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
var SettingsSidebar = require('./settings_sidebar.jsx');
|
||||||
|
var UserSettings = require('./user_settings.jsx');
|
||||||
|
|
||||||
|
module.exports = React.createClass({
|
||||||
|
componentDidMount: function() {
|
||||||
|
$('body').on('click', '.modal-back', function(){
|
||||||
|
$(this).closest('.modal-dialog').removeClass('display--content');
|
||||||
|
});
|
||||||
|
$('body').on('click', '.modal-header .close', function(){
|
||||||
|
setTimeout(function() {
|
||||||
|
$('.modal-dialog.display--content').removeClass('display--content');
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateTab: function(tab) {
|
||||||
|
this.setState({ active_tab: tab });
|
||||||
|
},
|
||||||
|
updateSection: function(section) {
|
||||||
|
this.setState({ active_section: section });
|
||||||
|
},
|
||||||
|
getInitialState: function() {
|
||||||
|
return { active_tab: "general", active_section: "" };
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
var tabs = [];
|
||||||
|
tabs.push({name: "general", ui_name: "General", icon: "glyphicon glyphicon-cog"});
|
||||||
|
tabs.push({name: "security", ui_name: "Security", icon: "glyphicon glyphicon-lock"});
|
||||||
|
tabs.push({name: "notifications", ui_name: "Notifications", icon: "glyphicon glyphicon-exclamation-sign"});
|
||||||
|
tabs.push({name: "appearance", ui_name: "Appearance", icon: "glyphicon glyphicon-wrench"});
|
||||||
|
//tabs.push({name: "sessions", ui_name: "Sessions", icon: "glyphicon glyphicon-globe"});
|
||||||
|
//tabs.push({name: "activity_log", ui_name: "Activity Log", icon: "glyphicon glyphicon-time"});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="modal fade" ref="modal" id="user_settings1" role="dialog" aria-hidden="true">
|
||||||
|
<div className="modal-dialog settings-modal">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-header">
|
||||||
|
<button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 className="modal-title" ref="title">Account Settings</h4>
|
||||||
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
<div className="settings-table">
|
||||||
|
<div className="settings-links">
|
||||||
|
<SettingsSidebar
|
||||||
|
tabs={tabs}
|
||||||
|
activeTab={this.state.active_tab}
|
||||||
|
updateTab={this.updateTab}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="settings-content">
|
||||||
|
<UserSettings
|
||||||
|
activeTab={this.state.active_tab}
|
||||||
|
activeSection={this.state.active_section}
|
||||||
|
updateSection={this.updateSection}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@@ -22,7 +22,8 @@ var MoreChannelsModal = require('../components/more_channels.jsx');
|
|||||||
var NewChannelModal = require('../components/new_channel.jsx');
|
var NewChannelModal = require('../components/new_channel.jsx');
|
||||||
var PostDeletedModal = require('../components/post_deleted_modal.jsx');
|
var PostDeletedModal = require('../components/post_deleted_modal.jsx');
|
||||||
var ChannelNotificationsModal = require('../components/channel_notifications.jsx');
|
var ChannelNotificationsModal = require('../components/channel_notifications.jsx');
|
||||||
var UserSettingsModal = require('../components/settings_modal.jsx');
|
var UserSettingsModal = require('../components/user_settings_modal.jsx');
|
||||||
|
var TeamSettingsModal = require('../components/team_settings_modal.jsx');
|
||||||
var ChannelMembersModal = require('../components/channel_members.jsx');
|
var ChannelMembersModal = require('../components/channel_members.jsx');
|
||||||
var ChannelInviteModal = require('../components/channel_invite_modal.jsx');
|
var ChannelInviteModal = require('../components/channel_invite_modal.jsx');
|
||||||
var TeamMembersModal = require('../components/team_members.jsx');
|
var TeamMembersModal = require('../components/team_members.jsx');
|
||||||
@@ -36,7 +37,7 @@ var ChannelInfoModal = require('../components/channel_info_modal.jsx');
|
|||||||
var Constants = require('../utils/constants.jsx');
|
var Constants = require('../utils/constants.jsx');
|
||||||
var ActionTypes = Constants.ActionTypes;
|
var ActionTypes = Constants.ActionTypes;
|
||||||
|
|
||||||
global.window.setup_channel_page = function(team_name, team_type, channel_name, channel_id) {
|
global.window.setup_channel_page = function(team_name, team_type, team_id, channel_name, channel_id) {
|
||||||
|
|
||||||
AppDispatcher.handleViewAction({
|
AppDispatcher.handleViewAction({
|
||||||
type: ActionTypes.CLICK_CHANNEL,
|
type: ActionTypes.CLICK_CHANNEL,
|
||||||
@@ -44,6 +45,11 @@ global.window.setup_channel_page = function(team_name, team_type, channel_name,
|
|||||||
id: channel_id
|
id: channel_id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AppDispatcher.handleViewAction({
|
||||||
|
type: ActionTypes.CLICK_TEAM,
|
||||||
|
id: team_id
|
||||||
|
});
|
||||||
|
|
||||||
React.render(
|
React.render(
|
||||||
<ErrorBar/>,
|
<ErrorBar/>,
|
||||||
document.getElementById('error_bar')
|
document.getElementById('error_bar')
|
||||||
@@ -79,6 +85,11 @@ global.window.setup_channel_page = function(team_name, team_type, channel_name,
|
|||||||
document.getElementById('user_settings_modal')
|
document.getElementById('user_settings_modal')
|
||||||
);
|
);
|
||||||
|
|
||||||
|
React.render(
|
||||||
|
<TeamSettingsModal />,
|
||||||
|
document.getElementById('team_settings_modal')
|
||||||
|
);
|
||||||
|
|
||||||
React.render(
|
React.render(
|
||||||
<TeamMembersModal teamName={team_name} />,
|
<TeamMembersModal teamName={team_name} />,
|
||||||
document.getElementById('team_members_modal')
|
document.getElementById('team_members_modal')
|
||||||
|
|||||||
100
web/react/stores/team_store.jsx
Обычный файл
100
web/react/stores/team_store.jsx
Обычный файл
@@ -0,0 +1,100 @@
|
|||||||
|
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||||
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
var assign = require('object-assign');
|
||||||
|
|
||||||
|
var Constants = require('../utils/constants.jsx');
|
||||||
|
var ActionTypes = Constants.ActionTypes;
|
||||||
|
|
||||||
|
|
||||||
|
var CHANGE_EVENT = 'change';
|
||||||
|
|
||||||
|
var TeamStore = assign({}, EventEmitter.prototype, {
|
||||||
|
emitChange: function() {
|
||||||
|
this.emit(CHANGE_EVENT);
|
||||||
|
},
|
||||||
|
addChangeListener: function(callback) {
|
||||||
|
this.on(CHANGE_EVENT, callback);
|
||||||
|
},
|
||||||
|
removeChangeListener: function(callback) {
|
||||||
|
this.removeListener(CHANGE_EVENT, callback);
|
||||||
|
},
|
||||||
|
get: function(id) {
|
||||||
|
var c = this._getTeams();
|
||||||
|
return c[id];
|
||||||
|
},
|
||||||
|
getByName: function(name) {
|
||||||
|
var current = null;
|
||||||
|
var t = this._getTeams();
|
||||||
|
|
||||||
|
for (id in t) {
|
||||||
|
if (t[id].name == name) {
|
||||||
|
return t[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
getAll: function() {
|
||||||
|
return this._getTeams();
|
||||||
|
},
|
||||||
|
setCurrentId: function(id) {
|
||||||
|
if (id == null)
|
||||||
|
sessionStorage.removeItem("current_team_id");
|
||||||
|
else
|
||||||
|
sessionStorage.setItem("current_team_id", id);
|
||||||
|
},
|
||||||
|
getCurrentId: function() {
|
||||||
|
return sessionStorage.getItem("current_team_id");
|
||||||
|
},
|
||||||
|
getCurrent: function() {
|
||||||
|
var currentId = TeamStore.getCurrentId();
|
||||||
|
|
||||||
|
if (currentId != null)
|
||||||
|
return this.get(currentId);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
storeTeam: function(team) {
|
||||||
|
var teams = this._getTeams();
|
||||||
|
teams[team.id] = team;
|
||||||
|
this._storeTeams(teams);
|
||||||
|
},
|
||||||
|
_storeTeams: function(teams) {
|
||||||
|
sessionStorage.setItem("user_teams", JSON.stringify(teams));
|
||||||
|
},
|
||||||
|
_getTeams: function() {
|
||||||
|
var teams = {};
|
||||||
|
|
||||||
|
try {
|
||||||
|
teams = JSON.parse(sessionStorage.user_teams);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return teams;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
TeamStore.dispatchToken = AppDispatcher.register(function(payload) {
|
||||||
|
var action = payload.action;
|
||||||
|
|
||||||
|
switch(action.type) {
|
||||||
|
|
||||||
|
case ActionTypes.CLICK_TEAM:
|
||||||
|
TeamStore.setCurrentId(action.id);
|
||||||
|
TeamStore.emitChange();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ActionTypes.RECIEVED_TEAM:
|
||||||
|
TeamStore.storeTeam(action.team);
|
||||||
|
TeamStore.emitChange();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = TeamStore;
|
||||||
@@ -357,3 +357,25 @@ module.exports.getStatuses = function() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports.getMyTeam = function() {
|
||||||
|
if (isCallInProgress("getMyTeam")) return;
|
||||||
|
|
||||||
|
callTracker["getMyTeam"] = utils.getTimestamp();
|
||||||
|
client.getMyTeam(
|
||||||
|
function(data, textStatus, xhr) {
|
||||||
|
callTracker["getMyTeam"] = 0;
|
||||||
|
|
||||||
|
if (xhr.status === 304 || !data) return;
|
||||||
|
|
||||||
|
AppDispatcher.handleServerAction({
|
||||||
|
type: ActionTypes.RECIEVED_TEAM,
|
||||||
|
team: data
|
||||||
|
});
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
callTracker["getMyTeam"] = 0;
|
||||||
|
dispatchError(err, "getMyTeam");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -811,3 +811,34 @@ module.exports.getStatuses = function(success, error) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports.getMyTeam = function(success, error) {
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/v1/teams/me",
|
||||||
|
dataType: 'json',
|
||||||
|
type: 'GET',
|
||||||
|
success: success,
|
||||||
|
ifModified: true,
|
||||||
|
error: function(xhr, status, err) {
|
||||||
|
e = handleError("getMyTeam", xhr, status, err);
|
||||||
|
error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.updateValetFeature = function(data, success, error) {
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/v1/teams/update_valet_feature",
|
||||||
|
dataType: 'json',
|
||||||
|
contentType: 'application/json',
|
||||||
|
type: 'POST',
|
||||||
|
data: JSON.stringify(data),
|
||||||
|
success: success,
|
||||||
|
error: function(xhr, status, err) {
|
||||||
|
e = handleError("updateValetFeature", xhr, status, err);
|
||||||
|
error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports.track('api', 'api_teams_update_valet_feature');
|
||||||
|
};
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ module.exports = {
|
|||||||
RECIEVED_STATUSES: null,
|
RECIEVED_STATUSES: null,
|
||||||
|
|
||||||
RECIEVED_MSG: null,
|
RECIEVED_MSG: null,
|
||||||
|
|
||||||
|
CLICK_TEAM: null,
|
||||||
|
RECIEVED_TEAM: null,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
PayloadSources: keyMirror({
|
PayloadSources: keyMirror({
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
<div id="edit_mention_tab"></div>
|
<div id="edit_mention_tab"></div>
|
||||||
<div id="get_link_modal"></div>
|
<div id="get_link_modal"></div>
|
||||||
<div id="user_settings_modal"></div>
|
<div id="user_settings_modal"></div>
|
||||||
|
<div id="team_settings_modal"></div>
|
||||||
<div id="invite_member_modal"></div>
|
<div id="invite_member_modal"></div>
|
||||||
<div id="edit_channel_modal"></div>
|
<div id="edit_channel_modal"></div>
|
||||||
<div id="delete_channel_modal"></div>
|
<div id="delete_channel_modal"></div>
|
||||||
@@ -43,7 +44,7 @@
|
|||||||
<div id="direct_channel_modal"></div>
|
<div id="direct_channel_modal"></div>
|
||||||
<div id="channel_info_modal"></div>
|
<div id="channel_info_modal"></div>
|
||||||
<script>
|
<script>
|
||||||
window.setup_channel_page('{{ .Props.TeamName }}', '{{ .Props.TeamType }}', '{{ .Props.ChannelName }}', '{{ .Props.ChannelId }}');
|
window.setup_channel_page('{{ .Props.TeamName }}', '{{ .Props.TeamType }}', '{{ .Props.TeamId }}', '{{ .Props.ChannelName }}', '{{ .Props.ChannelId }}');
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ func getChannel(c *api.Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
page.Title = name + " - " + team.Name + " " + page.SiteName
|
page.Title = name + " - " + team.Name + " " + page.SiteName
|
||||||
page.Props["TeamName"] = team.Name
|
page.Props["TeamName"] = team.Name
|
||||||
page.Props["TeamType"] = team.Type
|
page.Props["TeamType"] = team.Type
|
||||||
|
page.Props["TeamId"] = team.Id
|
||||||
page.Props["ChannelName"] = name
|
page.Props["ChannelName"] = name
|
||||||
page.Props["ChannelId"] = channelId
|
page.Props["ChannelId"] = channelId
|
||||||
page.Props["UserId"] = c.Session.UserId
|
page.Props["UserId"] = c.Session.UserId
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user