Merge pull request #881 from hmhealey/plt194

PLT-194 Changes to ChannelMember notification settings
Этот коммит содержится в:
Joram Wilander
2015-10-02 08:45:38 -04:00
родитель fbbee5bf61 c9a0030551
Коммит 08d390953a
16 изменённых файлов: 446 добавлений и 256 удалений

Просмотреть файл

@@ -23,7 +23,7 @@ func InitChannel(r *mux.Router) {
sr.Handle("/create_direct", ApiUserRequired(createDirectChannel)).Methods("POST") sr.Handle("/create_direct", ApiUserRequired(createDirectChannel)).Methods("POST")
sr.Handle("/update", ApiUserRequired(updateChannel)).Methods("POST") sr.Handle("/update", ApiUserRequired(updateChannel)).Methods("POST")
sr.Handle("/update_desc", ApiUserRequired(updateChannelDesc)).Methods("POST") sr.Handle("/update_desc", ApiUserRequired(updateChannelDesc)).Methods("POST")
sr.Handle("/update_notify_level", ApiUserRequired(updateNotifyLevel)).Methods("POST") 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]+}/", 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", ApiUserRequired(getChannelExtraInfo)).Methods("GET")
sr.Handle("/{id:[A-Za-z0-9]+}/join", ApiUserRequired(joinChannel)).Methods("POST") sr.Handle("/{id:[A-Za-z0-9]+}/join", ApiUserRequired(joinChannel)).Methods("POST")
@@ -76,7 +76,7 @@ func CreateChannel(c *Context, channel *model.Channel, addMember bool) (*model.C
if addMember { if addMember {
cm := &model.ChannelMember{ChannelId: sc.Id, UserId: c.Session.UserId, cm := &model.ChannelMember{ChannelId: sc.Id, UserId: c.Session.UserId,
Roles: model.CHANNEL_ROLE_ADMIN, NotifyLevel: model.CHANNEL_NOTIFY_ALL} Roles: model.CHANNEL_ROLE_ADMIN, NotifyProps: model.GetDefaultChannelNotifyProps()}
if cmresult := <-Srv.Store.Channel().SaveMember(cm); cmresult.Err != nil { if cmresult := <-Srv.Store.Channel().SaveMember(cm); cmresult.Err != nil {
return nil, cmresult.Err return nil, cmresult.Err
@@ -134,8 +134,7 @@ func CreateDirectChannel(c *Context, otherUserId string) (*model.Channel, *model
if sc, err := CreateChannel(c, channel, true); err != nil { if sc, err := CreateChannel(c, channel, true); err != nil {
return nil, err return nil, err
} else { } else {
cm := &model.ChannelMember{ChannelId: sc.Id, UserId: otherUserId, cm := &model.ChannelMember{ChannelId: sc.Id, UserId: otherUserId, Roles: "", NotifyProps: model.GetDefaultChannelNotifyProps()}
Roles: "", NotifyLevel: model.CHANNEL_NOTIFY_ALL}
if cmresult := <-Srv.Store.Channel().SaveMember(cm); cmresult.Err != nil { if cmresult := <-Srv.Store.Channel().SaveMember(cm); cmresult.Err != nil {
return nil, cmresult.Err return nil, cmresult.Err
@@ -372,7 +371,8 @@ func JoinChannel(c *Context, channelId string, role string) {
} }
if channel.Type == model.CHANNEL_OPEN { if channel.Type == model.CHANNEL_OPEN {
cm := &model.ChannelMember{ChannelId: channel.Id, UserId: c.Session.UserId, NotifyLevel: model.CHANNEL_NOTIFY_ALL, Roles: role} cm := &model.ChannelMember{ChannelId: channel.Id, UserId: c.Session.UserId,
Roles: role, NotifyProps: model.GetDefaultChannelNotifyProps()}
if cmresult := <-Srv.Store.Channel().SaveMember(cm); cmresult.Err != nil { if cmresult := <-Srv.Store.Channel().SaveMember(cm); cmresult.Err != nil {
c.Err = cmresult.Err c.Err = cmresult.Err
@@ -405,7 +405,9 @@ func JoinDefaultChannels(user *model.User, channelRole string) *model.AppError {
if result := <-Srv.Store.Channel().GetByName(user.TeamId, "town-square"); result.Err != nil { if result := <-Srv.Store.Channel().GetByName(user.TeamId, "town-square"); result.Err != nil {
err = result.Err err = result.Err
} else { } else {
cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id, NotifyLevel: model.CHANNEL_NOTIFY_ALL, Roles: channelRole} cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id,
Roles: channelRole, NotifyProps: model.GetDefaultChannelNotifyProps()}
if cmResult := <-Srv.Store.Channel().SaveMember(cm); cmResult.Err != nil { if cmResult := <-Srv.Store.Channel().SaveMember(cm); cmResult.Err != nil {
err = cmResult.Err err = cmResult.Err
} }
@@ -414,7 +416,9 @@ func JoinDefaultChannels(user *model.User, channelRole string) *model.AppError {
if result := <-Srv.Store.Channel().GetByName(user.TeamId, "off-topic"); result.Err != nil { if result := <-Srv.Store.Channel().GetByName(user.TeamId, "off-topic"); result.Err != nil {
err = result.Err err = result.Err
} else { } else {
cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id, NotifyLevel: model.CHANNEL_NOTIFY_ALL, Roles: channelRole} cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id,
Roles: channelRole, NotifyProps: model.GetDefaultChannelNotifyProps()}
if cmResult := <-Srv.Store.Channel().SaveMember(cm); cmResult.Err != nil { if cmResult := <-Srv.Store.Channel().SaveMember(cm); cmResult.Err != nil {
err = cmResult.Err err = cmResult.Err
} }
@@ -694,7 +698,7 @@ func addChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
} else { } else {
oUser := oresult.Data.(*model.User) oUser := oresult.Data.(*model.User)
cm := &model.ChannelMember{ChannelId: channel.Id, UserId: userId, NotifyLevel: model.CHANNEL_NOTIFY_ALL} cm := &model.ChannelMember{ChannelId: channel.Id, UserId: userId, NotifyProps: model.GetDefaultChannelNotifyProps()}
if cmresult := <-Srv.Store.Channel().SaveMember(cm); cmresult.Err != nil { if cmresult := <-Srv.Store.Channel().SaveMember(cm); cmresult.Err != nil {
l4g.Error("Failed to add member user_id=%v channel_id=%v err=%v", userId, id, cmresult.Err) l4g.Error("Failed to add member user_id=%v channel_id=%v err=%v", userId, id, cmresult.Err)
@@ -784,23 +788,18 @@ func removeChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
} }
func updateNotifyLevel(c *Context, w http.ResponseWriter, r *http.Request) { func updateNotifyProps(c *Context, w http.ResponseWriter, r *http.Request) {
data := model.MapFromJson(r.Body) data := model.MapFromJson(r.Body)
userId := data["user_id"] userId := data["user_id"]
if len(userId) != 26 { if len(userId) != 26 {
c.SetInvalidParam("updateNotifyLevel", "user_id") c.SetInvalidParam("updateMarkUnreadLevel", "user_id")
return return
} }
channelId := data["channel_id"] channelId := data["channel_id"]
if len(channelId) != 26 { if len(channelId) != 26 {
c.SetInvalidParam("updateNotifyLevel", "channel_id") c.SetInvalidParam("updateMarkUnreadLevel", "channel_id")
return
}
notifyLevel := data["notify_level"]
if len(notifyLevel) == 0 || !model.IsChannelNotifyLevelValid(notifyLevel) {
c.SetInvalidParam("updateNotifyLevel", "notify_level")
return return
} }
@@ -814,10 +813,29 @@ func updateNotifyLevel(c *Context, w http.ResponseWriter, r *http.Request) {
return return
} }
if result := <-Srv.Store.Channel().UpdateNotifyLevel(channelId, userId, notifyLevel); result.Err != nil { result := <-Srv.Store.Channel().GetMember(channelId, userId)
if result.Err != nil {
c.Err = result.Err c.Err = result.Err
return return
} }
w.Write([]byte(model.MapToJson(data))) member := result.Data.(model.ChannelMember)
// update whichever notify properties have been provided, but don't change the others
if markUnread, exists := data["mark_unread"]; exists {
member.NotifyProps["mark_unread"] = markUnread
}
if desktop, exists := data["desktop"]; exists {
member.NotifyProps["desktop"] = desktop
}
if result := <-Srv.Store.Channel().UpdateMember(&member); result.Err != nil {
c.Err = result.Err
return
} else {
// return the updated notify properties including any unchanged ones
w.Write([]byte(model.MapToJson(member.NotifyProps)))
}
} }

Просмотреть файл

@@ -255,7 +255,7 @@ func BenchmarkRemoveChannelMember(b *testing.B) {
} }
} }
func BenchmarkUpdateNotifyLevel(b *testing.B) { func BenchmarkUpdateNotifyProps(b *testing.B) {
var ( var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS} NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
) )
@@ -271,9 +271,10 @@ func BenchmarkUpdateNotifyLevel(b *testing.B) {
for i := range data { for i := range data {
newmap := map[string]string{ newmap := map[string]string{
"channel_id": channels[i].Id, "channel_id": channels[i].Id,
"user_id": user.Id, "user_id": user.Id,
"notify_level": model.CHANNEL_NOTIFY_MENTION, "desktop": model.CHANNEL_NOTIFY_MENTION,
"mark_unread": model.CHANNEL_MARK_UNREAD_MENTION,
} }
data[i] = newmap data[i] = newmap
} }
@@ -282,7 +283,7 @@ func BenchmarkUpdateNotifyLevel(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
for j := range channels { for j := range channels {
Client.Must(Client.UpdateNotifyLevel(data[j])) Client.Must(Client.UpdateNotifyProps(data[j]))
} }
} }
} }

Просмотреть файл

@@ -803,7 +803,7 @@ func TestRemoveChannelMember(t *testing.T) {
} }
func TestUpdateNotifyLevel(t *testing.T) { func TestUpdateNotifyProps(t *testing.T) {
Setup() Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN} team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
@@ -821,55 +821,94 @@ func TestUpdateNotifyLevel(t *testing.T) {
data := make(map[string]string) data := make(map[string]string)
data["channel_id"] = channel1.Id data["channel_id"] = channel1.Id
data["user_id"] = user.Id data["user_id"] = user.Id
data["notify_level"] = model.CHANNEL_NOTIFY_MENTION data["desktop"] = model.CHANNEL_NOTIFY_MENTION
timeBeforeUpdate := model.GetMillis() timeBeforeUpdate := model.GetMillis()
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
if _, err := Client.UpdateNotifyLevel(data); err != nil { // test updating desktop
if result, err := Client.UpdateNotifyProps(data); err != nil {
t.Fatal(err) t.Fatal(err)
} else if notifyProps := result.Data.(map[string]string); notifyProps["desktop"] != model.CHANNEL_NOTIFY_MENTION {
t.Fatal("NotifyProps[\"desktop\"] did not update properly")
} else if notifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_ALL {
t.Fatalf("NotifyProps[\"mark_unread\"] changed to %v", notifyProps["mark_unread"])
} }
rget := Client.Must(Client.GetChannels("")) rget := Client.Must(Client.GetChannels(""))
rdata := rget.Data.(*model.ChannelList) rdata := rget.Data.(*model.ChannelList)
if len(rdata.Members) == 0 || rdata.Members[channel1.Id].NotifyLevel != data["notify_level"] { if len(rdata.Members) == 0 || rdata.Members[channel1.Id].NotifyProps["desktop"] != data["desktop"] {
t.Fatal("NotifyLevel did not update properly") t.Fatal("NotifyProps[\"desktop\"] did not update properly")
} } else if rdata.Members[channel1.Id].LastUpdateAt <= timeBeforeUpdate {
if rdata.Members[channel1.Id].LastUpdateAt <= timeBeforeUpdate {
t.Fatal("LastUpdateAt did not update") t.Fatal("LastUpdateAt did not update")
} }
// test an empty update
delete(data, "desktop")
if result, err := Client.UpdateNotifyProps(data); err != nil {
t.Fatal(err)
} else if notifyProps := result.Data.(map[string]string); notifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_ALL {
t.Fatalf("NotifyProps[\"mark_unread\"] changed to %v", notifyProps["mark_unread"])
} else if notifyProps["desktop"] != model.CHANNEL_NOTIFY_MENTION {
t.Fatalf("NotifyProps[\"desktop\"] changed to %v", notifyProps["desktop"])
}
// test updating mark unread
data["mark_unread"] = model.CHANNEL_MARK_UNREAD_MENTION
if result, err := Client.UpdateNotifyProps(data); err != nil {
t.Fatal(err)
} else if notifyProps := result.Data.(map[string]string); notifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_MENTION {
t.Fatal("NotifyProps[\"mark_unread\"] did not update properly")
} else if notifyProps["desktop"] != model.CHANNEL_NOTIFY_MENTION {
t.Fatalf("NotifyProps[\"desktop\"] changed to %v", notifyProps["desktop"])
}
// test updating both
data["desktop"] = model.CHANNEL_NOTIFY_NONE
data["mark_unread"] = model.CHANNEL_MARK_UNREAD_MENTION
if result, err := Client.UpdateNotifyProps(data); err != nil {
t.Fatal(err)
} else if notifyProps := result.Data.(map[string]string); notifyProps["desktop"] != model.CHANNEL_NOTIFY_NONE {
t.Fatal("NotifyProps[\"desktop\"] did not update properly")
} else if notifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_MENTION {
t.Fatal("NotifyProps[\"mark_unread\"] did not update properly")
}
// test error cases
data["user_id"] = "junk" data["user_id"] = "junk"
if _, err := Client.UpdateNotifyLevel(data); err == nil { if _, err := Client.UpdateNotifyProps(data); err == nil {
t.Fatal("Should have errored - bad user id") t.Fatal("Should have errored - bad user id")
} }
data["user_id"] = "12345678901234567890123456" data["user_id"] = "12345678901234567890123456"
if _, err := Client.UpdateNotifyLevel(data); err == nil { if _, err := Client.UpdateNotifyProps(data); err == nil {
t.Fatal("Should have errored - bad user id") t.Fatal("Should have errored - bad user id")
} }
data["user_id"] = user.Id data["user_id"] = user.Id
data["channel_id"] = "junk" data["channel_id"] = "junk"
if _, err := Client.UpdateNotifyLevel(data); err == nil { if _, err := Client.UpdateNotifyProps(data); err == nil {
t.Fatal("Should have errored - bad channel id") t.Fatal("Should have errored - bad channel id")
} }
data["channel_id"] = "12345678901234567890123456" data["channel_id"] = "12345678901234567890123456"
if _, err := Client.UpdateNotifyLevel(data); err == nil { if _, err := Client.UpdateNotifyProps(data); err == nil {
t.Fatal("Should have errored - bad channel id") t.Fatal("Should have errored - bad channel id")
} }
data["channel_id"] = channel1.Id data["desktop"] = "junk"
data["notify_level"] = "" data["mark_unread"] = model.CHANNEL_MARK_UNREAD_ALL
if _, err := Client.UpdateNotifyLevel(data); err == nil { if _, err := Client.UpdateNotifyProps(data); err == nil {
t.Fatal("Should have errored - empty notify level") t.Fatal("Should have errored - bad desktop notify level")
} }
data["notify_level"] = "junk" data["desktop"] = model.CHANNEL_NOTIFY_ALL
if _, err := Client.UpdateNotifyLevel(data); err == nil { data["mark_unread"] = "junk"
t.Fatal("Should have errored - bad notify level") if _, err := Client.UpdateNotifyProps(data); err == nil {
t.Fatal("Should have errored - bad mark unread level")
} }
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"} user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey@test.com", Nickname: "Corey Hulen", Password: "pwd"}
@@ -879,8 +918,9 @@ func TestUpdateNotifyLevel(t *testing.T) {
data["channel_id"] = channel1.Id data["channel_id"] = channel1.Id
data["user_id"] = user2.Id data["user_id"] = user2.Id
data["notify_level"] = model.CHANNEL_NOTIFY_MENTION data["desktop"] = model.CHANNEL_NOTIFY_MENTION
if _, err := Client.UpdateNotifyLevel(data); err == nil { data["mark_unread"] = model.CHANNEL_MARK_UNREAD_MENTION
if _, err := Client.UpdateNotifyProps(data); err == nil {
t.Fatal("Should have errored - user not in channel") t.Fatal("Should have errored - user not in channel")
} }
} }

Просмотреть файл

@@ -10,22 +10,24 @@ import (
) )
const ( const (
CHANNEL_ROLE_ADMIN = "admin" CHANNEL_ROLE_ADMIN = "admin"
CHANNEL_NOTIFY_ALL = "all" CHANNEL_NOTIFY_DEFAULT = "default"
CHANNEL_NOTIFY_MENTION = "mention" CHANNEL_NOTIFY_ALL = "all"
CHANNEL_NOTIFY_NONE = "none" CHANNEL_NOTIFY_MENTION = "mention"
CHANNEL_NOTIFY_QUIET = "quiet" CHANNEL_NOTIFY_NONE = "none"
CHANNEL_MARK_UNREAD_ALL = "all"
CHANNEL_MARK_UNREAD_MENTION = "mention"
) )
type ChannelMember struct { type ChannelMember struct {
ChannelId string `json:"channel_id"` ChannelId string `json:"channel_id"`
UserId string `json:"user_id"` UserId string `json:"user_id"`
Roles string `json:"roles"` Roles string `json:"roles"`
LastViewedAt int64 `json:"last_viewed_at"` LastViewedAt int64 `json:"last_viewed_at"`
MsgCount int64 `json:"msg_count"` MsgCount int64 `json:"msg_count"`
MentionCount int64 `json:"mention_count"` MentionCount int64 `json:"mention_count"`
NotifyLevel string `json:"notify_level"` NotifyProps StringMap `json:"notify_props"`
LastUpdateAt int64 `json:"last_update_at"` LastUpdateAt int64 `json:"last_update_at"`
} }
func (o *ChannelMember) ToJson() string { func (o *ChannelMember) ToJson() string {
@@ -64,8 +66,14 @@ func (o *ChannelMember) IsValid() *AppError {
} }
} }
if len(o.NotifyLevel) > 20 || !IsChannelNotifyLevelValid(o.NotifyLevel) { notifyLevel := o.NotifyProps["desktop"]
return NewAppError("ChannelMember.IsValid", "Invalid notify level", "notify_level="+o.NotifyLevel) if len(notifyLevel) > 20 || !IsChannelNotifyLevelValid(notifyLevel) {
return NewAppError("ChannelMember.IsValid", "Invalid notify level", "notify_level="+notifyLevel)
}
markUnreadLevel := o.NotifyProps["mark_unread"]
if len(markUnreadLevel) > 20 || !IsChannelMarkUnreadLevelValid(markUnreadLevel) {
return NewAppError("ChannelMember.IsValid", "Invalid mark unread level", "mark_unread_level="+markUnreadLevel)
} }
return nil return nil
@@ -75,6 +83,24 @@ func (o *ChannelMember) PreSave() {
o.LastUpdateAt = GetMillis() o.LastUpdateAt = GetMillis()
} }
func IsChannelNotifyLevelValid(notifyLevel string) bool { func (o *ChannelMember) PreUpdate() {
return notifyLevel == CHANNEL_NOTIFY_ALL || notifyLevel == CHANNEL_NOTIFY_MENTION || notifyLevel == CHANNEL_NOTIFY_NONE || notifyLevel == CHANNEL_NOTIFY_QUIET o.LastUpdateAt = GetMillis()
}
func IsChannelNotifyLevelValid(notifyLevel string) bool {
return notifyLevel == CHANNEL_NOTIFY_DEFAULT ||
notifyLevel == CHANNEL_NOTIFY_ALL ||
notifyLevel == CHANNEL_NOTIFY_MENTION ||
notifyLevel == CHANNEL_NOTIFY_NONE
}
func IsChannelMarkUnreadLevelValid(markUnreadLevel string) bool {
return markUnreadLevel == CHANNEL_MARK_UNREAD_ALL || markUnreadLevel == CHANNEL_MARK_UNREAD_MENTION
}
func GetDefaultChannelNotifyProps() StringMap {
return StringMap{
"desktop": CHANNEL_NOTIFY_DEFAULT,
"mark_unread": CHANNEL_MARK_UNREAD_ALL,
}
} }

Просмотреть файл

@@ -31,24 +31,34 @@ func TestChannelMemberIsValid(t *testing.T) {
} }
o.Roles = "missing" o.Roles = "missing"
o.NotifyLevel = CHANNEL_NOTIFY_ALL o.NotifyProps = GetDefaultChannelNotifyProps()
o.UserId = NewId() o.UserId = NewId()
if err := o.IsValid(); err == nil { if err := o.IsValid(); err == nil {
t.Fatal("should be invalid") t.Fatal("should be invalid")
} }
o.Roles = CHANNEL_ROLE_ADMIN o.Roles = CHANNEL_ROLE_ADMIN
o.NotifyLevel = "junk" o.NotifyProps["desktop"] = "junk"
if err := o.IsValid(); err == nil { if err := o.IsValid(); err == nil {
t.Fatal("should be invalid") t.Fatal("should be invalid")
} }
o.NotifyLevel = "123456789012345678901" o.NotifyProps["desktop"] = "123456789012345678901"
if err := o.IsValid(); err == nil { if err := o.IsValid(); err == nil {
t.Fatal("should be invalid") t.Fatal("should be invalid")
} }
o.NotifyLevel = CHANNEL_NOTIFY_ALL o.NotifyProps["desktop"] = CHANNEL_NOTIFY_ALL
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.NotifyProps["mark_unread"] = "123456789012345678901"
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.NotifyProps["mark_unread"] = CHANNEL_MARK_UNREAD_ALL
if err := o.IsValid(); err != nil { if err := o.IsValid(); err != nil {
t.Fatal(err) t.Fatal(err)
} }

Просмотреть файл

@@ -450,8 +450,8 @@ func (c *Client) UpdateChannelDesc(data map[string]string) (*Result, *AppError)
} }
} }
func (c *Client) UpdateNotifyLevel(data map[string]string) (*Result, *AppError) { func (c *Client) UpdateNotifyProps(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/update_notify_level", MapToJson(data)); err != nil { if r, err := c.DoApiPost("/channels/update_notify_props", MapToJson(data)); err != nil {
return nil, err return nil, err
} else { } else {
return &Result{r.Header.Get(HEADER_REQUEST_ID), return &Result{r.Header.Get(HEADER_REQUEST_ID),

Просмотреть файл

@@ -4,6 +4,7 @@
package store package store
import ( import (
l4g "code.google.com/p/log4go"
"github.com/mattermost/platform/model" "github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils" "github.com/mattermost/platform/utils"
) )
@@ -30,13 +31,55 @@ func NewSqlChannelStore(sqlStore *SqlStore) ChannelStore {
tablem.ColMap("ChannelId").SetMaxSize(26) tablem.ColMap("ChannelId").SetMaxSize(26)
tablem.ColMap("UserId").SetMaxSize(26) tablem.ColMap("UserId").SetMaxSize(26)
tablem.ColMap("Roles").SetMaxSize(64) tablem.ColMap("Roles").SetMaxSize(64)
tablem.ColMap("NotifyLevel").SetMaxSize(20) tablem.ColMap("NotifyProps").SetMaxSize(2000)
} }
return s return s
} }
func (s SqlChannelStore) UpgradeSchemaIfNeeded() { func (s SqlChannelStore) UpgradeSchemaIfNeeded() {
if s.CreateColumnIfNotExists("ChannelMembers", "NotifyProps", "varchar(2000)", "varchar(2000)", "{}") {
// populate NotifyProps from existing NotifyLevel field
// set default values
_, err := s.GetMaster().Exec(
`UPDATE
ChannelMembers
SET
NotifyProps = CONCAT('{"desktop":"', CONCAT(NotifyLevel, '","mark_unread":"` + model.CHANNEL_MARK_UNREAD_ALL + `"}'))`)
if err != nil {
l4g.Error("Unable to set default values for ChannelMembers.NotifyProps")
l4g.Error(err.Error())
}
// assume channels with all notifications enabled are just using the default settings
_, err = s.GetMaster().Exec(
`UPDATE
ChannelMembers
SET
NotifyProps = '{"desktop":"` + model.CHANNEL_NOTIFY_DEFAULT + `","mark_unread":"` + model.CHANNEL_MARK_UNREAD_ALL + `"}'
WHERE
NotifyLevel = '` + model.CHANNEL_NOTIFY_ALL + `'`)
if err != nil {
l4g.Error("Unable to set values for ChannelMembers.NotifyProps when members previously had notifyLevel=all")
l4g.Error(err.Error())
}
// set quiet mode channels to have no notifications and only mark the channel unread on mentions
_, err = s.GetMaster().Exec(
`UPDATE
ChannelMembers
SET
NotifyProps = '{"desktop":"` + model.CHANNEL_NOTIFY_NONE + `","mark_unread":"` + model.CHANNEL_MARK_UNREAD_MENTION + `"}'
WHERE
NotifyLevel = 'quiet'`)
if err != nil {
l4g.Error("Unable to set values for ChannelMembers.NotifyProps when members previously had notifyLevel=quiet")
l4g.Error(err.Error())
}
s.RemoveColumnIfExists("ChannelMembers", "NotifyLevel")
}
} }
func (s SqlChannelStore) CreateIndexesIfNotExists() { func (s SqlChannelStore) CreateIndexesIfNotExists() {
@@ -386,6 +429,34 @@ func (s SqlChannelStore) SaveMember(member *model.ChannelMember) StoreChannel {
return storeChannel return storeChannel
} }
func (s SqlChannelStore) UpdateMember(member *model.ChannelMember) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
member.PreUpdate()
if result.Err = member.IsValid(); result.Err != nil {
storeChannel <- result
close(storeChannel)
return
}
if _, err := s.GetMaster().Update(member); err != nil {
result.Err = model.NewAppError("SqlChannelStore.UpdateMember", "We encounted an error updating the channel member",
"channel_id="+member.ChannelId+", "+"user_id="+member.UserId+", "+err.Error())
} else {
result.Data = member
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}
func (s SqlChannelStore) GetMembers(channelId string) StoreChannel { func (s SqlChannelStore) GetMembers(channelId string) StoreChannel {
storeChannel := make(StoreChannel) storeChannel := make(StoreChannel)
@@ -649,35 +720,6 @@ func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string)
return storeChannel return storeChannel
} }
func (s SqlChannelStore) UpdateNotifyLevel(channelId, userId, notifyLevel string) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
updateAt := model.GetMillis()
_, err := s.GetMaster().Exec(
`UPDATE
ChannelMembers
SET
NotifyLevel = :NotifyLevel,
LastUpdateAt = :LastUpdateAt
WHERE
UserId = :UserId
AND ChannelId = :ChannelId`,
map[string]interface{}{"ChannelId": channelId, "UserId": userId, "NotifyLevel": notifyLevel, "LastUpdateAt": updateAt})
if err != nil {
result.Err = model.NewAppError("SqlChannelStore.UpdateNotifyLevel", "We couldn't update the notify level", "channel_id="+channelId+", user_id="+userId+", "+err.Error())
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}
func (s SqlChannelStore) GetForExport(teamId string) StoreChannel { func (s SqlChannelStore) GetForExport(teamId string) StoreChannel {
storeChannel := make(StoreChannel) storeChannel := make(StoreChannel)

Просмотреть файл

@@ -135,13 +135,13 @@ func TestChannelStoreDelete(t *testing.T) {
m1 := model.ChannelMember{} m1 := model.ChannelMember{}
m1.ChannelId = o1.Id m1.ChannelId = o1.Id
m1.UserId = model.NewId() m1.UserId = model.NewId()
m1.NotifyLevel = model.CHANNEL_NOTIFY_ALL m1.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m1)) Must(store.Channel().SaveMember(&m1))
m2 := model.ChannelMember{} m2 := model.ChannelMember{}
m2.ChannelId = o2.Id m2.ChannelId = o2.Id
m2.UserId = m1.UserId m2.UserId = m1.UserId
m2.NotifyLevel = model.CHANNEL_NOTIFY_ALL m2.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m2)) Must(store.Channel().SaveMember(&m2))
if r := <-store.Channel().Delete(o1.Id, model.GetMillis()); r.Err != nil { if r := <-store.Channel().Delete(o1.Id, model.GetMillis()); r.Err != nil {
@@ -222,13 +222,13 @@ func TestChannelMemberStore(t *testing.T) {
o1 := model.ChannelMember{} o1 := model.ChannelMember{}
o1.ChannelId = c1.Id o1.ChannelId = c1.Id
o1.UserId = u1.Id o1.UserId = u1.Id
o1.NotifyLevel = model.CHANNEL_NOTIFY_ALL o1.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&o1)) Must(store.Channel().SaveMember(&o1))
o2 := model.ChannelMember{} o2 := model.ChannelMember{}
o2.ChannelId = c1.Id o2.ChannelId = c1.Id
o2.UserId = u2.Id o2.UserId = u2.Id
o2.NotifyLevel = model.CHANNEL_NOTIFY_ALL o2.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&o2)) Must(store.Channel().SaveMember(&o2))
c1t2 := (<-store.Channel().Get(c1.Id)).Data.(*model.Channel) c1t2 := (<-store.Channel().Get(c1.Id)).Data.(*model.Channel)
@@ -291,7 +291,7 @@ func TestChannelStorePermissionsTo(t *testing.T) {
m1 := model.ChannelMember{} m1 := model.ChannelMember{}
m1.ChannelId = o1.Id m1.ChannelId = o1.Id
m1.UserId = model.NewId() m1.UserId = model.NewId()
m1.NotifyLevel = model.CHANNEL_NOTIFY_ALL m1.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m1)) Must(store.Channel().SaveMember(&m1))
count := (<-store.Channel().CheckPermissionsTo(o1.TeamId, o1.Id, m1.UserId)).Data.(int64) count := (<-store.Channel().CheckPermissionsTo(o1.TeamId, o1.Id, m1.UserId)).Data.(int64)
@@ -371,19 +371,19 @@ func TestChannelStoreGetChannels(t *testing.T) {
m1 := model.ChannelMember{} m1 := model.ChannelMember{}
m1.ChannelId = o1.Id m1.ChannelId = o1.Id
m1.UserId = model.NewId() m1.UserId = model.NewId()
m1.NotifyLevel = model.CHANNEL_NOTIFY_ALL m1.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m1)) Must(store.Channel().SaveMember(&m1))
m2 := model.ChannelMember{} m2 := model.ChannelMember{}
m2.ChannelId = o1.Id m2.ChannelId = o1.Id
m2.UserId = model.NewId() m2.UserId = model.NewId()
m2.NotifyLevel = model.CHANNEL_NOTIFY_ALL m2.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m2)) Must(store.Channel().SaveMember(&m2))
m3 := model.ChannelMember{} m3 := model.ChannelMember{}
m3.ChannelId = o2.Id m3.ChannelId = o2.Id
m3.UserId = model.NewId() m3.UserId = model.NewId()
m3.NotifyLevel = model.CHANNEL_NOTIFY_ALL m3.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m3)) Must(store.Channel().SaveMember(&m3))
cresult := <-store.Channel().GetChannels(o1.TeamId, m1.UserId) cresult := <-store.Channel().GetChannels(o1.TeamId, m1.UserId)
@@ -414,19 +414,19 @@ func TestChannelStoreGetMoreChannels(t *testing.T) {
m1 := model.ChannelMember{} m1 := model.ChannelMember{}
m1.ChannelId = o1.Id m1.ChannelId = o1.Id
m1.UserId = model.NewId() m1.UserId = model.NewId()
m1.NotifyLevel = model.CHANNEL_NOTIFY_ALL m1.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m1)) Must(store.Channel().SaveMember(&m1))
m2 := model.ChannelMember{} m2 := model.ChannelMember{}
m2.ChannelId = o1.Id m2.ChannelId = o1.Id
m2.UserId = model.NewId() m2.UserId = model.NewId()
m2.NotifyLevel = model.CHANNEL_NOTIFY_ALL m2.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m2)) Must(store.Channel().SaveMember(&m2))
m3 := model.ChannelMember{} m3 := model.ChannelMember{}
m3.ChannelId = o2.Id m3.ChannelId = o2.Id
m3.UserId = model.NewId() m3.UserId = model.NewId()
m3.NotifyLevel = model.CHANNEL_NOTIFY_ALL m3.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m3)) Must(store.Channel().SaveMember(&m3))
o3 := model.Channel{} o3 := model.Channel{}
@@ -482,19 +482,19 @@ func TestChannelStoreGetChannelCounts(t *testing.T) {
m1 := model.ChannelMember{} m1 := model.ChannelMember{}
m1.ChannelId = o1.Id m1.ChannelId = o1.Id
m1.UserId = model.NewId() m1.UserId = model.NewId()
m1.NotifyLevel = model.CHANNEL_NOTIFY_ALL m1.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m1)) Must(store.Channel().SaveMember(&m1))
m2 := model.ChannelMember{} m2 := model.ChannelMember{}
m2.ChannelId = o1.Id m2.ChannelId = o1.Id
m2.UserId = model.NewId() m2.UserId = model.NewId()
m2.NotifyLevel = model.CHANNEL_NOTIFY_ALL m2.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m2)) Must(store.Channel().SaveMember(&m2))
m3 := model.ChannelMember{} m3 := model.ChannelMember{}
m3.ChannelId = o2.Id m3.ChannelId = o2.Id
m3.UserId = model.NewId() m3.UserId = model.NewId()
m3.NotifyLevel = model.CHANNEL_NOTIFY_ALL m3.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m3)) Must(store.Channel().SaveMember(&m3))
cresult := <-store.Channel().GetChannelCounts(o1.TeamId, m1.UserId) cresult := <-store.Channel().GetChannelCounts(o1.TeamId, m1.UserId)
@@ -523,7 +523,7 @@ func TestChannelStoreUpdateLastViewedAt(t *testing.T) {
m1 := model.ChannelMember{} m1 := model.ChannelMember{}
m1.ChannelId = o1.Id m1.ChannelId = o1.Id
m1.UserId = model.NewId() m1.UserId = model.NewId()
m1.NotifyLevel = model.CHANNEL_NOTIFY_ALL m1.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m1)) Must(store.Channel().SaveMember(&m1))
err := (<-store.Channel().UpdateLastViewedAt(m1.ChannelId, m1.UserId)).Err err := (<-store.Channel().UpdateLastViewedAt(m1.ChannelId, m1.UserId)).Err
@@ -551,7 +551,7 @@ func TestChannelStoreIncrementMentionCount(t *testing.T) {
m1 := model.ChannelMember{} m1 := model.ChannelMember{}
m1.ChannelId = o1.Id m1.ChannelId = o1.Id
m1.UserId = model.NewId() m1.UserId = model.NewId()
m1.NotifyLevel = model.CHANNEL_NOTIFY_ALL m1.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m1)) Must(store.Channel().SaveMember(&m1))
err := (<-store.Channel().IncrementMentionCount(m1.ChannelId, m1.UserId)).Err err := (<-store.Channel().IncrementMentionCount(m1.ChannelId, m1.UserId)).Err

Просмотреть файл

@@ -484,7 +484,7 @@ func TestPostStoreSearch(t *testing.T) {
m1 := model.ChannelMember{} m1 := model.ChannelMember{}
m1.ChannelId = c1.Id m1.ChannelId = c1.Id
m1.UserId = userId m1.UserId = userId
m1.NotifyLevel = model.CHANNEL_NOTIFY_ALL m1.NotifyProps = model.GetDefaultChannelNotifyProps()
Must(store.Channel().SaveMember(&m1)) Must(store.Channel().SaveMember(&m1))
c2 := &model.Channel{} c2 := &model.Channel{}

Просмотреть файл

@@ -62,6 +62,7 @@ type ChannelStore interface {
GetForExport(teamId string) StoreChannel GetForExport(teamId string) StoreChannel
SaveMember(member *model.ChannelMember) StoreChannel SaveMember(member *model.ChannelMember) StoreChannel
UpdateMember(member *model.ChannelMember) StoreChannel
GetMembers(channelId string) StoreChannel GetMembers(channelId string) StoreChannel
GetMember(channelId string, userId string) StoreChannel GetMember(channelId string, userId string) StoreChannel
RemoveMember(channelId string, userId string) StoreChannel RemoveMember(channelId string, userId string) StoreChannel
@@ -71,7 +72,6 @@ type ChannelStore interface {
CheckPermissionsToByName(teamId string, channelName string, userId string) StoreChannel CheckPermissionsToByName(teamId string, channelName string, userId string) StoreChannel
UpdateLastViewedAt(channelId string, userId string) StoreChannel UpdateLastViewedAt(channelId string, userId string) StoreChannel
IncrementMentionCount(channelId string, userId string) StoreChannel IncrementMentionCount(channelId string, userId string) StoreChannel
UpdateNotifyLevel(channelId string, userId string, notifyLevel string) StoreChannel
} }
type PostStore interface { type PostStore interface {

Просмотреть файл

@@ -15,14 +15,24 @@ export default class ChannelNotifications extends React.Component {
this.onListenerChange = this.onListenerChange.bind(this); this.onListenerChange = this.onListenerChange.bind(this);
this.updateSection = this.updateSection.bind(this); this.updateSection = this.updateSection.bind(this);
this.handleUpdate = this.handleUpdate.bind(this);
this.handleRadioClick = this.handleRadioClick.bind(this);
this.handleQuietToggle = this.handleQuietToggle.bind(this);
this.createDesktopSection = this.createDesktopSection.bind(this);
this.createQuietSection = this.createQuietSection.bind(this);
this.state = {notifyLevel: '', title: '', channelId: '', activeSection: ''}; this.handleSubmitNotifyLevel = this.handleSubmitNotifyLevel.bind(this);
this.handleUpdateNotifyLevel = this.handleUpdateNotifyLevel.bind(this);
this.createNotifyLevelSection = this.createNotifyLevelSection.bind(this);
this.handleSubmitMarkUnreadLevel = this.handleSubmitMarkUnreadLevel.bind(this);
this.handleUpdateMarkUnreadLevel = this.handleUpdateMarkUnreadLevel.bind(this);
this.createMarkUnreadLevelSection = this.createMarkUnreadLevelSection.bind(this);
this.state = {
notifyLevel: '',
markUnreadLevel: '',
title: '',
channelId: '',
activeSection: ''
};
} }
componentDidMount() { componentDidMount() {
ChannelStore.addChangeListener(this.onListenerChange); ChannelStore.addChangeListener(this.onListenerChange);
@@ -30,33 +40,34 @@ export default class ChannelNotifications extends React.Component {
var button = e.relatedTarget; var button = e.relatedTarget;
var channelId = button.getAttribute('data-channelid'); var channelId = button.getAttribute('data-channelid');
var notifyLevel = ChannelStore.getMember(channelId).notify_level; const member = ChannelStore.getMember(channelId);
var quietMode = false; var notifyLevel = member.notify_props.desktop;
var markUnreadLevel = member.notify_props.mark_unread;
if (notifyLevel === 'quiet') { this.setState({
quietMode = true; notifyLevel,
} markUnreadLevel,
title: button.getAttribute('data-title'),
this.setState({notifyLevel: notifyLevel, quietMode: quietMode, title: button.getAttribute('data-title'), channelId: channelId}); channelId: channelId
});
}.bind(this)); }.bind(this));
} }
componentWillUnmount() { componentWillUnmount() {
ChannelStore.removeChangeListener(this.onListenerChange); ChannelStore.removeChangeListener(this.onListenerChange);
} }
onListenerChange() { onListenerChange() {
if (!this.state.channelId) { if (!this.state.channelId) {
return; return;
} }
var notifyLevel = ChannelStore.getMember(this.state.channelId).notify_level; const member = ChannelStore.getMember(this.state.channelId);
var quietMode = false; var notifyLevel = member.notify_props.desktop;
if (notifyLevel === 'quiet') { var markUnreadLevel = member.notify_props.mark_unread;
quietMode = true;
}
var newState = this.state; var newState = this.state;
newState.notifyLevel = notifyLevel; newState.notifyLevel = notifyLevel;
newState.quietMode = quietMode; newState.markUnreadLevel = markUnreadLevel;
if (!Utils.areStatesEqual(this.state, newState)) { if (!Utils.areStatesEqual(this.state, newState)) {
this.setState(newState); this.setState(newState);
@@ -65,53 +76,64 @@ export default class ChannelNotifications extends React.Component {
updateSection(section) { updateSection(section) {
this.setState({activeSection: section}); this.setState({activeSection: section});
} }
handleUpdate() {
handleSubmitNotifyLevel() {
var channelId = this.state.channelId; var channelId = this.state.channelId;
var notifyLevel = this.state.notifyLevel; var notifyLevel = this.state.notifyLevel;
if (this.state.quietMode) {
notifyLevel = 'quiet'; if (ChannelStore.getMember(channelId).notify_props.desktop === notifyLevel) {
this.updateSection('');
return;
} }
var data = {}; var data = {};
data.channel_id = channelId; data.channel_id = channelId;
data.user_id = UserStore.getCurrentId(); data.user_id = UserStore.getCurrentId();
data.notify_level = notifyLevel; data.desktop = notifyLevel;
if (!data.notify_level || data.notify_level.length === 0) { Client.updateNotifyProps(data,
return; () => {
}
Client.updateNotifyLevel(data,
function success() {
var member = ChannelStore.getMember(channelId); var member = ChannelStore.getMember(channelId);
member.notify_level = notifyLevel; member.notify_props.desktop = notifyLevel;
ChannelStore.setChannelMember(member); ChannelStore.setChannelMember(member);
this.updateSection(''); this.updateSection('');
}.bind(this), },
function error(err) { (err) => {
this.setState({serverError: err.message}); this.setState({serverError: err.message});
}.bind(this) }
); );
} }
handleRadioClick(notifyLevel) {
this.setState({notifyLevel: notifyLevel, quietMode: false}); handleUpdateNotifyLevel(notifyLevel) {
this.setState({notifyLevel});
React.findDOMNode(this.refs.modal).focus(); React.findDOMNode(this.refs.modal).focus();
} }
handleQuietToggle(quietMode) {
this.setState({notifyLevel: 'none', quietMode: quietMode}); createNotifyLevelSection(serverError) {
React.findDOMNode(this.refs.modal).focus();
}
createDesktopSection(serverError) {
var handleUpdateSection; var handleUpdateSection;
const user = UserStore.getCurrentUser();
const globalNotifyLevel = user.notify_props.desktop;
let globalNotifyLevelName;
if (globalNotifyLevel === 'all') {
globalNotifyLevelName = 'For all activity';
} else if (globalNotifyLevel === 'mention') {
globalNotifyLevelName = 'Only for mentions';
} else {
globalNotifyLevelName = 'Never';
}
if (this.state.activeSection === 'desktop') { if (this.state.activeSection === 'desktop') {
var notifyActive = [false, false, false]; var notifyActive = [false, false, false, false];
if (this.state.notifyLevel === 'mention') { if (this.state.notifyLevel === 'default') {
notifyActive[1] = true;
} else if (this.state.notifyLevel === 'all') {
notifyActive[0] = true; notifyActive[0] = true;
} else { } else if (this.state.notifyLevel === 'all') {
notifyActive[1] = true;
} else if (this.state.notifyLevel === 'mention') {
notifyActive[2] = true; notifyActive[2] = true;
} else {
notifyActive[3] = true;
} }
var inputs = []; var inputs = [];
@@ -123,9 +145,9 @@ export default class ChannelNotifications extends React.Component {
<input <input
type='radio' type='radio'
checked={notifyActive[0]} checked={notifyActive[0]}
onChange={this.handleRadioClick.bind(this, 'all')} onChange={this.handleUpdateNotifyLevel.bind(this, 'default')}
> >
For all activity {`Global default (${globalNotifyLevelName})`}
</input> </input>
</label> </label>
<br/> <br/>
@@ -135,9 +157,9 @@ export default class ChannelNotifications extends React.Component {
<input <input
type='radio' type='radio'
checked={notifyActive[1]} checked={notifyActive[1]}
onChange={this.handleRadioClick.bind(this, 'mention')} onChange={this.handleUpdateNotifyLevel.bind(this, 'all')}
> >
Only for mentions {'For all activity'}
</input> </input>
</label> </label>
<br/> <br/>
@@ -147,9 +169,21 @@ export default class ChannelNotifications extends React.Component {
<input <input
type='radio' type='radio'
checked={notifyActive[2]} checked={notifyActive[2]}
onChange={this.handleRadioClick.bind(this, 'none')} onChange={this.handleUpdateNotifyLevel.bind(this, 'mention')}
> >
Never {'Only for mentions'}
</input>
</label>
<br/>
</div>
<div className='radio'>
<label>
<input
type='radio'
checked={notifyActive[3]}
onChange={this.handleUpdateNotifyLevel.bind(this, 'none')}
>
{'Never'}
</input> </input>
</label> </label>
</div> </div>
@@ -162,30 +196,19 @@ export default class ChannelNotifications extends React.Component {
e.preventDefault(); e.preventDefault();
}.bind(this); }.bind(this);
let curChannel = ChannelStore.get(this.state.channelId); const extraInfo = (
let extraInfo = (
<span> <span>
These settings will override the global notification settings. {'Selecting an option other than "Default" will override the global notification settings.'}
<br/> <br/>
Desktop notifications are available on Firefox, Safari, and Chrome. {'Desktop notifications are available on Firefox, Safari, and Chrome.'}
</span> </span>
); );
if (curChannel && curChannel.display_name) {
extraInfo = (
<span>
These settings will override the global notification settings for the <b>{curChannel.display_name}</b> channel.
<br/>
Desktop notifications are available on Firefox, Safari, and Chrome.
</span>
);
}
return ( return (
<SettingItemMax <SettingItemMax
title='Send desktop notifications' title='Send desktop notifications'
inputs={inputs} inputs={inputs}
submit={this.handleUpdate} submit={this.handleSubmitNotifyLevel}
server_error={serverError} server_error={serverError}
updateSection={handleUpdateSection} updateSection={handleUpdateSection}
extraInfo={extraInfo} extraInfo={extraInfo}
@@ -194,7 +217,9 @@ export default class ChannelNotifications extends React.Component {
} }
var describe; var describe;
if (this.state.notifyLevel === 'mention') { if (this.state.notifyLevel === 'default') {
describe = `Global default (${globalNotifyLevelName})`;
} else if (this.state.notifyLevel === 'mention') {
describe = 'Only for mentions'; describe = 'Only for mentions';
} else if (this.state.notifyLevel === 'all') { } else if (this.state.notifyLevel === 'all') {
describe = 'For all activity'; describe = 'For all activity';
@@ -215,101 +240,123 @@ export default class ChannelNotifications extends React.Component {
/> />
); );
} }
createQuietSection(serverError) {
var handleUpdateSection; handleSubmitMarkUnreadLevel() {
if (this.state.activeSection === 'quiet') { const channelId = this.state.channelId;
var quietActive = [false, false]; const markUnreadLevel = this.state.markUnreadLevel;
if (this.state.quietMode) {
quietActive[0] = true; if (ChannelStore.getMember(channelId).notify_props.mark_unread === markUnreadLevel) {
} else { this.updateSection('');
quietActive[1] = true; return;
}
const data = {
channel_id: channelId,
user_id: UserStore.getCurrentId(),
mark_unread: markUnreadLevel
};
Client.updateNotifyProps(data,
() => {
var member = ChannelStore.getMember(channelId);
member.notify_props.mark_unread = markUnreadLevel;
ChannelStore.setChannelMember(member);
this.updateSection('');
},
(err) => {
this.setState({serverError: err.message});
} }
);
}
var inputs = []; handleUpdateMarkUnreadLevel(markUnreadLevel) {
this.setState({markUnreadLevel});
React.findDOMNode(this.refs.modal).focus();
}
inputs.push( createMarkUnreadLevelSection(serverError) {
let content;
if (this.state.activeSection === 'markUnreadLevel') {
const inputs = [(
<div> <div>
<div className='radio'> <div className='radio'>
<label> <label>
<input <input
type='radio' type='radio'
checked={quietActive[0]} checked={this.state.markUnreadLevel === 'all'}
onChange={this.handleQuietToggle.bind(this, true)} onChange={this.handleUpdateMarkUnreadLevel.bind(this, 'all')}
> >
On {'For all unread messages'}
</input> </input>
</label> </label>
<br/> <br />
</div> </div>
<div className='radio'> <div className='radio'>
<label> <label>
<input <input
type='radio' type='radio'
checked={quietActive[1]} checked={this.state.markUnreadLevel === 'mention'}
onChange={this.handleQuietToggle.bind(this, false)} onChange={this.handleUpdateMarkUnreadLevel.bind(this, 'mention')}
> >
Off {'Only for mentions'}
</input> </input>
</label> </label>
<br/> <br />
</div> </div>
</div> </div>
); )];
inputs.push( const handleUpdateSection = function handleUpdateSection(e) {
<div>
<br/>
Enabling quiet mode will turn off desktop notifications and only mark the channel as unread if you have been mentioned.
</div>
);
handleUpdateSection = function updateSection(e) {
this.updateSection(''); this.updateSection('');
this.onListenerChange(); this.onListenerChange();
e.preventDefault(); e.preventDefault();
}.bind(this); }.bind(this);
return ( const extraInfo = <span>{'The channel name is bolded in the sidebar when there are unread messages. Selecting "Only for mentions" will bold the channel only when you are mentioned.'}</span>;
content = (
<SettingItemMax <SettingItemMax
title='Quiet mode' title='Mark Channel Unread'
inputs={inputs} inputs={inputs}
submit={this.handleUpdate} submit={this.handleSubmitMarkUnreadLevel}
server_error={serverError} server_error={serverError}
updateSection={handleUpdateSection} updateSection={handleUpdateSection}
extraInfo={extraInfo}
/>
);
} else {
let describe;
if (!this.state.markUnreadLevel || this.state.markUnreadLevel === 'all') {
describe = 'For all unread messages';
} else {
describe = 'Only for mentions';
}
const handleUpdateSection = function handleUpdateSection(e) {
this.updateSection('markUnreadLevel');
e.preventDefault();
}.bind(this);
content = (
<SettingItemMin
title='Mark Channel Unread'
describe={describe}
updateSection={handleUpdateSection}
/> />
); );
} }
var describe; return content;
if (this.state.quietMode) {
describe = 'On';
} else {
describe = 'Off';
}
handleUpdateSection = function updateSection(e) {
this.updateSection('quiet');
e.preventDefault();
}.bind(this);
return (
<SettingItemMin
title='Quiet mode'
describe={describe}
updateSection={handleUpdateSection}
/>
);
} }
render() { render() {
var serverError = null; var serverError = null;
if (this.state.serverError) { if (this.state.serverError) {
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>; serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
} }
var desktopSection = this.createDesktopSection(serverError);
var quietSection = this.createQuietSection(serverError);
return ( return (
<div <div
className='modal fade' className='modal fade'
@@ -341,9 +388,9 @@ export default class ChannelNotifications extends React.Component {
> >
<br/> <br/>
<div className='divider-dark first'/> <div className='divider-dark first'/>
{desktopSection} {this.createNotifyLevelSection(serverError)}
<div className='divider-light'/> <div className='divider-light'/>
{quietSection} {this.createMarkUnreadLevelSection(serverError)}
<div className='divider-dark'/> <div className='divider-dark'/>
</div> </div>
</div> </div>

Просмотреть файл

@@ -15,7 +15,7 @@ function getCountsStateFromStores() {
count += channel.total_msg_count - channelMember.msg_count; count += channel.total_msg_count - channelMember.msg_count;
} else if (channelMember.mention_count > 0) { } else if (channelMember.mention_count > 0) {
count += channelMember.mention_count; count += channelMember.mention_count;
} else if (channelMember.notify_level !== 'quiet' && channel.total_msg_count - channelMember.msg_count > 0) { } else if (channelMember.notify_props.mark_unread !== 'mention' && channel.total_msg_count - channelMember.msg_count > 0) {
count += 1; count += 1;
} }
}); });

Просмотреть файл

@@ -200,13 +200,17 @@ export default class Sidebar extends React.Component {
} }
var channel = ChannelStore.get(msg.channel_id); var channel = ChannelStore.get(msg.channel_id);
var user = UserStore.getCurrentUser(); const user = UserStore.getCurrentUser();
if (user.notify_props && ((user.notify_props.desktop === 'mention' && mentions.indexOf(user.id) === -1 && channel.type !== 'D') || user.notify_props.desktop === 'none')) { const member = ChannelStore.getMember(msg.channel_id);
return;
var notifyLevel = member.notify_props.desktop;
if (notifyLevel === 'default') {
notifyLevel = user.notify_props.desktop;
} }
var member = ChannelStore.getMember(msg.channel_id); if (notifyLevel === 'none') {
if ((member.notify_level === 'mention' && mentions.indexOf(user.id) === -1) || member.notify_level === 'none' || member.notify_level === 'quiet') { return;
} else if (notifyLevel === 'mention' && mentions.indexOf(user.id) === -1 && channel.type !== 'D') {
return; return;
} }
@@ -330,7 +334,7 @@ export default class Sidebar extends React.Component {
var unread = false; var unread = false;
if (channelMember) { if (channelMember) {
msgCount = channel.total_msg_count - channelMember.msg_count; msgCount = channel.total_msg_count - channelMember.msg_count;
unread = (msgCount > 0 && channelMember.notify_level !== 'quiet') || channelMember.mention_count > 0; unread = (msgCount > 0 && channelMember.notify_props.mark_unread !== 'mention') || channelMember.mention_count > 0;
} }
var titleClass = ''; var titleClass = '';

Просмотреть файл

@@ -17,7 +17,7 @@ function getNotificationsStateFromStores() {
if (user.notify_props && user.notify_props.desktop_sound) { if (user.notify_props && user.notify_props.desktop_sound) {
sound = user.notify_props.desktop_sound; sound = user.notify_props.desktop_sound;
} }
var desktop = 'all'; var desktop = 'default';
if (user.notify_props && user.notify_props.desktop) { if (user.notify_props && user.notify_props.desktop) {
desktop = user.notify_props.desktop; desktop = user.notify_props.desktop;
} }

Просмотреть файл

@@ -152,21 +152,23 @@ export function getChannel(id) {
} }
export function updateLastViewedAt() { export function updateLastViewedAt() {
if (isCallInProgress('updateLastViewed')) { const channelId = ChannelStore.getCurrentId();
if (channelId === null) {
return; return;
} }
if (ChannelStore.getCurrentId() == null) { if (isCallInProgress(`updateLastViewed${channelId}`)) {
return; return;
} }
callTracker.updateLastViewed = utils.getTimestamp(); callTracker[`updateLastViewed${channelId}`] = utils.getTimestamp();
client.updateLastViewedAt( client.updateLastViewedAt(
ChannelStore.getCurrentId(), channelId,
function updateLastViewedAtSuccess() { () => {
callTracker.updateLastViewed = 0; callTracker.updateLastViewed = 0;
}, },
function updateLastViewdAtFailure(err) { (err) => {
callTracker.updateLastViewed = 0; callTracker.updateLastViewed = 0;
dispatchError(err, 'updateLastViewedAt'); dispatchError(err, 'updateLastViewedAt');
} }

Просмотреть файл

@@ -582,16 +582,16 @@ export function updateChannelDesc(data, success, error) {
track('api', 'api_channels_desc'); track('api', 'api_channels_desc');
} }
export function updateNotifyLevel(data, success, error) { export function updateNotifyProps(data, success, error) {
$.ajax({ $.ajax({
url: '/api/v1/channels/update_notify_level', url: '/api/v1/channels/update_notify_props',
dataType: 'json', dataType: 'json',
contentType: 'application/json', contentType: 'application/json',
type: 'POST', type: 'POST',
data: JSON.stringify(data), data: JSON.stringify(data),
success, success,
error: function onError(xhr, status, err) { error: function onError(xhr, status, err) {
var e = handleError('updateNotifyLevel', xhr, status, err); var e = handleError('updateNotifyProps', xhr, status, err);
error(e); error(e);
} }
}); });