PLT-2707 Adding option to show DM list from all of server (#2871)
* PLT-2707 Adding option to show DM list from all of server * Fixing loc
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
6b06f49e89
Коммит
6611229cd7
@@ -68,7 +68,7 @@ func TestCliCreateUserWithTeam(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
profiles := th.SystemAdminClient.Must(th.SystemAdminClient.GetProfilesForTeam(th.SystemAdminTeam.Id, "")).Data.(map[string]*model.User)
|
profiles := th.SystemAdminClient.Must(th.SystemAdminClient.GetProfiles(th.SystemAdminTeam.Id, "")).Data.(map[string]*model.User)
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ func TestCliJoinTeam(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
profiles := th.SystemAdminClient.Must(th.SystemAdminClient.GetProfilesForTeam(th.SystemAdminTeam.Id, "")).Data.(map[string]*model.User)
|
profiles := th.SystemAdminClient.Must(th.SystemAdminClient.GetProfiles(th.SystemAdminTeam.Id, "")).Data.(map[string]*model.User)
|
||||||
|
|
||||||
found := false
|
found := false
|
||||||
|
|
||||||
|
|||||||
46
api/user.go
46
api/user.go
@@ -55,6 +55,7 @@ func InitUser() {
|
|||||||
BaseRoutes.Users.Handle("/status", ApiUserRequiredActivity(getStatuses, false)).Methods("POST")
|
BaseRoutes.Users.Handle("/status", ApiUserRequiredActivity(getStatuses, false)).Methods("POST")
|
||||||
BaseRoutes.Users.Handle("/direct_profiles", ApiUserRequired(getDirectProfiles)).Methods("GET")
|
BaseRoutes.Users.Handle("/direct_profiles", ApiUserRequired(getDirectProfiles)).Methods("GET")
|
||||||
BaseRoutes.Users.Handle("/profiles/{id:[A-Za-z0-9]+}", ApiUserRequired(getProfiles)).Methods("GET")
|
BaseRoutes.Users.Handle("/profiles/{id:[A-Za-z0-9]+}", ApiUserRequired(getProfiles)).Methods("GET")
|
||||||
|
BaseRoutes.Users.Handle("/profiles_for_dm_list/{id:[A-Za-z0-9]+}", ApiUserRequired(getProfilesForDirectMessageList)).Methods("GET")
|
||||||
|
|
||||||
BaseRoutes.Users.Handle("/mfa", ApiAppHandler(checkMfa)).Methods("POST")
|
BaseRoutes.Users.Handle("/mfa", ApiAppHandler(checkMfa)).Methods("POST")
|
||||||
BaseRoutes.Users.Handle("/generate_mfa_qr", ApiUserRequiredTrustRequester(generateMfaQrCode)).Methods("GET")
|
BaseRoutes.Users.Handle("/generate_mfa_qr", ApiUserRequiredTrustRequester(generateMfaQrCode)).Methods("GET")
|
||||||
@@ -902,6 +903,49 @@ func getUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getProfilesForDirectMessageList(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
params := mux.Vars(r)
|
||||||
|
id := params["id"]
|
||||||
|
|
||||||
|
var pchan store.StoreChannel
|
||||||
|
|
||||||
|
if *utils.Cfg.TeamSettings.RestrictDirectMessage == model.DIRECT_MESSAGE_TEAM {
|
||||||
|
if c.Session.GetTeamByTeamId(id) == nil {
|
||||||
|
if !c.HasSystemAdminPermissions("getProfiles") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pchan = Srv.Store.User().GetProfiles(id)
|
||||||
|
} else {
|
||||||
|
pchan = Srv.Store.User().GetAllProfiles()
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := <-pchan; result.Err != nil {
|
||||||
|
c.Err = result.Err
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
profiles := result.Data.(map[string]*model.User)
|
||||||
|
|
||||||
|
for k, p := range profiles {
|
||||||
|
options := utils.Cfg.GetSanitizeOptions()
|
||||||
|
options["passwordupdate"] = false
|
||||||
|
|
||||||
|
if c.IsSystemAdmin() {
|
||||||
|
options["fullname"] = true
|
||||||
|
options["email"] = true
|
||||||
|
} else {
|
||||||
|
p.ClearNonProfileFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Sanitize(options)
|
||||||
|
profiles[k] = p
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte(model.UserMapToJson(profiles)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func getProfiles(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getProfiles(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
params := mux.Vars(r)
|
params := mux.Vars(r)
|
||||||
id := params["id"]
|
id := params["id"]
|
||||||
@@ -940,7 +984,6 @@ func getProfiles(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
|
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
|
||||||
w.Write([]byte(model.UserMapToJson(profiles)))
|
w.Write([]byte(model.UserMapToJson(profiles)))
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -973,7 +1016,6 @@ func getDirectProfiles(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
|
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
|
||||||
w.Write([]byte(model.UserMapToJson(profiles)))
|
w.Write([]byte(model.UserMapToJson(profiles)))
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -395,6 +395,22 @@ func TestGetDirectProfiles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetProfilesForDirectMessageList(t *testing.T) {
|
||||||
|
th := Setup().InitBasic()
|
||||||
|
|
||||||
|
th.BasicClient.Must(th.BasicClient.CreateDirectChannel(th.BasicUser2.Id))
|
||||||
|
|
||||||
|
if result, err := th.BasicClient.GetProfilesForDirectMessageList(th.BasicTeam.Id); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else {
|
||||||
|
users := result.Data.(map[string]*model.User)
|
||||||
|
|
||||||
|
if len(users) < 1 {
|
||||||
|
t.Fatal("map was wrong length")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetAudits(t *testing.T) {
|
func TestGetAudits(t *testing.T) {
|
||||||
th := Setup()
|
th := Setup()
|
||||||
Client := th.CreateClient()
|
Client := th.CreateClient()
|
||||||
|
|||||||
@@ -34,7 +34,8 @@
|
|||||||
"RestrictCreationToDomains": "",
|
"RestrictCreationToDomains": "",
|
||||||
"RestrictTeamNames": true,
|
"RestrictTeamNames": true,
|
||||||
"EnableCustomBrand": false,
|
"EnableCustomBrand": false,
|
||||||
"CustomBrandText": ""
|
"CustomBrandText": "",
|
||||||
|
"RestrictDirectMessage": "any"
|
||||||
},
|
},
|
||||||
"SqlSettings": {
|
"SqlSettings": {
|
||||||
"DriverName": "mysql",
|
"DriverName": "mysql",
|
||||||
|
|||||||
@@ -2303,6 +2303,10 @@
|
|||||||
"id": "model.config.is_valid.ldap_security.app_error",
|
"id": "model.config.is_valid.ldap_security.app_error",
|
||||||
"translation": "Invalid connection security for LDAP settings. Must be '', 'TLS', or 'STARTTLS'"
|
"translation": "Invalid connection security for LDAP settings. Must be '', 'TLS', or 'STARTTLS'"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "model.config.is_valid.restrict_direct_message.app_error",
|
||||||
|
"translation": "Invalid direct message restriction. Must be 'any', or 'team'"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "model.config.is_valid.listen_address.app_error",
|
"id": "model.config.is_valid.listen_address.app_error",
|
||||||
"translation": "Invalid listen address for service settings Must be set."
|
"translation": "Invalid listen address for service settings Must be set."
|
||||||
|
|||||||
@@ -321,8 +321,8 @@ func (c *Client) GetMe(etag string) (*Result, *AppError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
|
func (c *Client) GetProfilesForDirectMessageList(teamId string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/profiles/"+teamId, "", etag); err != nil {
|
if r, err := c.DoApiGet("/users/profiles_for_dm_list/"+teamId, "", ""); 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),
|
||||||
@@ -330,8 +330,8 @@ func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetProfilesForTeam(teamId string, etag string) (*Result, *AppError) {
|
func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/profiles/"+teamId+"?skip_direct=true", "", etag); err != nil {
|
if r, err := c.DoApiGet("/users/profiles/"+teamId, "", etag); 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),
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ const (
|
|||||||
GENERIC_NOTIFICATION = "generic"
|
GENERIC_NOTIFICATION = "generic"
|
||||||
FULL_NOTIFICATION = "full"
|
FULL_NOTIFICATION = "full"
|
||||||
|
|
||||||
|
DIRECT_MESSAGE_ANY = "any"
|
||||||
|
DIRECT_MESSAGE_TEAM = "team"
|
||||||
|
|
||||||
FAKE_SETTING = "********************************"
|
FAKE_SETTING = "********************************"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -162,6 +165,7 @@ type TeamSettings struct {
|
|||||||
RestrictTeamNames *bool
|
RestrictTeamNames *bool
|
||||||
EnableCustomBrand *bool
|
EnableCustomBrand *bool
|
||||||
CustomBrandText *string
|
CustomBrandText *string
|
||||||
|
RestrictDirectMessage *string
|
||||||
}
|
}
|
||||||
|
|
||||||
type LdapSettings struct {
|
type LdapSettings struct {
|
||||||
@@ -315,6 +319,11 @@ func (o *Config) SetDefaults() {
|
|||||||
*o.TeamSettings.EnableOpenServer = false
|
*o.TeamSettings.EnableOpenServer = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.TeamSettings.RestrictDirectMessage == nil {
|
||||||
|
o.TeamSettings.RestrictDirectMessage = new(string)
|
||||||
|
*o.TeamSettings.RestrictDirectMessage = DIRECT_MESSAGE_ANY
|
||||||
|
}
|
||||||
|
|
||||||
if o.EmailSettings.EnableSignInWithEmail == nil {
|
if o.EmailSettings.EnableSignInWithEmail == nil {
|
||||||
o.EmailSettings.EnableSignInWithEmail = new(bool)
|
o.EmailSettings.EnableSignInWithEmail = new(bool)
|
||||||
|
|
||||||
@@ -520,6 +529,10 @@ func (o *Config) IsValid() *AppError {
|
|||||||
return NewLocAppError("Config.IsValid", "model.config.is_valid.max_users.app_error", nil, "")
|
return NewLocAppError("Config.IsValid", "model.config.is_valid.max_users.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !(*o.TeamSettings.RestrictDirectMessage == DIRECT_MESSAGE_ANY || *o.TeamSettings.RestrictDirectMessage == DIRECT_MESSAGE_TEAM) {
|
||||||
|
return NewLocAppError("Config.IsValid", "model.config.is_valid.restrict_direct_message.app_error", nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
if len(o.SqlSettings.AtRestEncryptKey) < 32 {
|
if len(o.SqlSettings.AtRestEncryptKey) < 32 {
|
||||||
return NewLocAppError("Config.IsValid", "model.config.is_valid.encrypt_sql.app_error", nil, "")
|
return NewLocAppError("Config.IsValid", "model.config.is_valid.encrypt_sql.app_error", nil, "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -454,7 +454,14 @@ func (s SqlUserStore) GetEtagForDirectProfiles(userId string) StoreChannel {
|
|||||||
Channels.Type = 'D'
|
Channels.Type = 'D'
|
||||||
AND Channels.Id = ChannelMembers.ChannelId
|
AND Channels.Id = ChannelMembers.ChannelId
|
||||||
AND ChannelMembers.UserId = :UserId))
|
AND ChannelMembers.UserId = :UserId))
|
||||||
`, map[string]interface{}{"UserId": userId})
|
OR Id IN (SELECT
|
||||||
|
Name
|
||||||
|
FROM
|
||||||
|
Preferences
|
||||||
|
WHERE
|
||||||
|
UserId = :UserId
|
||||||
|
AND Category = 'direct_channel_show')
|
||||||
|
`, map[string]interface{}{"UserId": userId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
|
result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
|
||||||
} else {
|
} else {
|
||||||
@@ -468,6 +475,57 @@ func (s SqlUserStore) GetEtagForDirectProfiles(userId string) StoreChannel {
|
|||||||
return storeChannel
|
return storeChannel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlUserStore) GetEtagForAllProfiles() StoreChannel {
|
||||||
|
storeChannel := make(StoreChannel)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
result := StoreResult{}
|
||||||
|
|
||||||
|
updateAt, err := s.GetReplica().SelectInt("SELECT UpdateAt FROM Users ORDER BY UpdateAt DESC LIMIT 1")
|
||||||
|
if err != nil {
|
||||||
|
result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, model.GetMillis())
|
||||||
|
} else {
|
||||||
|
result.Data = fmt.Sprintf("%v.%v", model.CurrentVersion, updateAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return storeChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
func (us SqlUserStore) GetAllProfiles() StoreChannel {
|
||||||
|
|
||||||
|
storeChannel := make(StoreChannel)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
result := StoreResult{}
|
||||||
|
|
||||||
|
var users []*model.User
|
||||||
|
|
||||||
|
if _, err := us.GetReplica().Select(&users, "SELECT * FROM Users"); err != nil {
|
||||||
|
result.Err = model.NewLocAppError("SqlUserStore.GetProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error())
|
||||||
|
} else {
|
||||||
|
|
||||||
|
userMap := make(map[string]*model.User)
|
||||||
|
|
||||||
|
for _, u := range users {
|
||||||
|
u.Password = ""
|
||||||
|
u.AuthData = ""
|
||||||
|
userMap[u.Id] = u
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Data = userMap
|
||||||
|
}
|
||||||
|
|
||||||
|
storeChannel <- result
|
||||||
|
close(storeChannel)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return storeChannel
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlUserStore) GetEtagForProfiles(teamId string) StoreChannel {
|
func (s SqlUserStore) GetEtagForProfiles(teamId string) StoreChannel {
|
||||||
storeChannel := make(StoreChannel)
|
storeChannel := make(StoreChannel)
|
||||||
|
|
||||||
@@ -548,7 +606,15 @@ func (us SqlUserStore) GetDirectProfiles(userId string) StoreChannel {
|
|||||||
WHERE
|
WHERE
|
||||||
Channels.Type = 'D'
|
Channels.Type = 'D'
|
||||||
AND Channels.Id = ChannelMembers.ChannelId
|
AND Channels.Id = ChannelMembers.ChannelId
|
||||||
AND ChannelMembers.UserId = :UserId))`, map[string]interface{}{"UserId": userId}); err != nil {
|
AND ChannelMembers.UserId = :UserId))
|
||||||
|
OR Id IN (SELECT
|
||||||
|
Name
|
||||||
|
FROM
|
||||||
|
Preferences
|
||||||
|
WHERE
|
||||||
|
UserId = :UserId
|
||||||
|
AND Category = 'direct_channel_show')
|
||||||
|
`, map[string]interface{}{"UserId": userId}); err != nil {
|
||||||
result.Err = model.NewLocAppError("SqlUserStore.GetDirectProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error())
|
result.Err = model.NewLocAppError("SqlUserStore.GetDirectProfiles", "store.sql_user.get_profiles.app_error", nil, err.Error())
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|||||||
@@ -263,6 +263,31 @@ func TestActiveUserCount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUserStoreGetAllProfiles(t *testing.T) {
|
||||||
|
Setup()
|
||||||
|
|
||||||
|
teamId := model.NewId()
|
||||||
|
|
||||||
|
u1 := &model.User{}
|
||||||
|
u1.Email = model.NewId()
|
||||||
|
Must(store.User().Save(u1))
|
||||||
|
Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
|
||||||
|
|
||||||
|
u2 := &model.User{}
|
||||||
|
u2.Email = model.NewId()
|
||||||
|
Must(store.User().Save(u2))
|
||||||
|
Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
|
||||||
|
|
||||||
|
if r1 := <-store.User().GetAllProfiles(); r1.Err != nil {
|
||||||
|
t.Fatal(r1.Err)
|
||||||
|
} else {
|
||||||
|
users := r1.Data.(map[string]*model.User)
|
||||||
|
if len(users) < 2 {
|
||||||
|
t.Fatal("invalid returned users")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUserStoreGetProfiles(t *testing.T) {
|
func TestUserStoreGetProfiles(t *testing.T) {
|
||||||
Setup()
|
Setup()
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ type UserStore interface {
|
|||||||
UpdateMfaActive(userId string, active bool) StoreChannel
|
UpdateMfaActive(userId string, active bool) StoreChannel
|
||||||
Get(id string) StoreChannel
|
Get(id string) StoreChannel
|
||||||
GetAll() StoreChannel
|
GetAll() StoreChannel
|
||||||
|
GetAllProfiles() StoreChannel
|
||||||
GetProfiles(teamId string) StoreChannel
|
GetProfiles(teamId string) StoreChannel
|
||||||
GetDirectProfiles(userId string) StoreChannel
|
GetDirectProfiles(userId string) StoreChannel
|
||||||
GetProfileByIds(userId []string) StoreChannel
|
GetProfileByIds(userId []string) StoreChannel
|
||||||
@@ -139,6 +140,7 @@ type UserStore interface {
|
|||||||
GetByUsername(username string) StoreChannel
|
GetByUsername(username string) StoreChannel
|
||||||
GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled bool) StoreChannel
|
GetForLogin(loginId string, allowSignInWithUsername, allowSignInWithEmail, ldapEnabled bool) StoreChannel
|
||||||
VerifyEmail(userId string) StoreChannel
|
VerifyEmail(userId string) StoreChannel
|
||||||
|
GetEtagForAllProfiles() StoreChannel
|
||||||
GetEtagForProfiles(teamId string) StoreChannel
|
GetEtagForProfiles(teamId string) StoreChannel
|
||||||
GetEtagForDirectProfiles(userId string) StoreChannel
|
GetEtagForDirectProfiles(userId string) StoreChannel
|
||||||
UpdateFailedPasswordAttempts(userId string, attempts int) StoreChannel
|
UpdateFailedPasswordAttempts(userId string, attempts int) StoreChannel
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ func getClientConfig(c *model.Config) map[string]string {
|
|||||||
props["EnableUserCreation"] = strconv.FormatBool(c.TeamSettings.EnableUserCreation)
|
props["EnableUserCreation"] = strconv.FormatBool(c.TeamSettings.EnableUserCreation)
|
||||||
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
|
props["EnableOpenServer"] = strconv.FormatBool(*c.TeamSettings.EnableOpenServer)
|
||||||
props["RestrictTeamNames"] = strconv.FormatBool(*c.TeamSettings.RestrictTeamNames)
|
props["RestrictTeamNames"] = strconv.FormatBool(*c.TeamSettings.RestrictTeamNames)
|
||||||
|
props["RestrictDirectMessage"] = *c.TeamSettings.RestrictDirectMessage
|
||||||
|
|
||||||
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
|
props["EnableOAuthServiceProvider"] = strconv.FormatBool(c.ServiceSettings.EnableOAuthServiceProvider)
|
||||||
props["SegmentDeveloperKey"] = c.ServiceSettings.SegmentDeveloperKey
|
props["SegmentDeveloperKey"] = c.ServiceSettings.SegmentDeveloperKey
|
||||||
|
|||||||
@@ -157,6 +157,11 @@ export function emitPostFocusEvent(postId) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function emitProfilesForDmList() {
|
||||||
|
AsyncClient.getProfilesForDirectMessageList();
|
||||||
|
AsyncClient.getTeamMembers(TeamStore.getCurrentId());
|
||||||
|
}
|
||||||
|
|
||||||
export function emitCloseRightHandSide() {
|
export function emitCloseRightHandSide() {
|
||||||
AppDispatcher.handleServerAction({
|
AppDispatcher.handleServerAction({
|
||||||
type: ActionTypes.RECEIVED_SEARCH,
|
type: ActionTypes.RECEIVED_SEARCH,
|
||||||
@@ -335,6 +340,10 @@ export function emitClearSuggestions(suggestionId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function emitPreferenceChangedEvent(preference) {
|
export function emitPreferenceChangedEvent(preference) {
|
||||||
|
if (preference.category === Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW) {
|
||||||
|
AsyncClient.getDirectProfiles();
|
||||||
|
}
|
||||||
|
|
||||||
AppDispatcher.handleServerAction({
|
AppDispatcher.handleServerAction({
|
||||||
type: Constants.ActionTypes.RECEIVED_PREFERENCE,
|
type: Constants.ActionTypes.RECEIVED_PREFERENCE,
|
||||||
preference
|
preference
|
||||||
|
|||||||
@@ -862,13 +862,22 @@ export default class Client {
|
|||||||
|
|
||||||
getProfilesForTeam = (teamId, success, error) => {
|
getProfilesForTeam = (teamId, success, error) => {
|
||||||
request.
|
request.
|
||||||
get(`${this.getUsersRoute()}/profiles/${teamId}?skip_direct=true`).
|
get(`${this.getUsersRoute()}/profiles/${teamId}`).
|
||||||
set(this.defaultHeaders).
|
set(this.defaultHeaders).
|
||||||
type('application/json').
|
type('application/json').
|
||||||
accept('application/json').
|
accept('application/json').
|
||||||
end(this.handleResponse.bind(this, 'getProfilesForTeam', success, error));
|
end(this.handleResponse.bind(this, 'getProfilesForTeam', success, error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProfilesForDirectMessageList = (success, error) => {
|
||||||
|
request.
|
||||||
|
get(`${this.getUsersRoute()}/profiles_for_dm_list/${this.getTeamId()}`).
|
||||||
|
set(this.defaultHeaders).
|
||||||
|
type('application/json').
|
||||||
|
accept('application/json').
|
||||||
|
end(this.handleResponse.bind(this, 'getProfilesForDirectMessageList', success, error));
|
||||||
|
}
|
||||||
|
|
||||||
getStatuses = (ids, success, error) => {
|
getStatuses = (ids, success, error) => {
|
||||||
request.
|
request.
|
||||||
post(`${this.getUsersRoute()}/status`).
|
post(`${this.getUsersRoute()}/status`).
|
||||||
|
|||||||
@@ -24,6 +24,14 @@ const holders = defineMessages({
|
|||||||
saving: {
|
saving: {
|
||||||
id: 'admin.team.saving',
|
id: 'admin.team.saving',
|
||||||
defaultMessage: 'Saving Config...'
|
defaultMessage: 'Saving Config...'
|
||||||
|
},
|
||||||
|
restrictDirectMessageAny: {
|
||||||
|
id: 'admin.team.restrict_direct_message_any',
|
||||||
|
defaultMessage: 'Any user on the Mattermost server'
|
||||||
|
},
|
||||||
|
restrictDirectMessageTeam: {
|
||||||
|
id: 'admin.team.restrict_direct_message_team',
|
||||||
|
defaultMessage: 'Any member of the team'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,6 +56,7 @@ class TeamSettings extends React.Component {
|
|||||||
saveNeeded: false,
|
saveNeeded: false,
|
||||||
brandImageExists: false,
|
brandImageExists: false,
|
||||||
enableCustomBrand: this.props.config.TeamSettings.EnableCustomBrand,
|
enableCustomBrand: this.props.config.TeamSettings.EnableCustomBrand,
|
||||||
|
restrictDirectMessage: this.props.config.TeamSettings.RestrictDirectMessage,
|
||||||
serverError: null
|
serverError: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -104,6 +113,7 @@ class TeamSettings extends React.Component {
|
|||||||
config.TeamSettings.EnableUserCreation = this.refs.EnableUserCreation.checked;
|
config.TeamSettings.EnableUserCreation = this.refs.EnableUserCreation.checked;
|
||||||
config.TeamSettings.EnableOpenServer = this.refs.EnableOpenServer.checked;
|
config.TeamSettings.EnableOpenServer = this.refs.EnableOpenServer.checked;
|
||||||
config.TeamSettings.RestrictTeamNames = this.refs.RestrictTeamNames.checked;
|
config.TeamSettings.RestrictTeamNames = this.refs.RestrictTeamNames.checked;
|
||||||
|
config.TeamSettings.RestrictDirectMessage = this.refs.RestrictDirectMessage.value.trim();
|
||||||
|
|
||||||
if (this.refs.EnableCustomBrand) {
|
if (this.refs.EnableCustomBrand) {
|
||||||
config.TeamSettings.EnableCustomBrand = this.refs.EnableCustomBrand.checked;
|
config.TeamSettings.EnableCustomBrand = this.refs.EnableCustomBrand.checked;
|
||||||
@@ -660,6 +670,36 @@ class TeamSettings extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className='form-group'>
|
||||||
|
<label
|
||||||
|
className='control-label col-sm-4'
|
||||||
|
htmlFor='restrictDirectMessage'
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='admin.team.restrictDirectMessage'
|
||||||
|
defaultMessage='Enable users to open Direct Message channels with:'
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<div className='col-sm-8'>
|
||||||
|
<select
|
||||||
|
className='form-control'
|
||||||
|
id='restrictDirectMessage'
|
||||||
|
ref='RestrictDirectMessage'
|
||||||
|
defaultValue={this.props.config.TeamSettings.RestrictDirectMessage}
|
||||||
|
onChange={this.handleChange.bind(this, 'restrictDirectMessage')}
|
||||||
|
>
|
||||||
|
<option value='any'>{formatMessage(holders.restrictDirectMessageAny)}</option>
|
||||||
|
<option value='team'>{formatMessage(holders.restrictDirectMessageTeam)}</option>
|
||||||
|
</select>
|
||||||
|
<p className='help-text'>
|
||||||
|
<FormattedHTMLMessage
|
||||||
|
id='admin.team.restrictDirectMessageDesc'
|
||||||
|
defaultMessage='"Any user on the Mattermost server" enables users to open a Direct Message channel with any user on the server, even if they are not on any teams together. "Any member of the team" limits the ability to open Direct Message channels to only users who are in the same team.'
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{brand}
|
{brand}
|
||||||
|
|
||||||
<div className='form-group'>
|
<div className='form-group'>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import $ from 'jquery';
|
|||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import Client from 'utils/web_client.jsx';
|
import Client from 'utils/web_client.jsx';
|
||||||
|
import * as AsyncClient from 'utils/async_client.jsx';
|
||||||
import TeamStore from 'stores/team_store.jsx';
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
@@ -99,6 +100,7 @@ class TeamUrl extends React.Component {
|
|||||||
(team) => {
|
(team) => {
|
||||||
Client.track('signup', 'signup_team_08_complete');
|
Client.track('signup', 'signup_team_08_complete');
|
||||||
$('#sign-up-button').button('reset');
|
$('#sign-up-button').button('reset');
|
||||||
|
AsyncClient.getDirectProfiles();
|
||||||
TeamStore.saveTeam(team);
|
TeamStore.saveTeam(team);
|
||||||
TeamStore.appendTeamMember({team_id: team.id, user_id: UserStore.getCurrentId(), roles: 'admin'});
|
TeamStore.appendTeamMember({team_id: team.id, user_id: UserStore.getCurrentId(), roles: 'admin'});
|
||||||
TeamStore.emitChange();
|
TeamStore.emitChange();
|
||||||
|
|||||||
@@ -15,6 +15,14 @@ const holders = defineMessages({
|
|||||||
search: {
|
search: {
|
||||||
id: 'filtered_user_list.search',
|
id: 'filtered_user_list.search',
|
||||||
defaultMessage: 'Search members'
|
defaultMessage: 'Search members'
|
||||||
|
},
|
||||||
|
anyTeam: {
|
||||||
|
id: 'filtered_user_list.any_team',
|
||||||
|
defaultMessage: 'All Users'
|
||||||
|
},
|
||||||
|
teamOnly: {
|
||||||
|
id: 'filtered_user_list.team_only',
|
||||||
|
defaultMessage: 'Members of this Team'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -25,9 +33,13 @@ class FilteredUserList extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.handleFilterChange = this.handleFilterChange.bind(this);
|
this.handleFilterChange = this.handleFilterChange.bind(this);
|
||||||
|
this.handleListChange = this.handleListChange.bind(this);
|
||||||
|
this.filterUsers = this.filterUsers.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
filter: ''
|
filter: '',
|
||||||
|
users: this.filterUsers(props.teamMembers, props.users),
|
||||||
|
selected: 'team'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,18 +49,49 @@ class FilteredUserList extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filterUsers(teamMembers, users) {
|
||||||
|
if (!teamMembers || teamMembers.length === 0) {
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
var filteredUsers = users.filter((user) => {
|
||||||
|
for (const index in teamMembers) {
|
||||||
|
if (teamMembers.hasOwnProperty(index) && teamMembers[index].user_id === user.id) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return filteredUsers;
|
||||||
|
}
|
||||||
|
|
||||||
handleFilterChange(e) {
|
handleFilterChange(e) {
|
||||||
this.setState({
|
this.setState({
|
||||||
filter: e.target.value
|
filter: e.target.value
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleListChange(e) {
|
||||||
|
var users = this.props.users;
|
||||||
|
|
||||||
|
if (e.target.value === 'team') {
|
||||||
|
users = this.filterUsers(this.props.teamMembers, this.props.users);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
selected: e.target.value,
|
||||||
|
users
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {formatMessage} = this.props.intl;
|
const {formatMessage} = this.props.intl;
|
||||||
|
|
||||||
let users = this.props.users;
|
let users = this.state.users;
|
||||||
|
|
||||||
if (this.state.filter) {
|
if (this.state.filter && this.state.filter.length > 0) {
|
||||||
const filter = this.state.filter.toLowerCase();
|
const filter = this.state.filter.toLowerCase();
|
||||||
|
|
||||||
users = users.filter((user) => {
|
users = users.filter((user) => {
|
||||||
@@ -60,7 +103,7 @@ class FilteredUserList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let count;
|
let count;
|
||||||
if (users.length === this.props.users.length) {
|
if (users.length === this.state.users.length) {
|
||||||
count = (
|
count = (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='filtered_user_list.count'
|
id='filtered_user_list.count'
|
||||||
@@ -77,12 +120,42 @@ class FilteredUserList extends React.Component {
|
|||||||
defaultMessage='{count} {count, plural, =0 {0 members} one {member} other {members}} of {total} Total'
|
defaultMessage='{count} {count, plural, =0 {0 members} one {member} other {members}} of {total} Total'
|
||||||
values={{
|
values={{
|
||||||
count: users.length,
|
count: users.length,
|
||||||
total: this.props.users.length
|
total: this.state.users.length
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let teamToggle;
|
||||||
|
|
||||||
|
let teamMembers = this.props.teamMembers;
|
||||||
|
if (this.props.showTeamToggle) {
|
||||||
|
teamMembers = [];
|
||||||
|
|
||||||
|
teamToggle = (
|
||||||
|
<div className='col-sm-6'>
|
||||||
|
<select
|
||||||
|
className='form-control member-select'
|
||||||
|
id='restrictList'
|
||||||
|
ref='restrictList'
|
||||||
|
defaultValue='team'
|
||||||
|
onChange={this.handleListChange}
|
||||||
|
>
|
||||||
|
<option value='any'>{formatMessage(holders.anyTeam)}</option>
|
||||||
|
<option value='team'>{formatMessage(holders.teamOnly)}</option>
|
||||||
|
</select>
|
||||||
|
<span
|
||||||
|
className='member-show'
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id='filtered_user_list.show'
|
||||||
|
defaultMessage='Show'
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='filtered-user-list'
|
className='filtered-user-list'
|
||||||
@@ -100,6 +173,7 @@ class FilteredUserList extends React.Component {
|
|||||||
<div className='col-sm-6'>
|
<div className='col-sm-6'>
|
||||||
<span className='member-count'>{count}</span>
|
<span className='member-count'>{count}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{teamToggle}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
ref='userList'
|
ref='userList'
|
||||||
@@ -107,7 +181,7 @@ class FilteredUserList extends React.Component {
|
|||||||
>
|
>
|
||||||
<UserList
|
<UserList
|
||||||
users={users}
|
users={users}
|
||||||
teamMembers={this.props.teamMembers}
|
teamMembers={teamMembers}
|
||||||
actions={this.props.actions}
|
actions={this.props.actions}
|
||||||
actionProps={this.props.actionProps}
|
actionProps={this.props.actionProps}
|
||||||
/>
|
/>
|
||||||
@@ -121,7 +195,8 @@ FilteredUserList.defaultProps = {
|
|||||||
users: [],
|
users: [],
|
||||||
teamMembers: [],
|
teamMembers: [],
|
||||||
actions: [],
|
actions: [],
|
||||||
actionProps: {}
|
actionProps: {},
|
||||||
|
showTeamToggle: false
|
||||||
};
|
};
|
||||||
|
|
||||||
FilteredUserList.propTypes = {
|
FilteredUserList.propTypes = {
|
||||||
@@ -130,6 +205,7 @@ FilteredUserList.propTypes = {
|
|||||||
teamMembers: React.PropTypes.arrayOf(React.PropTypes.object),
|
teamMembers: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||||
actions: React.PropTypes.arrayOf(React.PropTypes.func),
|
actions: React.PropTypes.arrayOf(React.PropTypes.func),
|
||||||
actionProps: React.PropTypes.object,
|
actionProps: React.PropTypes.object,
|
||||||
|
showTeamToggle: React.PropTypes.bool,
|
||||||
style: React.PropTypes.object
|
style: React.PropTypes.object
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,14 @@
|
|||||||
import {Modal} from 'react-bootstrap';
|
import {Modal} from 'react-bootstrap';
|
||||||
import FilteredUserList from './filtered_user_list.jsx';
|
import FilteredUserList from './filtered_user_list.jsx';
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
|
import * as GlobalActions from 'action_creators/global_actions.jsx';
|
||||||
|
|
||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
import {browserHistory} from 'react-router';
|
import {browserHistory} from 'react-router';
|
||||||
import SpinnerButton from 'components/spinner_button.jsx';
|
import SpinnerButton from 'components/spinner_button.jsx';
|
||||||
|
import LoadingScreen from 'components/loading_screen.jsx';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
@@ -17,38 +20,27 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.handleHide = this.handleHide.bind(this);
|
this.handleHide = this.handleHide.bind(this);
|
||||||
|
this.handleOnEnter = this.handleOnEnter.bind(this);
|
||||||
this.handleShowDirectChannel = this.handleShowDirectChannel.bind(this);
|
this.handleShowDirectChannel = this.handleShowDirectChannel.bind(this);
|
||||||
this.handleUserChange = this.handleUserChange.bind(this);
|
this.handleUserChange = this.handleUserChange.bind(this);
|
||||||
|
this.onTeamChange = this.onTeamChange.bind(this);
|
||||||
this.createJoinDirectChannelButton = this.createJoinDirectChannelButton.bind(this);
|
this.createJoinDirectChannelButton = this.createJoinDirectChannelButton.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
users: this.getUsersFromStore(),
|
users: null,
|
||||||
|
teamMembers: null,
|
||||||
loadingDMChannel: -1
|
loadingDMChannel: -1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getUsersFromStore() {
|
|
||||||
const currentId = UserStore.getCurrentId();
|
|
||||||
const profiles = UserStore.getActiveOnlyProfiles();
|
|
||||||
const users = [];
|
|
||||||
|
|
||||||
for (const id in profiles) {
|
|
||||||
if (id !== currentId) {
|
|
||||||
users.push(profiles[id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
users.sort((a, b) => a.username.localeCompare(b.username));
|
|
||||||
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
UserStore.addChangeListener(this.handleUserChange);
|
UserStore.addDmListChangeListener(this.handleUserChange);
|
||||||
|
TeamStore.addChangeListener(this.onTeamChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
UserStore.removeChangeListener(this.handleUserChange);
|
UserStore.removeDmListChangeListener(this.handleUserChange);
|
||||||
|
TeamStore.removeChangeListener(this.onTeamChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
@@ -77,6 +69,17 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleOnEnter() {
|
||||||
|
this.setState({
|
||||||
|
users: null,
|
||||||
|
teamMembers: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOnEntered() {
|
||||||
|
GlobalActions.emitProfilesForDmList();
|
||||||
|
}
|
||||||
|
|
||||||
handleShowDirectChannel(teammate, e) {
|
handleShowDirectChannel(teammate, e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
@@ -99,7 +102,15 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleUserChange() {
|
handleUserChange() {
|
||||||
this.setState({users: this.getUsersFromStore()});
|
this.setState({
|
||||||
|
users: UserStore.getProfilesForDmList()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onTeamChange() {
|
||||||
|
this.setState({
|
||||||
|
teamMembers: TeamStore.getMembersForTeam()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createJoinDirectChannelButton({user}) {
|
createJoinDirectChannelButton({user}) {
|
||||||
@@ -123,11 +134,33 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
maxHeight = Utils.windowHeight() - 300;
|
maxHeight = Utils.windowHeight() - 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var body = null;
|
||||||
|
if (this.state.users == null || this.state.teamMembers == null) {
|
||||||
|
body = (<LoadingScreen/>);
|
||||||
|
} else {
|
||||||
|
var showTeamToggle = false;
|
||||||
|
if (global.window.mm_config.RestrictDirectMessage === 'any') {
|
||||||
|
showTeamToggle = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
body = (
|
||||||
|
<FilteredUserList
|
||||||
|
style={{maxHeight}}
|
||||||
|
users={this.state.users}
|
||||||
|
teamMembers={this.state.teamMembers}
|
||||||
|
actions={[this.createJoinDirectChannelButton]}
|
||||||
|
showTeamToggle={showTeamToggle}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
dialogClassName='more-modal more-direct-channels'
|
dialogClassName='more-modal more-direct-channels'
|
||||||
show={this.props.show}
|
show={this.props.show}
|
||||||
onHide={this.handleHide}
|
onHide={this.handleHide}
|
||||||
|
onEnter={this.handleOnEnter}
|
||||||
|
onEntered={this.handleOnEntered}
|
||||||
>
|
>
|
||||||
<Modal.Header closeButton={true}>
|
<Modal.Header closeButton={true}>
|
||||||
<Modal.Title>
|
<Modal.Title>
|
||||||
@@ -138,11 +171,7 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
</Modal.Title>
|
</Modal.Title>
|
||||||
</Modal.Header>
|
</Modal.Header>
|
||||||
<Modal.Body>
|
<Modal.Body>
|
||||||
<FilteredUserList
|
{body}
|
||||||
style={{maxHeight}}
|
|
||||||
users={this.state.users}
|
|
||||||
actions={[this.createJoinDirectChannelButton]}
|
|
||||||
/>
|
|
||||||
</Modal.Body>
|
</Modal.Body>
|
||||||
<Modal.Footer>
|
<Modal.Footer>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -124,8 +124,6 @@ export default class Sidebar extends React.Component {
|
|||||||
|
|
||||||
directChannels.sort(this.sortChannelsByDisplayName);
|
directChannels.sort(this.sortChannelsByDisplayName);
|
||||||
|
|
||||||
const hiddenDirectChannelCount = UserStore.getActiveOnlyProfileList(true).length - directChannels.length;
|
|
||||||
|
|
||||||
const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999);
|
const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -134,7 +132,6 @@ export default class Sidebar extends React.Component {
|
|||||||
publicChannels,
|
publicChannels,
|
||||||
privateChannels,
|
privateChannels,
|
||||||
directChannels,
|
directChannels,
|
||||||
hiddenDirectChannelCount,
|
|
||||||
unreadCounts: JSON.parse(JSON.stringify(ChannelStore.getUnreadCounts())),
|
unreadCounts: JSON.parse(JSON.stringify(ChannelStore.getUnreadCounts())),
|
||||||
showTutorialTip: tutorialStep === TutorialSteps.CHANNEL_POPOVER,
|
showTutorialTip: tutorialStep === TutorialSteps.CHANNEL_POPOVER,
|
||||||
currentTeam: TeamStore.getCurrent(),
|
currentTeam: TeamStore.getCurrent(),
|
||||||
@@ -527,25 +524,19 @@ export default class Sidebar extends React.Component {
|
|||||||
}
|
}
|
||||||
head.appendChild(link);
|
head.appendChild(link);
|
||||||
|
|
||||||
var directMessageMore = null;
|
var directMessageMore = (
|
||||||
if (this.state.hiddenDirectChannelCount > 0) {
|
<li key='more'>
|
||||||
directMessageMore = (
|
<a
|
||||||
<li key='more'>
|
href='#'
|
||||||
<a
|
onClick={this.showMoreDirectChannelsModal}
|
||||||
href='#'
|
>
|
||||||
onClick={this.showMoreDirectChannelsModal}
|
<FormattedMessage
|
||||||
>
|
id='sidebar.more'
|
||||||
<FormattedMessage
|
defaultMessage='More'
|
||||||
id='sidebar.more'
|
/>
|
||||||
defaultMessage='More ({count})'
|
</a>
|
||||||
values={{
|
</li>
|
||||||
count: this.state.hiddenDirectChannelCount
|
);
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let showChannelModal = false;
|
let showChannelModal = false;
|
||||||
if (this.state.newChannelModalType !== '') {
|
if (this.state.newChannelModalType !== '') {
|
||||||
|
|||||||
@@ -542,6 +542,10 @@
|
|||||||
"admin.team.userCreationTitle": "Enable User Creation: ",
|
"admin.team.userCreationTitle": "Enable User Creation: ",
|
||||||
"admin.team_analytics.activeUsers": "Active Users With Posts",
|
"admin.team_analytics.activeUsers": "Active Users With Posts",
|
||||||
"admin.team_analytics.totalPosts": "Total Posts",
|
"admin.team_analytics.totalPosts": "Total Posts",
|
||||||
|
"admin.team.restrictDirectMessage": "Enable users to open Direct Message channels with:",
|
||||||
|
"admin.team.restrictDirectMessageDesc": "'Any user on the Mattermost server' enables users to open a Direct Message channel with any user on the server, even if they are not on any teams together. 'Any member of the team' limits the ability to open Direct Message channels to only users who are in the same team.",
|
||||||
|
"admin.team.restrict_direct_message_any": "Any user on the Mattermost server",
|
||||||
|
"admin.team.restrict_direct_message_team": "Any member of the team",
|
||||||
"admin.userList.title": "Users for {team}",
|
"admin.userList.title": "Users for {team}",
|
||||||
"admin.userList.title2": "Users for {team} ({count})",
|
"admin.userList.title2": "Users for {team} ({count})",
|
||||||
"admin.user_item.authServiceEmail": ", <strong>Sign-in Method:</strong> Email",
|
"admin.user_item.authServiceEmail": ", <strong>Sign-in Method:</strong> Email",
|
||||||
@@ -859,6 +863,9 @@
|
|||||||
"file_upload.pasted": "Image Pasted at ",
|
"file_upload.pasted": "Image Pasted at ",
|
||||||
"filtered_user_list.count": "{count} {count, plural, =0 {0 members} one {member} other {members}}",
|
"filtered_user_list.count": "{count} {count, plural, =0 {0 members} one {member} other {members}}",
|
||||||
"filtered_user_list.countTotal": "{count} {count, plural, =0 {0 members} one {member} other {members}} of {total} Total",
|
"filtered_user_list.countTotal": "{count} {count, plural, =0 {0 members} one {member} other {members}} of {total} Total",
|
||||||
|
"filtered_user_list.show": "Show",
|
||||||
|
"filtered_user_list.any_team": "All Users",
|
||||||
|
"filtered_user_list.team_only": "Members of this Team",
|
||||||
"filtered_user_list.member": "Member",
|
"filtered_user_list.member": "Member",
|
||||||
"filtered_user_list.search": "Search members",
|
"filtered_user_list.search": "Search members",
|
||||||
"find_team.email": "Email",
|
"find_team.email": "Email",
|
||||||
@@ -1120,7 +1127,7 @@
|
|||||||
"sidebar.createChannel": "Create new channel",
|
"sidebar.createChannel": "Create new channel",
|
||||||
"sidebar.createGroup": "Create new group",
|
"sidebar.createGroup": "Create new group",
|
||||||
"sidebar.direct": "Direct Messages",
|
"sidebar.direct": "Direct Messages",
|
||||||
"sidebar.more": "More ({count})",
|
"sidebar.more": "More",
|
||||||
"sidebar.moreElips": "More...",
|
"sidebar.moreElips": "More...",
|
||||||
"sidebar.pg": "Private Groups",
|
"sidebar.pg": "Private Groups",
|
||||||
"sidebar.removeList": "Remove from list",
|
"sidebar.removeList": "Remove from list",
|
||||||
|
|||||||
@@ -1118,7 +1118,7 @@
|
|||||||
"sidebar.createChannel": "Crear un nuevo canal",
|
"sidebar.createChannel": "Crear un nuevo canal",
|
||||||
"sidebar.createGroup": "Crear un nuevo grupo",
|
"sidebar.createGroup": "Crear un nuevo grupo",
|
||||||
"sidebar.direct": "Mensajes Directos",
|
"sidebar.direct": "Mensajes Directos",
|
||||||
"sidebar.more": "Más ({count})",
|
"sidebar.more": "Más",
|
||||||
"sidebar.moreElips": "Más...",
|
"sidebar.moreElips": "Más...",
|
||||||
"sidebar.pg": "Grupos Privados",
|
"sidebar.pg": "Grupos Privados",
|
||||||
"sidebar.removeList": "Remover de la lista",
|
"sidebar.removeList": "Remover de la lista",
|
||||||
|
|||||||
@@ -976,7 +976,7 @@
|
|||||||
"sidebar.createChannel": "Créer un nouveau canal",
|
"sidebar.createChannel": "Créer un nouveau canal",
|
||||||
"sidebar.createGroup": "Créer un nouveau groupe",
|
"sidebar.createGroup": "Créer un nouveau groupe",
|
||||||
"sidebar.direct": "Messages privés",
|
"sidebar.direct": "Messages privés",
|
||||||
"sidebar.more": "Plus ({count})",
|
"sidebar.more": "Plus",
|
||||||
"sidebar.moreElips": "Plus...",
|
"sidebar.moreElips": "Plus...",
|
||||||
"sidebar.pg": "Groupes privés",
|
"sidebar.pg": "Groupes privés",
|
||||||
"sidebar.removeList": "Retirer de la liste",
|
"sidebar.removeList": "Retirer de la liste",
|
||||||
|
|||||||
@@ -1078,7 +1078,7 @@
|
|||||||
"sidebar.createChannel": "新しいチャンネルを作成する",
|
"sidebar.createChannel": "新しいチャンネルを作成する",
|
||||||
"sidebar.createGroup": "新しいグループを作成する",
|
"sidebar.createGroup": "新しいグループを作成する",
|
||||||
"sidebar.direct": "ダイレクトメッセージ",
|
"sidebar.direct": "ダイレクトメッセージ",
|
||||||
"sidebar.more": "もっと表示する({count})",
|
"sidebar.more": "もっと表示する",
|
||||||
"sidebar.moreElips": "もっと…",
|
"sidebar.moreElips": "もっと…",
|
||||||
"sidebar.pg": "非公開グループ",
|
"sidebar.pg": "非公開グループ",
|
||||||
"sidebar.removeList": "一覧から削除する",
|
"sidebar.removeList": "一覧から削除する",
|
||||||
|
|||||||
@@ -1120,7 +1120,7 @@
|
|||||||
"sidebar.createChannel": "Criar novo canal",
|
"sidebar.createChannel": "Criar novo canal",
|
||||||
"sidebar.createGroup": "Criar um novo grupo",
|
"sidebar.createGroup": "Criar um novo grupo",
|
||||||
"sidebar.direct": "Mensagens Diretas",
|
"sidebar.direct": "Mensagens Diretas",
|
||||||
"sidebar.more": "Mais ({count})",
|
"sidebar.more": "Mais",
|
||||||
"sidebar.moreElips": "Mais...",
|
"sidebar.moreElips": "Mais...",
|
||||||
"sidebar.pg": "Grupos Privados",
|
"sidebar.pg": "Grupos Privados",
|
||||||
"sidebar.removeList": "Remover da lista",
|
"sidebar.removeList": "Remover da lista",
|
||||||
|
|||||||
@@ -436,6 +436,21 @@
|
|||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.member-show {
|
||||||
|
@include opacity(.8);
|
||||||
|
float: right;
|
||||||
|
margin-top: 12px;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-select {
|
||||||
|
@include opacity(.8);
|
||||||
|
float: right;
|
||||||
|
width: auto;
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.more-purpose {
|
.more-purpose {
|
||||||
@include opacity(.7);
|
@include opacity(.7);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import EventEmitter from 'events';
|
|||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
const ActionTypes = Constants.ActionTypes;
|
const ActionTypes = Constants.ActionTypes;
|
||||||
|
|
||||||
|
const CHANGE_EVENT_DM_LIST = 'change_dm_list';
|
||||||
const CHANGE_EVENT = 'change';
|
const CHANGE_EVENT = 'change';
|
||||||
const CHANGE_EVENT_SESSIONS = 'change_sessions';
|
const CHANGE_EVENT_SESSIONS = 'change_sessions';
|
||||||
const CHANGE_EVENT_AUDITS = 'change_audits';
|
const CHANGE_EVENT_AUDITS = 'change_audits';
|
||||||
@@ -19,6 +20,7 @@ class UserStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
|
this.profiles_for_dm_list = {};
|
||||||
this.profiles = {};
|
this.profiles = {};
|
||||||
this.direct_profiles = {};
|
this.direct_profiles = {};
|
||||||
this.statuses = {};
|
this.statuses = {};
|
||||||
@@ -40,6 +42,18 @@ class UserStoreClass extends EventEmitter {
|
|||||||
this.removeListener(CHANGE_EVENT, callback);
|
this.removeListener(CHANGE_EVENT, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emitDmListChange() {
|
||||||
|
this.emit(CHANGE_EVENT_DM_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
addDmListChangeListener(callback) {
|
||||||
|
this.on(CHANGE_EVENT_DM_LIST, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeDmListChangeListener(callback) {
|
||||||
|
this.removeListener(CHANGE_EVENT_DM_LIST, callback);
|
||||||
|
}
|
||||||
|
|
||||||
emitSessionsChange() {
|
emitSessionsChange() {
|
||||||
this.emit(CHANGE_EVENT_SESSIONS);
|
this.emit(CHANGE_EVENT_SESSIONS);
|
||||||
}
|
}
|
||||||
@@ -190,6 +204,29 @@ class UserStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProfilesForDmList() {
|
||||||
|
const currentId = this.getCurrentId();
|
||||||
|
const profiles = [];
|
||||||
|
|
||||||
|
for (const id in this.profiles_for_dm_list) {
|
||||||
|
if (this.profiles_for_dm_list.hasOwnProperty(id) && id !== currentId) {
|
||||||
|
var profile = this.profiles_for_dm_list[id];
|
||||||
|
|
||||||
|
if (profile.delete_at === 0) {
|
||||||
|
profiles.push(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
profiles.sort((a, b) => a.username.localeCompare(b.username));
|
||||||
|
|
||||||
|
return profiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveProfilesForDmList(profiles) {
|
||||||
|
this.profiles_for_dm_list = profiles;
|
||||||
|
}
|
||||||
|
|
||||||
setSessions(sessions) {
|
setSessions(sessions) {
|
||||||
this.sessions = sessions;
|
this.sessions = sessions;
|
||||||
}
|
}
|
||||||
@@ -278,6 +315,10 @@ UserStore.dispatchToken = AppDispatcher.register((payload) => {
|
|||||||
var action = payload.action;
|
var action = payload.action;
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case ActionTypes.RECEIVED_PROFILES_FOR_DM_LIST:
|
||||||
|
UserStore.saveProfilesForDmList(action.profiles);
|
||||||
|
UserStore.emitDmListChange();
|
||||||
|
break;
|
||||||
case ActionTypes.RECEIVED_PROFILES:
|
case ActionTypes.RECEIVED_PROFILES:
|
||||||
UserStore.saveProfiles(action.profiles);
|
UserStore.saveProfiles(action.profiles);
|
||||||
UserStore.emitChange();
|
UserStore.emitChange();
|
||||||
|
|||||||
@@ -480,6 +480,20 @@ describe('Client.User', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('getProfilesForDirectMessageList', function(done) {
|
||||||
|
TestHelper.initBasic(() => {
|
||||||
|
TestHelper.basicClient().getProfilesForDirectMessageList(
|
||||||
|
function(data) {
|
||||||
|
assert.equal(Object.keys(data).length > 0, true);
|
||||||
|
done();
|
||||||
|
},
|
||||||
|
function(err) {
|
||||||
|
done(new Error(err.message));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('getStatuses', function(done) {
|
it('getStatuses', function(done) {
|
||||||
TestHelper.initBasic(() => {
|
TestHelper.initBasic(() => {
|
||||||
var ids = [];
|
var ids = [];
|
||||||
|
|||||||
@@ -224,6 +224,28 @@ export function getTeamMembers(teamId) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getProfilesForDirectMessageList() {
|
||||||
|
if (isCallInProgress('getProfilesForDirectMessageList')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callTracker.getProfilesForDirectMessageList = utils.getTimestamp();
|
||||||
|
Client.getProfilesForDirectMessageList(
|
||||||
|
(data) => {
|
||||||
|
callTracker.getProfilesForDirectMessageList = 0;
|
||||||
|
|
||||||
|
AppDispatcher.handleServerAction({
|
||||||
|
type: ActionTypes.RECEIVED_PROFILES_FOR_DM_LIST,
|
||||||
|
profiles: data
|
||||||
|
});
|
||||||
|
},
|
||||||
|
(err) => {
|
||||||
|
callTracker.getProfilesForDirectMessageList = 0;
|
||||||
|
dispatchError(err, 'getProfilesForDirectMessageList');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function getProfiles() {
|
export function getProfiles() {
|
||||||
if (isCallInProgress('getProfiles')) {
|
if (isCallInProgress('getProfiles')) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export default {
|
|||||||
RECEIVED_MENTION_DATA: null,
|
RECEIVED_MENTION_DATA: null,
|
||||||
RECEIVED_ADD_MENTION: null,
|
RECEIVED_ADD_MENTION: null,
|
||||||
|
|
||||||
|
RECEIVED_PROFILES_FOR_DM_LIST: null,
|
||||||
RECEIVED_PROFILES: null,
|
RECEIVED_PROFILES: null,
|
||||||
RECEIVED_DIRECT_PROFILES: null,
|
RECEIVED_DIRECT_PROFILES: null,
|
||||||
RECEIVED_ME: null,
|
RECEIVED_ME: null,
|
||||||
|
|||||||
@@ -1247,6 +1247,13 @@ export function openDirectChannelToUser(user, successCb, errorCb) {
|
|||||||
'true'
|
'true'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// if the user in another team and isn't already in the direct message
|
||||||
|
// list then we should add him so his name shows up correctly.
|
||||||
|
var profileUser = UserStore.getProfile(user.id);
|
||||||
|
if (!profileUser) {
|
||||||
|
UserStore.getDirectProfiles()[user.id] = user;
|
||||||
|
}
|
||||||
|
|
||||||
const channelName = this.getDirectChannelName(UserStore.getCurrentId(), user.id);
|
const channelName = this.getDirectChannelName(UserStore.getCurrentId(), user.id);
|
||||||
let channel = ChannelStore.getByName(channelName);
|
let channel = ChannelStore.getByName(channelName);
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user