Merge branch 'master' of https://github.com/mattermost/platform into ui-improvements
Этот коммит содержится в:
@@ -14,11 +14,22 @@ func InitPreference(r *mux.Router) {
|
|||||||
l4g.Debug("Initializing preference api routes")
|
l4g.Debug("Initializing preference api routes")
|
||||||
|
|
||||||
sr := r.PathPrefix("/preferences").Subrouter()
|
sr := r.PathPrefix("/preferences").Subrouter()
|
||||||
|
sr.Handle("/", ApiUserRequired(getAllPreferences)).Methods("GET")
|
||||||
sr.Handle("/save", ApiUserRequired(savePreferences)).Methods("POST")
|
sr.Handle("/save", ApiUserRequired(savePreferences)).Methods("POST")
|
||||||
sr.Handle("/{category:[A-Za-z0-9_]+}", ApiUserRequired(getPreferenceCategory)).Methods("GET")
|
sr.Handle("/{category:[A-Za-z0-9_]+}", ApiUserRequired(getPreferenceCategory)).Methods("GET")
|
||||||
sr.Handle("/{category:[A-Za-z0-9_]+}/{name:[A-Za-z0-9_]+}", ApiUserRequired(getPreference)).Methods("GET")
|
sr.Handle("/{category:[A-Za-z0-9_]+}/{name:[A-Za-z0-9_]+}", ApiUserRequired(getPreference)).Methods("GET")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAllPreferences(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if result := <-Srv.Store.Preference().GetAll(c.Session.UserId); result.Err != nil {
|
||||||
|
c.Err = result.Err
|
||||||
|
} else {
|
||||||
|
data := result.Data.(model.Preferences)
|
||||||
|
|
||||||
|
w.Write([]byte(data.ToJson()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func savePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
|
func savePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
preferences, err := model.PreferencesFromJson(r.Body)
|
preferences, err := model.PreferencesFromJson(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -52,61 +63,10 @@ func getPreferenceCategory(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
} else {
|
} else {
|
||||||
data := result.Data.(model.Preferences)
|
data := result.Data.(model.Preferences)
|
||||||
|
|
||||||
data = transformPreferences(c, data, category)
|
|
||||||
|
|
||||||
w.Write([]byte(data.ToJson()))
|
w.Write([]byte(data.ToJson()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func transformPreferences(c *Context, preferences model.Preferences, category string) model.Preferences {
|
|
||||||
if len(preferences) == 0 && category == model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW {
|
|
||||||
// add direct channels for a user that existed before preferences were added
|
|
||||||
preferences = addDirectChannels(c.Session.UserId, c.Session.TeamId)
|
|
||||||
}
|
|
||||||
|
|
||||||
return preferences
|
|
||||||
}
|
|
||||||
|
|
||||||
func addDirectChannels(userId, teamId string) model.Preferences {
|
|
||||||
var profiles map[string]*model.User
|
|
||||||
if result := <-Srv.Store.User().GetProfiles(teamId); result.Err != nil {
|
|
||||||
l4g.Error("Failed to add direct channel preferences for user user_id=%s, team_id=%s, err=%v", userId, teamId, result.Err.Error())
|
|
||||||
return model.Preferences{}
|
|
||||||
} else {
|
|
||||||
profiles = result.Data.(map[string]*model.User)
|
|
||||||
}
|
|
||||||
|
|
||||||
var preferences model.Preferences
|
|
||||||
|
|
||||||
for id := range profiles {
|
|
||||||
if id == userId {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
profile := profiles[id]
|
|
||||||
|
|
||||||
preference := model.Preference{
|
|
||||||
UserId: userId,
|
|
||||||
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
|
|
||||||
Name: profile.Id,
|
|
||||||
Value: "true",
|
|
||||||
}
|
|
||||||
|
|
||||||
preferences = append(preferences, preference)
|
|
||||||
|
|
||||||
if len(preferences) >= 10 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if result := <-Srv.Store.Preference().Save(&preferences); result.Err != nil {
|
|
||||||
l4g.Error("Failed to add direct channel preferences for user user_id=%s, eam_id=%s, err=%v", userId, teamId, result.Err.Error())
|
|
||||||
return model.Preferences{}
|
|
||||||
} else {
|
|
||||||
return preferences
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPreference(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getPreference(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
params := mux.Vars(r)
|
params := mux.Vars(r)
|
||||||
category := params["category"]
|
category := params["category"]
|
||||||
|
|||||||
@@ -9,6 +9,64 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestGetAllPreferences(t *testing.T) {
|
||||||
|
Setup()
|
||||||
|
|
||||||
|
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
||||||
|
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
||||||
|
|
||||||
|
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||||
|
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
||||||
|
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
||||||
|
|
||||||
|
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
||||||
|
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
||||||
|
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
||||||
|
|
||||||
|
category := model.NewId()
|
||||||
|
|
||||||
|
preferences1 := model.Preferences{
|
||||||
|
{
|
||||||
|
UserId: user1.Id,
|
||||||
|
Category: category,
|
||||||
|
Name: model.NewId(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
UserId: user1.Id,
|
||||||
|
Category: category,
|
||||||
|
Name: model.NewId(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
UserId: user1.Id,
|
||||||
|
Category: model.NewId(),
|
||||||
|
Name: model.NewId(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Client.LoginByEmail(team.Name, user1.Email, "pwd")
|
||||||
|
Client.Must(Client.SetPreferences(&preferences1))
|
||||||
|
|
||||||
|
if result, err := Client.GetAllPreferences(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if data := result.Data.(model.Preferences); len(data) != 3 {
|
||||||
|
t.Fatal("received the wrong number of preferences")
|
||||||
|
} else if !((data[0] == preferences1[0] && data[1] == preferences1[1]) || (data[0] == preferences1[1] && data[1] == preferences1[0])) {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
if data[0] != preferences1[i] && data[1] != preferences1[i] && data[2] != preferences1[i] {
|
||||||
|
t.Fatal("got incorrect preferences")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Client.LoginByEmail(team.Name, user2.Email, "pwd")
|
||||||
|
|
||||||
|
if result, err := Client.GetAllPreferences(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if data := result.Data.(model.Preferences); len(data) != 0 {
|
||||||
|
t.Fatal("received the wrong number of preferences")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSetPreferences(t *testing.T) {
|
func TestSetPreferences(t *testing.T) {
|
||||||
Setup()
|
Setup()
|
||||||
|
|
||||||
@@ -113,54 +171,6 @@ func TestGetPreferenceCategory(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTransformPreferences(t *testing.T) {
|
|
||||||
Setup()
|
|
||||||
|
|
||||||
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
|
|
||||||
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
|
|
||||||
|
|
||||||
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
|
||||||
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
|
|
||||||
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
|
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
|
||||||
Client.Must(Client.CreateUser(user, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
Client.Must(Client.LoginByEmail(team.Name, user1.Email, "pwd"))
|
|
||||||
|
|
||||||
if result, err := Client.GetPreferenceCategory(model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else if data := result.Data.(model.Preferences); len(data) != 5 {
|
|
||||||
t.Fatal("received the wrong number of direct channels")
|
|
||||||
}
|
|
||||||
|
|
||||||
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
|
||||||
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
|
|
||||||
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
|
|
||||||
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
|
|
||||||
Client.Must(Client.CreateUser(user, ""))
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure user1's preferences don't change
|
|
||||||
if result, err := Client.GetPreferenceCategory(model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else if data := result.Data.(model.Preferences); len(data) != 5 {
|
|
||||||
t.Fatal("received the wrong number of direct channels")
|
|
||||||
}
|
|
||||||
|
|
||||||
Client.Must(Client.LoginByEmail(team.Name, user2.Email, "pwd"))
|
|
||||||
|
|
||||||
if result, err := Client.GetPreferenceCategory(model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
} else if data := result.Data.(model.Preferences); len(data) != 10 {
|
|
||||||
t.Fatal("received the wrong number of direct channels")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetPreference(t *testing.T) {
|
func TestGetPreference(t *testing.T) {
|
||||||
Setup()
|
Setup()
|
||||||
|
|
||||||
|
|||||||
23
api/team.go
23
api/team.go
@@ -52,7 +52,7 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isTreamCreationAllowed(c, email) {
|
if !isTeamCreationAllowed(c, email) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ func createTeamFromSSO(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isTreamCreationAllowed(c, team.Email) {
|
if !isTeamCreationAllowed(c, team.Email) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isTreamCreationAllowed(c, teamSignup.Team.Email) {
|
if !isTeamCreationAllowed(c, teamSignup.Team.Email) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ func CreateTeam(c *Context, team *model.Team) *model.Team {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isTreamCreationAllowed(c, team.Email) {
|
if !isTeamCreationAllowed(c, team.Email) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,12 +276,12 @@ func CreateTeam(c *Context, team *model.Team) *model.Team {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTreamCreationAllowed(c *Context, email string) bool {
|
func isTeamCreationAllowed(c *Context, email string) bool {
|
||||||
|
|
||||||
email = strings.ToLower(email)
|
email = strings.ToLower(email)
|
||||||
|
|
||||||
if !utils.Cfg.TeamSettings.EnableTeamCreation {
|
if !utils.Cfg.TeamSettings.EnableTeamCreation {
|
||||||
c.Err = model.NewAppError("isTreamCreationAllowed", "Team creation has been disabled. Please ask your systems administrator for details.", "")
|
c.Err = model.NewAppError("isTeamCreationAllowed", "Team creation has been disabled. Please ask your systems administrator for details.", "")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,7 +298,7 @@ func isTreamCreationAllowed(c *Context, email string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(utils.Cfg.TeamSettings.RestrictCreationToDomains) > 0 && !matched {
|
if len(utils.Cfg.TeamSettings.RestrictCreationToDomains) > 0 && !matched {
|
||||||
c.Err = model.NewAppError("isTreamCreationAllowed", "Email must be from a specific domain (e.g. @example.com). Please ask your systems administrator for details.", "")
|
c.Err = model.NewAppError("isTeamCreationAllowed", "Email must be from a specific domain (e.g. @example.com). Please ask your systems administrator for details.", "")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,14 +409,13 @@ func findTeams(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
teams := result.Data.([]*model.Team)
|
teams := result.Data.([]*model.Team)
|
||||||
|
m := make(map[string]*model.Team)
|
||||||
s := make([]string, 0, len(teams))
|
|
||||||
|
|
||||||
for _, v := range teams {
|
for _, v := range teams {
|
||||||
s = append(s, v.Name)
|
v.Sanitize()
|
||||||
|
m[v.Id] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Write([]byte(model.ArrayToJson(s)))
|
w.Write([]byte(model.TeamMapToJson(m)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,9 +121,12 @@ func TestFindTeamByEmail(t *testing.T) {
|
|||||||
if r1, err := Client.FindTeams(user.Email); err != nil {
|
if r1, err := Client.FindTeams(user.Email); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
domains := r1.Data.([]string)
|
teams := r1.Data.(map[string]*model.Team)
|
||||||
if domains[0] != team.Name {
|
if teams[team.Id].Name != team.Name {
|
||||||
t.Fatal(domains)
|
t.Fatal()
|
||||||
|
}
|
||||||
|
if teams[team.Id].DisplayName != team.DisplayName {
|
||||||
|
t.Fatal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
43
api/user.go
43
api/user.go
@@ -198,7 +198,9 @@ func CreateUser(c *Context, team *model.Team, user *model.User) *model.User {
|
|||||||
l4g.Error("Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v", ruser.Id, ruser.TeamId, err)
|
l4g.Error("Encountered an issue joining default channels user_id=%s, team_id=%s, err=%v", ruser.Id, ruser.TeamId, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fireAndForgetWelcomeEmail(result.Data.(*model.User).Id, ruser.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team), user.EmailVerified)
|
fireAndForgetWelcomeEmail(ruser.Id, ruser.Email, team.Name, team.DisplayName, c.GetSiteURL(), c.GetTeamURLFromTeam(team), user.EmailVerified)
|
||||||
|
|
||||||
|
addDirectChannelsAndForget(ruser)
|
||||||
|
|
||||||
if user.EmailVerified {
|
if user.EmailVerified {
|
||||||
if cresult := <-Srv.Store.User().VerifyEmail(ruser.Id); cresult.Err != nil {
|
if cresult := <-Srv.Store.User().VerifyEmail(ruser.Id); cresult.Err != nil {
|
||||||
@@ -237,6 +239,45 @@ func fireAndForgetWelcomeEmail(userId, email, teamName, teamDisplayName, siteURL
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addDirectChannelsAndForget(user *model.User) {
|
||||||
|
go func() {
|
||||||
|
var profiles map[string]*model.User
|
||||||
|
if result := <-Srv.Store.User().GetProfiles(user.TeamId); result.Err != nil {
|
||||||
|
l4g.Error("Failed to add direct channel preferences for user user_id=%s, team_id=%s, err=%v", user.Id, user.TeamId, result.Err.Error())
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
profiles = result.Data.(map[string]*model.User)
|
||||||
|
}
|
||||||
|
|
||||||
|
var preferences model.Preferences
|
||||||
|
|
||||||
|
for id := range profiles {
|
||||||
|
if id == user.Id {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
profile := profiles[id]
|
||||||
|
|
||||||
|
preference := model.Preference{
|
||||||
|
UserId: user.Id,
|
||||||
|
Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW,
|
||||||
|
Name: profile.Id,
|
||||||
|
Value: "true",
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences = append(preferences, preference)
|
||||||
|
|
||||||
|
if len(preferences) >= 10 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := <-Srv.Store.Preference().Save(&preferences); result.Err != nil {
|
||||||
|
l4g.Error("Failed to add direct channel preferences for new user user_id=%s, eam_id=%s, err=%v", user.Id, user.TeamId, result.Err.Error())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
func FireAndForgetVerifyEmail(userId, userEmail, teamName, teamDisplayName, siteURL, teamURL string) {
|
func FireAndForgetVerifyEmail(userId, userEmail, teamName, teamDisplayName, siteURL, teamURL string) {
|
||||||
go func() {
|
go func() {
|
||||||
|
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
#### Important notes
|
#### Important notes
|
||||||
|
|
||||||
1. **DO NOT manipulate the Mattermost database**
|
1. **DO NOT manipulate the Mattermost database**
|
||||||
- In particular, DO NOT delete data from the database, as this will most likely crash Mattermost in strange ways. Mattermost is designed to archive content continously and generally assumes data is never deleted.
|
- In particular, DO NOT delete data from the database, as Mattermost is designed to stop working if data integrity has been compromised. The system is designed to archive content continously and generally assumes data is never deleted.
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ func (c *Client) FindTeams(email string) (*Result, *AppError) {
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
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), TeamMapFromJson(r.Body)}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,6 +844,15 @@ func (c *Client) ListIncomingWebhooks() (*Result, *AppError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetAllPreferences() (*Result, *AppError) {
|
||||||
|
if r, err := c.DoApiGet("/preferences/", "", ""); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
preferences, _ := PreferencesFromJson(r.Body)
|
||||||
|
return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) SetPreferences(preferences *Preferences) (*Result, *AppError) {
|
func (c *Client) SetPreferences(preferences *Preferences) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/preferences/save", preferences.ToJson()); err != nil {
|
if r, err := c.DoApiPost("/preferences/save", preferences.ToJson()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -219,3 +219,9 @@ func CleanTeamName(s string) string {
|
|||||||
|
|
||||||
func (o *Team) PreExport() {
|
func (o *Team) PreExport() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Team) Sanitize() {
|
||||||
|
o.Email = ""
|
||||||
|
o.Type = ""
|
||||||
|
o.AllowedDomains = ""
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func (s SqlPreferenceStore) Save(preferences *model.Preferences) StoreChannel {
|
|||||||
result := StoreResult{}
|
result := StoreResult{}
|
||||||
|
|
||||||
// wrap in a transaction so that if one fails, everything fails
|
// wrap in a transaction so that if one fails, everything fails
|
||||||
transaction, err := s.GetReplica().Begin()
|
transaction, err := s.GetMaster().Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.Err = model.NewAppError("SqlPreferenceStore.Save", "Unable to open transaction to save preferences", err.Error())
|
result.Err = model.NewAppError("SqlPreferenceStore.Save", "Unable to open transaction to save preferences", err.Error())
|
||||||
} else {
|
} else {
|
||||||
@@ -212,3 +212,30 @@ func (s SqlPreferenceStore) GetCategory(userId string, category string) StoreCha
|
|||||||
|
|
||||||
return storeChannel
|
return storeChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlPreferenceStore) GetAll(userId string) StoreChannel {
|
||||||
|
storeChannel := make(StoreChannel)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
result := StoreResult{}
|
||||||
|
|
||||||
|
var preferences model.Preferences
|
||||||
|
|
||||||
|
if _, err := s.GetReplica().Select(&preferences,
|
||||||
|
`SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
Preferences
|
||||||
|
WHERE
|
||||||
|
UserId = :UserId`, map[string]interface{}{"UserId": userId}); err != nil {
|
||||||
|
result.Err = model.NewAppError("SqlPreferenceStore.GetAll", "We encounted an error while finding preferences", err.Error())
|
||||||
|
} else {
|
||||||
|
result.Data = preferences
|
||||||
|
}
|
||||||
|
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return storeChannel
|
||||||
|
}
|
||||||
|
|||||||
@@ -144,3 +144,51 @@ func TestPreferenceGetCategory(t *testing.T) {
|
|||||||
t.Fatal("shouldn't have got any preferences")
|
t.Fatal("shouldn't have got any preferences")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPreferenceGetAll(t *testing.T) {
|
||||||
|
Setup()
|
||||||
|
|
||||||
|
userId := model.NewId()
|
||||||
|
category := model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW
|
||||||
|
name := model.NewId()
|
||||||
|
|
||||||
|
preferences := model.Preferences{
|
||||||
|
{
|
||||||
|
UserId: userId,
|
||||||
|
Category: category,
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
// same user/category, different name
|
||||||
|
{
|
||||||
|
UserId: userId,
|
||||||
|
Category: category,
|
||||||
|
Name: model.NewId(),
|
||||||
|
},
|
||||||
|
// same user/name, different category
|
||||||
|
{
|
||||||
|
UserId: userId,
|
||||||
|
Category: model.NewId(),
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
// same name/category, different user
|
||||||
|
{
|
||||||
|
UserId: model.NewId(),
|
||||||
|
Category: category,
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Must(store.Preference().Save(&preferences))
|
||||||
|
|
||||||
|
if result := <-store.Preference().GetAll(userId); result.Err != nil {
|
||||||
|
t.Fatal(result.Err)
|
||||||
|
} else if data := result.Data.(model.Preferences); len(data) != 3 {
|
||||||
|
t.Fatal("got the wrong number of preferences")
|
||||||
|
} else {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
if data[0] != preferences[i] && data[1] != preferences[i] && data[2] != preferences[i] {
|
||||||
|
t.Fatal("got incorrect preferences")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -156,4 +156,5 @@ type PreferenceStore interface {
|
|||||||
Save(preferences *model.Preferences) StoreChannel
|
Save(preferences *model.Preferences) StoreChannel
|
||||||
Get(userId string, category string, name string) StoreChannel
|
Get(userId string, category string, name string) StoreChannel
|
||||||
GetCategory(userId string, category string) StoreChannel
|
GetCategory(userId string, category string) StoreChannel
|
||||||
|
GetAll(userId string) StoreChannel
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,24 @@ var AboutBuildModal = require('./about_build_modal.jsx');
|
|||||||
var Constants = require('../utils/constants.jsx');
|
var Constants = require('../utils/constants.jsx');
|
||||||
|
|
||||||
function getStateFromStores() {
|
function getStateFromStores() {
|
||||||
return {teams: UserStore.getTeams()};
|
let teams = [];
|
||||||
|
let teamsObject = UserStore.getTeams();
|
||||||
|
for (let teamId in teamsObject) {
|
||||||
|
if (teamsObject.hasOwnProperty(teamId)) {
|
||||||
|
teams.push(teamsObject[teamId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
teams.sort(function sortByDisplayName(teamA, teamB) {
|
||||||
|
let teamADisplayName = teamA.display_name.toLowerCase();
|
||||||
|
let teamBDisplayName = teamB.display_name.toLowerCase();
|
||||||
|
if (teamADisplayName < teamBDisplayName) {
|
||||||
|
return -1;
|
||||||
|
} else if (teamADisplayName > teamBDisplayName) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
return {teams};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class NavbarDropdown extends React.Component {
|
export default class NavbarDropdown extends React.Component {
|
||||||
@@ -154,9 +171,9 @@ export default class NavbarDropdown extends React.Component {
|
|||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|
||||||
this.state.teams.forEach((teamName) => {
|
this.state.teams.forEach((team) => {
|
||||||
if (teamName !== this.props.teamName) {
|
if (team.name !== this.props.teamName) {
|
||||||
teams.push(<li key={teamName}><a href={Utils.getWindowLocationOrigin() + '/' + teamName}>{'Switch to ' + teamName}</a></li>);
|
teams.push(<li key={team.name}><a href={Utils.getWindowLocationOrigin() + '/' + team.name}>{'Switch to ' + team.display_name}</a></li>);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
var PostStore = require('../stores/post_store.jsx');
|
var PostStore = require('../stores/post_store.jsx');
|
||||||
var ChannelStore = require('../stores/channel_store.jsx');
|
var ChannelStore = require('../stores/channel_store.jsx');
|
||||||
var UserStore = require('../stores/user_store.jsx');
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
|
var PreferenceStore = require('../stores/preference_store.jsx');
|
||||||
var UserProfile = require('./user_profile.jsx');
|
var UserProfile = require('./user_profile.jsx');
|
||||||
var AsyncClient = require('../utils/async_client.jsx');
|
var AsyncClient = require('../utils/async_client.jsx');
|
||||||
var Post = require('./post.jsx');
|
var Post = require('./post.jsx');
|
||||||
@@ -105,6 +106,7 @@ export default class PostList extends React.Component {
|
|||||||
PostStore.clearUnseenDeletedPosts(this.props.channelId);
|
PostStore.clearUnseenDeletedPosts(this.props.channelId);
|
||||||
PostStore.addChangeListener(this.onChange);
|
PostStore.addChangeListener(this.onChange);
|
||||||
UserStore.addStatusesChangeListener(this.onTimeChange);
|
UserStore.addStatusesChangeListener(this.onTimeChange);
|
||||||
|
PreferenceStore.addChangeListener(this.onTimeChange);
|
||||||
SocketStore.addChangeListener(this.onSocketChange);
|
SocketStore.addChangeListener(this.onSocketChange);
|
||||||
|
|
||||||
const postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
|
const postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
|
||||||
@@ -156,6 +158,7 @@ export default class PostList extends React.Component {
|
|||||||
PostStore.removeChangeListener(this.onChange);
|
PostStore.removeChangeListener(this.onChange);
|
||||||
UserStore.removeStatusesChangeListener(this.onTimeChange);
|
UserStore.removeStatusesChangeListener(this.onTimeChange);
|
||||||
SocketStore.removeChangeListener(this.onSocketChange);
|
SocketStore.removeChangeListener(this.onSocketChange);
|
||||||
|
PreferenceStore.removeChangeListener(this.onTimeChange);
|
||||||
$('body').off('click.userpopover');
|
$('body').off('click.userpopover');
|
||||||
$(window).off('resize');
|
$(window).off('resize');
|
||||||
var postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
|
var postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
var PostStore = require('../stores/post_store.jsx');
|
var PostStore = require('../stores/post_store.jsx');
|
||||||
var UserStore = require('../stores/user_store.jsx');
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
|
var PreferenceStore = require('../stores/preference_store.jsx');
|
||||||
var utils = require('../utils/utils.jsx');
|
var utils = require('../utils/utils.jsx');
|
||||||
var SearchBox = require('./search_bar.jsx');
|
var SearchBox = require('./search_bar.jsx');
|
||||||
var CreateComment = require('./create_comment.jsx');
|
var CreateComment = require('./create_comment.jsx');
|
||||||
@@ -18,6 +19,7 @@ export default class RhsThread extends React.Component {
|
|||||||
|
|
||||||
this.onChange = this.onChange.bind(this);
|
this.onChange = this.onChange.bind(this);
|
||||||
this.onChangeAll = this.onChangeAll.bind(this);
|
this.onChangeAll = this.onChangeAll.bind(this);
|
||||||
|
this.forceUpdateInfo = this.forceUpdateInfo.bind(this);
|
||||||
|
|
||||||
this.state = this.getStateFromStores();
|
this.state = this.getStateFromStores();
|
||||||
}
|
}
|
||||||
@@ -43,6 +45,7 @@ export default class RhsThread extends React.Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
PostStore.addSelectedPostChangeListener(this.onChange);
|
PostStore.addSelectedPostChangeListener(this.onChange);
|
||||||
PostStore.addChangeListener(this.onChangeAll);
|
PostStore.addChangeListener(this.onChangeAll);
|
||||||
|
PreferenceStore.addChangeListener(this.forceUpdateInfo);
|
||||||
this.resize();
|
this.resize();
|
||||||
$(window).resize(function resize() {
|
$(window).resize(function resize() {
|
||||||
this.resize();
|
this.resize();
|
||||||
@@ -57,6 +60,16 @@ export default class RhsThread extends React.Component {
|
|||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
PostStore.removeSelectedPostChangeListener(this.onChange);
|
PostStore.removeSelectedPostChangeListener(this.onChange);
|
||||||
PostStore.removeChangeListener(this.onChangeAll);
|
PostStore.removeChangeListener(this.onChangeAll);
|
||||||
|
PreferenceStore.removeChangeListener(this.forceUpdateInfo);
|
||||||
|
}
|
||||||
|
forceUpdateInfo() {
|
||||||
|
if (this.state.postList) {
|
||||||
|
for (var postId in this.state.postList.posts) {
|
||||||
|
if (this.refs[postId]) {
|
||||||
|
this.refs[postId].forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
onChange() {
|
onChange() {
|
||||||
var newState = this.getStateFromStores();
|
var newState = this.getStateFromStores();
|
||||||
@@ -174,6 +187,7 @@ export default class RhsThread extends React.Component {
|
|||||||
/>
|
/>
|
||||||
<div className='post-right__scroll'>
|
<div className='post-right__scroll'>
|
||||||
<RootPost
|
<RootPost
|
||||||
|
ref={rootPost.id}
|
||||||
post={rootPost}
|
post={rootPost}
|
||||||
commentCount={postsArray.length}
|
commentCount={postsArray.length}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -132,11 +132,7 @@ export default class Sidebar extends React.Component {
|
|||||||
SocketStore.addChangeListener(this.onSocketChange);
|
SocketStore.addChangeListener(this.onSocketChange);
|
||||||
PreferenceStore.addChangeListener(this.onChange);
|
PreferenceStore.addChangeListener(this.onChange);
|
||||||
|
|
||||||
AsyncClient.getDirectChannelPreferences();
|
$('.nav-pills__container').perfectScrollbar();
|
||||||
|
|
||||||
if ($(window).width() > 768) {
|
|
||||||
$('.nav-pills__container').perfectScrollbar();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateTitle();
|
this.updateTitle();
|
||||||
this.updateUnreadIndicators();
|
this.updateUnreadIndicators();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ var GeneralTab = require('./user_settings_general.jsx');
|
|||||||
var AppearanceTab = require('./user_settings_appearance.jsx');
|
var AppearanceTab = require('./user_settings_appearance.jsx');
|
||||||
var DeveloperTab = require('./user_settings_developer.jsx');
|
var DeveloperTab = require('./user_settings_developer.jsx');
|
||||||
var IntegrationsTab = require('./user_settings_integrations.jsx');
|
var IntegrationsTab = require('./user_settings_integrations.jsx');
|
||||||
|
var DisplayTab = require('./user_settings_display.jsx');
|
||||||
|
|
||||||
export default class UserSettings extends React.Component {
|
export default class UserSettings extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@@ -98,6 +99,17 @@ export default class UserSettings extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
} else if (this.props.activeTab === 'display') {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<DisplayTab
|
||||||
|
user={this.state.user}
|
||||||
|
activeSection={this.props.activeSection}
|
||||||
|
updateSection={this.props.updateSection}
|
||||||
|
updateTab={this.props.updateTab}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div/>;
|
return <div/>;
|
||||||
|
|||||||
168
web/react/components/user_settings/user_settings_display.jsx
Обычный файл
168
web/react/components/user_settings/user_settings_display.jsx
Обычный файл
@@ -0,0 +1,168 @@
|
|||||||
|
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
import { savePreferences } from '../../utils/client.jsx';
|
||||||
|
import SettingItemMin from '../setting_item_min.jsx';
|
||||||
|
import SettingItemMax from '../setting_item_max.jsx';
|
||||||
|
import Constants from '../../utils/constants.jsx';
|
||||||
|
import PreferenceStore from '../../stores/preference_store.jsx';
|
||||||
|
|
||||||
|
function getDisplayStateFromStores() {
|
||||||
|
const militaryTime = PreferenceStore.getPreference(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', {value: 'false'});
|
||||||
|
|
||||||
|
return {militaryTime: militaryTime.value};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class UserSettingsDisplay extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
|
this.handleClockRadio = this.handleClockRadio.bind(this);
|
||||||
|
this.updateSection = this.updateSection.bind(this);
|
||||||
|
this.handleClose = this.handleClose.bind(this);
|
||||||
|
|
||||||
|
this.state = getDisplayStateFromStores();
|
||||||
|
}
|
||||||
|
handleSubmit() {
|
||||||
|
const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', this.state.militaryTime);
|
||||||
|
|
||||||
|
savePreferences([preference],
|
||||||
|
() => {
|
||||||
|
PreferenceStore.emitChange();
|
||||||
|
this.updateSection('');
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
this.setState({serverError: err.message});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
handleClockRadio(militaryTime) {
|
||||||
|
this.setState({militaryTime: militaryTime});
|
||||||
|
}
|
||||||
|
updateSection(section) {
|
||||||
|
this.setState(getDisplayStateFromStores());
|
||||||
|
this.props.updateSection(section);
|
||||||
|
}
|
||||||
|
handleClose() {
|
||||||
|
this.updateSection('');
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
$('#user_settings').on('hidden.bs.modal', this.handleClose);
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
$('#user_settings').off('hidden.bs.modal', this.handleClose);
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const serverError = this.state.serverError || null;
|
||||||
|
let clockSection;
|
||||||
|
if (this.props.activeSection === 'clock') {
|
||||||
|
let clockFormat = [false, false];
|
||||||
|
if (this.state.militaryTime === 'true') {
|
||||||
|
clockFormat[1] = true;
|
||||||
|
} else {
|
||||||
|
clockFormat[0] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpdateClockSection = (e) => {
|
||||||
|
this.updateSection('');
|
||||||
|
e.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputs = [
|
||||||
|
<div key='userDisplayClockOptions'>
|
||||||
|
<div className='radio'>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
checked={clockFormat[0]}
|
||||||
|
onChange={this.handleClockRadio.bind(this, 'false')}
|
||||||
|
>
|
||||||
|
12-hour clock (example: 4:00 PM)
|
||||||
|
</input>
|
||||||
|
</label>
|
||||||
|
<br/>
|
||||||
|
</div>
|
||||||
|
<div className='radio'>
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type='radio'
|
||||||
|
checked={clockFormat[1]}
|
||||||
|
onChange={this.handleClockRadio.bind(this, 'true')}
|
||||||
|
>
|
||||||
|
24-hour clock (example: 16:00)
|
||||||
|
</input>
|
||||||
|
</label>
|
||||||
|
<br/>
|
||||||
|
</div>
|
||||||
|
<div><br/>{'Select how you prefer time displayed.'}</div>
|
||||||
|
</div>
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
clockSection = (
|
||||||
|
<SettingItemMax
|
||||||
|
title='Clock Display'
|
||||||
|
inputs={inputs}
|
||||||
|
submit={this.handleSubmit}
|
||||||
|
server_error={serverError}
|
||||||
|
updateSection={handleUpdateClockSection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let describe = '';
|
||||||
|
if (this.state.militaryTime === 'true') {
|
||||||
|
describe = '24-hour clock (example: 16:00)';
|
||||||
|
} else {
|
||||||
|
describe = '12-hour clock (example: 4:00 PM)';
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpdateClockSection = () => {
|
||||||
|
this.props.updateSection('clock');
|
||||||
|
};
|
||||||
|
|
||||||
|
clockSection = (
|
||||||
|
<SettingItemMin
|
||||||
|
title='Clock Display'
|
||||||
|
describe={describe}
|
||||||
|
updateSection={handleUpdateClockSection}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
{'Display Settings'}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div className='user-settings'>
|
||||||
|
<h3 className='tab-header'>{'Display Settings'}</h3>
|
||||||
|
<div className='divider-dark first'/>
|
||||||
|
{clockSection}
|
||||||
|
<div className='divider-dark'/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserSettingsDisplay.propTypes = {
|
||||||
|
user: React.PropTypes.object,
|
||||||
|
updateSection: React.PropTypes.func,
|
||||||
|
updateTab: React.PropTypes.func,
|
||||||
|
activeSection: React.PropTypes.string
|
||||||
|
};
|
||||||
@@ -41,6 +41,7 @@ export default class UserSettingsModal extends React.Component {
|
|||||||
if (global.window.config.EnableIncomingWebhooks === 'true') {
|
if (global.window.config.EnableIncomingWebhooks === 'true') {
|
||||||
tabs.push({name: 'integrations', uiName: 'Integrations', icon: 'glyphicon glyphicon-transfer'});
|
tabs.push({name: 'integrations', uiName: 'Integrations', icon: 'glyphicon glyphicon-transfer'});
|
||||||
}
|
}
|
||||||
|
tabs.push({name: 'display', uiName: 'Display', icon: 'glyphicon glyphicon-eye-open'});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ var RegisterAppModal = require('../components/register_app_modal.jsx');
|
|||||||
var ImportThemeModal = require('../components/user_settings/import_theme_modal.jsx');
|
var ImportThemeModal = require('../components/user_settings/import_theme_modal.jsx');
|
||||||
var TeamStore = require('../stores/team_store.jsx');
|
var TeamStore = require('../stores/team_store.jsx');
|
||||||
|
|
||||||
|
var AsyncClient = require('../utils/async_client.jsx');
|
||||||
var Constants = require('../utils/constants.jsx');
|
var Constants = require('../utils/constants.jsx');
|
||||||
var ActionTypes = Constants.ActionTypes;
|
var ActionTypes = Constants.ActionTypes;
|
||||||
|
|
||||||
@@ -54,6 +55,8 @@ function setupChannelPage(props) {
|
|||||||
id: props.TeamId
|
id: props.TeamId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AsyncClient.getAllPreferences();
|
||||||
|
|
||||||
// ChannelLoader must be rendered first
|
// ChannelLoader must be rendered first
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<ChannelLoader/>,
|
<ChannelLoader/>,
|
||||||
|
|||||||
@@ -120,3 +120,4 @@ class PreferenceStoreClass extends EventEmitter {
|
|||||||
|
|
||||||
const PreferenceStore = new PreferenceStoreClass();
|
const PreferenceStore = new PreferenceStoreClass();
|
||||||
export default PreferenceStore;
|
export default PreferenceStore;
|
||||||
|
window.PreferenceStore = PreferenceStore;
|
||||||
|
|||||||
@@ -638,16 +638,15 @@ export function getMyTeam() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDirectChannelPreferences() {
|
export function getAllPreferences() {
|
||||||
if (isCallInProgress('getDirectChannelPreferences')) {
|
if (isCallInProgress('getAllPreferences')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
callTracker.getDirectChannelPreferences = utils.getTimestamp();
|
callTracker.getAllPreferences = utils.getTimestamp();
|
||||||
client.getPreferenceCategory(
|
client.getAllPreferences(
|
||||||
Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW,
|
|
||||||
(data, textStatus, xhr) => {
|
(data, textStatus, xhr) => {
|
||||||
callTracker.getDirectChannelPreferences = 0;
|
callTracker.getAllPreferences = 0;
|
||||||
|
|
||||||
if (xhr.status === 304 || !data) {
|
if (xhr.status === 304 || !data) {
|
||||||
return;
|
return;
|
||||||
@@ -659,8 +658,8 @@ export function getDirectChannelPreferences() {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
callTracker.getDirectChannelPreferences = 0;
|
callTracker.getAllPreferences = 0;
|
||||||
dispatchError(err, 'getDirectChannelPreferences');
|
dispatchError(err, 'getAllPreferences');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1142,6 +1142,19 @@ export function listIncomingHooks(success, error) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getAllPreferences(success, error) {
|
||||||
|
$.ajax({
|
||||||
|
url: `/api/v1/preferences/`,
|
||||||
|
dataType: 'json',
|
||||||
|
type: 'GET',
|
||||||
|
success,
|
||||||
|
error: (xhr, status, err) => {
|
||||||
|
var e = handleError('getAllPreferences', xhr, status, err);
|
||||||
|
error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function getPreferenceCategory(category, success, error) {
|
export function getPreferenceCategory(category, success, error) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/api/v1/preferences/${category}`,
|
url: `/api/v1/preferences/${category}`,
|
||||||
|
|||||||
@@ -289,7 +289,8 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
Preferences: {
|
Preferences: {
|
||||||
CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show'
|
CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show',
|
||||||
|
CATEGORY_DISPLAY_SETTINGS: 'display_settings'
|
||||||
},
|
},
|
||||||
KeyCodes: {
|
KeyCodes: {
|
||||||
UP: 38,
|
UP: 38,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
|
||||||
var ChannelStore = require('../stores/channel_store.jsx');
|
var ChannelStore = require('../stores/channel_store.jsx');
|
||||||
var UserStore = require('../stores/user_store.jsx');
|
var UserStore = require('../stores/user_store.jsx');
|
||||||
|
var PreferenceStore = require('../stores/preference_store.jsx');
|
||||||
var TeamStore = require('../stores/team_store.jsx');
|
var TeamStore = require('../stores/team_store.jsx');
|
||||||
var Constants = require('../utils/constants.jsx');
|
var Constants = require('../utils/constants.jsx');
|
||||||
var ActionTypes = Constants.ActionTypes;
|
var ActionTypes = Constants.ActionTypes;
|
||||||
@@ -164,23 +165,29 @@ export function displayDate(ticks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function displayTime(ticks) {
|
export function displayTime(ticks) {
|
||||||
var d = new Date(ticks);
|
const d = new Date(ticks);
|
||||||
var hours = d.getHours();
|
let hours = d.getHours();
|
||||||
var minutes = d.getMinutes();
|
let minutes = d.getMinutes();
|
||||||
|
let ampm = '';
|
||||||
|
|
||||||
var ampm = 'AM';
|
|
||||||
if (hours >= 12) {
|
|
||||||
ampm = 'PM';
|
|
||||||
}
|
|
||||||
|
|
||||||
hours = hours % 12;
|
|
||||||
if (!hours) {
|
|
||||||
hours = '12';
|
|
||||||
}
|
|
||||||
if (minutes <= 9) {
|
if (minutes <= 9) {
|
||||||
minutes = '0' + minutes;
|
minutes = '0' + minutes;
|
||||||
}
|
}
|
||||||
return hours + ':' + minutes + ' ' + ampm;
|
|
||||||
|
const useMilitaryTime = PreferenceStore.getPreference(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'use_military_time', {value: 'false'}).value;
|
||||||
|
if (useMilitaryTime === 'false') {
|
||||||
|
ampm = ' AM';
|
||||||
|
if (hours >= 12) {
|
||||||
|
ampm = ' PM';
|
||||||
|
}
|
||||||
|
|
||||||
|
hours = hours % 12;
|
||||||
|
if (!hours) {
|
||||||
|
hours = '12';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return hours + ':' + minutes + ampm;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function displayDateTime(ticks) {
|
export function displayDateTime(ticks) {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user