summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/channel.go12
-rw-r--r--app/import.go144
-rw-r--r--app/import_test.go393
-rw-r--r--app/team.go30
-rw-r--r--i18n/en.json16
5 files changed, 581 insertions, 14 deletions
diff --git a/app/channel.go b/app/channel.go
index aba65143b..1f5d308bf 100644
--- a/app/channel.go
+++ b/app/channel.go
@@ -336,7 +336,7 @@ func DeleteChannel(channel *model.Channel, userId string) *model.AppError {
return nil
}
-func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError) {
+func addUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError) {
if channel.DeleteAt > 0 {
return nil, model.NewLocAppError("AddUserToChannel", "api.channel.add_user_to_channel.deleted.app_error", nil, "")
}
@@ -380,6 +380,16 @@ func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelM
InvalidateCacheForUser(user.Id)
InvalidateCacheForChannelMembers(channel.Id)
+ return newMember, nil
+}
+
+func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelMember, *model.AppError) {
+
+ newMember, err := addUserToChannel(user, channel)
+ if err != nil {
+ return nil, err
+ }
+
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_USER_ADDED, "", channel.Id, "", nil)
message.Add("user_id", user.Id)
message.Add("team_id", channel.TeamId)
diff --git a/app/import.go b/app/import.go
index e99dd79dc..4a27bcd7e 100644
--- a/app/import.go
+++ b/app/import.go
@@ -55,6 +55,19 @@ type UserImportData struct {
Position *string `json:"position"`
Roles *string `json:"roles"`
Locale *string `json:"locale"`
+
+ Teams *[]UserTeamImportData `json:"teams"`
+}
+
+type UserTeamImportData struct {
+ Name *string `json:"name"`
+ Roles *string `json:"roles"`
+ Channels *[]UserChannelImportData `json:"channels"`
+}
+
+type UserChannelImportData struct {
+ Name *string `json:"name"`
+ Roles *string `json:"roles"`
}
//
@@ -376,6 +389,91 @@ func ImportUser(data *UserImportData, dryRun bool) *model.AppError {
}
}
+ return ImportUserTeams(*data.Username, data.Teams)
+}
+
+func ImportUserTeams(username string, data *[]UserTeamImportData) *model.AppError {
+ if data == nil {
+ return nil
+ }
+
+ user, err := GetUserByUsername(username)
+ if err != nil {
+ return err
+ }
+
+ for _, tdata := range *data {
+ team, err := GetTeamByName(*tdata.Name)
+ if err != nil {
+ return err
+ }
+
+ var roles string
+ if tdata.Roles == nil {
+ roles = model.ROLE_TEAM_USER.Id
+ } else {
+ roles = *tdata.Roles
+ }
+
+ if _, err := GetTeamMember(team.Id, user.Id); err != nil {
+ if _, err := joinUserToTeam(team, user); err != nil {
+ return err
+ }
+ }
+
+ if member, err := GetTeamMember(team.Id, user.Id); err != nil {
+ return err
+ } else {
+ if member.Roles != roles {
+ if _, err := UpdateTeamMemberRoles(team.Id, user.Id, roles); err != nil {
+ return err
+ }
+ }
+ }
+
+ if err := ImportUserChannels(user, team, tdata.Channels); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func ImportUserChannels(user *model.User, team *model.Team, data *[]UserChannelImportData) *model.AppError {
+ if data == nil {
+ return nil
+ }
+
+ // Loop through all channels.
+ for _, cdata := range *data {
+ channel, err := GetChannelByName(*cdata.Name, team.Id)
+ if err != nil {
+ return err
+ }
+
+ var roles string
+ if cdata.Roles == nil {
+ roles = model.ROLE_CHANNEL_USER.Id
+ } else {
+ roles = *cdata.Roles
+ }
+
+ var member *model.ChannelMember
+ member, err = GetChannelMember(channel.Id, user.Id)
+ if err != nil {
+ member, err = addUserToChannel(user, channel)
+ if err != nil {
+ return err
+ }
+ }
+
+ if member.Roles != roles {
+ if _, err := UpdateChannelMemberRoles(channel.Id, user.Id, roles); err != nil {
+ return err
+ }
+ }
+ }
+
return nil
}
@@ -421,6 +519,52 @@ func validateUserImportData(data *UserImportData) *model.AppError {
return model.NewAppError("BulkImport", "app.import.validate_user_import_data.roles_invalid.error", nil, "", http.StatusBadRequest)
}
+ if data.Teams != nil {
+ return validateUserTeamsImportData(data.Teams)
+ } else {
+ return nil
+ }
+}
+
+func validateUserTeamsImportData(data *[]UserTeamImportData) *model.AppError {
+ if data == nil {
+ return nil
+ }
+
+ for _, tdata := range *data {
+ if tdata.Name == nil {
+ return model.NewAppError("BulkImport", "app.import.validate_user_teams_import_data.team_name_missing.error", nil, "", http.StatusBadRequest)
+ }
+
+ if tdata.Roles != nil && !model.IsValidUserRoles(*tdata.Roles) {
+ return model.NewAppError("BulkImport", "app.import.validate_user_teams_import_data.invalid_roles.error", nil, "", http.StatusBadRequest)
+ }
+
+ if tdata.Channels != nil {
+ if err := validateUserChannelsImportData(tdata.Channels); err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+func validateUserChannelsImportData(data *[]UserChannelImportData) *model.AppError {
+ if data == nil {
+ return nil
+ }
+
+ for _, cdata := range *data {
+ if cdata.Name == nil {
+ return model.NewAppError("BulkImport", "app.import.validate_user_channels_import_data.channel_name_missing.error", nil, "", http.StatusBadRequest)
+ }
+
+ if cdata.Roles != nil && !model.IsValidUserRoles(*cdata.Roles) {
+ return model.NewAppError("BulkImport", "app.import.validate_user_channels_import_data.invalid_roles.error", nil, "", http.StatusBadRequest)
+ }
+ }
+
return nil
}
diff --git a/app/import_test.go b/app/import_test.go
index f3add56b2..d4ffad69f 100644
--- a/app/import_test.go
+++ b/app/import_test.go
@@ -349,6 +349,82 @@ func TestImportValidateUserImportData(t *testing.T) {
data.Roles = ptrStr("system_user")
}
+func TestImportValidateUserTeamsImportData(t *testing.T) {
+
+ // Invalid Name.
+ data := []UserTeamImportData{
+ {
+ Roles: ptrStr("team_admin team_user"),
+ },
+ }
+ if err := validateUserTeamsImportData(&data); err == nil {
+ t.Fatal("Should have failed due to invalid name.")
+ }
+ data[0].Name = ptrStr("teamname")
+
+ // Invalid Roles
+ data[0].Roles = ptrStr("wtf")
+ if err := validateUserTeamsImportData(&data); err == nil {
+ t.Fatal("Should have failed due to invalid roles.")
+ }
+
+ // Valid (nil roles)
+ data[0].Roles = nil
+ if err := validateUserTeamsImportData(&data); err != nil {
+ t.Fatal("Should have succeeded with empty roles.")
+ }
+
+ // Valid (empty roles)
+ data[0].Roles = ptrStr("")
+ if err := validateUserTeamsImportData(&data); err != nil {
+ t.Fatal("Should have succeeded with empty roles.")
+ }
+
+ // Valid (with roles)
+ data[0].Roles = ptrStr("team_admin team_user")
+ if err := validateUserTeamsImportData(&data); err != nil {
+ t.Fatal("Should have succeeded with valid roles.")
+ }
+}
+
+func TestImportValidateUserChannelsImportData(t *testing.T) {
+
+ // Invalid Name.
+ data := []UserChannelImportData{
+ {
+ Roles: ptrStr("channel_admin channel_user"),
+ },
+ }
+ if err := validateUserChannelsImportData(&data); err == nil {
+ t.Fatal("Should have failed due to invalid name.")
+ }
+ data[0].Name = ptrStr("channelname")
+
+ // Invalid Roles
+ data[0].Roles = ptrStr("wtf")
+ if err := validateUserChannelsImportData(&data); err == nil {
+ t.Fatal("Should have failed due to invalid roles.")
+ }
+
+ // Valid (nil roles)
+ data[0].Roles = nil
+ if err := validateUserChannelsImportData(&data); err != nil {
+ t.Fatal("Should have succeeded with empty roles.")
+ }
+
+ // Valid (empty roles)
+ data[0].Roles = ptrStr("")
+ if err := validateUserChannelsImportData(&data); err != nil {
+ t.Fatal("Should have succeeded with empty roles.")
+ }
+
+ // Valid (with roles)
+ data[0].Roles = ptrStr("channel_admin channel_user")
+ if err := validateUserChannelsImportData(&data); err != nil {
+ t.Fatal("Should have succeeded with valid roles.")
+ }
+}
+
func TestImportImportTeam(t *testing.T) {
_ = Setup()
@@ -467,11 +543,9 @@ func TestImportImportChannel(t *testing.T) {
DisplayName: ptrStr("Display Name"),
Type: ptrStr("O"),
}, false)
- var team *model.Team
- if te, err := GetTeamByName(teamName); err != nil {
+ team, err := GetTeamByName(teamName);
+ if err != nil {
t.Fatalf("Failed to get team from database.")
- } else {
- team = te
}
// Check how many channels are in the database.
@@ -792,6 +866,314 @@ func TestImportImportUser(t *testing.T) {
t.Fatalf("Expected roles to be set: %v", user.Roles)
}
}
+
+ // Test team and channel memberships
+ teamName := model.NewId()
+ ImportTeam(&TeamImportData{
+ Name: &teamName,
+ DisplayName: ptrStr("Display Name"),
+ Type: ptrStr("O"),
+ }, false)
+ team, err := GetTeamByName(teamName);
+ if err != nil {
+ t.Fatalf("Failed to get team from database.")
+ }
+
+ channelName := model.NewId()
+ ImportChannel(&ChannelImportData{
+ Team: &teamName,
+ Name: &channelName,
+ DisplayName: ptrStr("Display Name"),
+ Type: ptrStr("O"),
+ }, false)
+ channel, err := GetChannelByName(channelName, team.Id);
+ if err != nil {
+ t.Fatalf("Failed to get channel from database.")
+ }
+
+ username = model.NewId()
+ data = UserImportData{
+ Username: &username,
+ Email: ptrStr(model.NewId() + "@example.com"),
+ Nickname: ptrStr(model.NewId()),
+ FirstName: ptrStr(model.NewId()),
+ LastName: ptrStr(model.NewId()),
+ Position: ptrStr(model.NewId()),
+ }
+
+ teamMembers, err := GetTeamMembers(team.Id, 0, 1000)
+ if err != nil {
+ t.Fatalf("Failed to get team member count")
+ }
+ teamMemberCount := len(teamMembers)
+
+ channelMemberCount, err := GetChannelMemberCount(channel.Id)
+ if err != nil {
+ t.Fatalf("Failed to get channel member count")
+ }
+
+ // Test with an invalid team & channel membership in dry-run mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Roles: ptrStr("invalid"),
+ Channels: &[]UserChannelImportData{
+ {
+ Roles: ptrStr("invalid"),
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, true); err == nil {
+ t.Fatalf("Should have failed.")
+ }
+
+ // Test with an unknown team name & invalid channel membership in dry-run mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Name: ptrStr(model.NewId()),
+ Channels: &[]UserChannelImportData{
+ {
+ Roles: ptrStr("invalid"),
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, true); err == nil {
+ t.Fatalf("Should have failed.")
+ }
+
+ // Test with a valid team & invalid channel membership in dry-run mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Name: &teamName,
+ Channels: &[]UserChannelImportData{
+ {
+ Roles: ptrStr("invalid"),
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, true); err == nil {
+ t.Fatalf("Should have failed.")
+ }
+
+ // Test with a valid team & unknown channel name in dry-run mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Name: &teamName,
+ Channels: &[]UserChannelImportData{
+ {
+ Name: ptrStr(model.NewId()),
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, true); err != nil {
+ t.Fatalf("Should have succeeded.")
+ }
+
+ // Test with a valid team & valid channel name in dry-run mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Name: &teamName,
+ Channels: &[]UserChannelImportData{
+ {
+ Name: &channelName,
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, true); err != nil {
+ t.Fatalf("Should have succeeded.")
+ }
+
+ // Check no new member objects were created because dry run mode.
+ if tmc, err := GetTeamMembers(team.Id, 0, 1000); err != nil {
+ t.Fatalf("Failed to get Team Member Count")
+ } else if len(tmc) != teamMemberCount {
+ t.Fatalf("Number of team members not as expected")
+ }
+
+ if cmc, err := GetChannelMemberCount(channel.Id); err != nil {
+ t.Fatalf("Failed to get Channel Member Count")
+ } else if cmc != channelMemberCount {
+ t.Fatalf("Number of channel members not as expected")
+ }
+
+ // Test with an invalid team & channel membership in apply mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Roles: ptrStr("invalid"),
+ Channels: &[]UserChannelImportData{
+ {
+ Roles: ptrStr("invalid"),
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, false); err == nil {
+ t.Fatalf("Should have failed.")
+ }
+
+ // Test with an unknown team name & invalid channel membership in apply mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Name: ptrStr(model.NewId()),
+ Channels: &[]UserChannelImportData{
+ {
+ Roles: ptrStr("invalid"),
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, false); err == nil {
+ t.Fatalf("Should have failed.")
+ }
+
+ // Test with a valid team & invalid channel membership in apply mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Name: &teamName,
+ Channels: &[]UserChannelImportData{
+ {
+ Roles: ptrStr("invalid"),
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, false); err == nil {
+ t.Fatalf("Should have failed.")
+ }
+
+ // Check no new member objects were created because all tests should have failed so far.
+ if tmc, err := GetTeamMembers(team.Id, 0, 1000); err != nil {
+ t.Fatalf("Failed to get Team Member Count")
+ } else if len(tmc) != teamMemberCount {
+ t.Fatalf("Number of team members not as expected")
+ }
+
+ if cmc, err := GetChannelMemberCount(channel.Id); err != nil {
+ t.Fatalf("Failed to get Channel Member Count")
+ } else if cmc != channelMemberCount {
+ t.Fatalf("Number of channel members not as expected")
+ }
+
+ // Test with a valid team & unknown channel name in apply mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Name: &teamName,
+ Channels: &[]UserChannelImportData{
+ {
+ Name: ptrStr(model.NewId()),
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, false); err == nil {
+ t.Fatalf("Should have failed.")
+ }
+
+ // Check only new team member object created because dry run mode.
+ if tmc, err := GetTeamMembers(team.Id, 0, 1000); err != nil {
+ t.Fatalf("Failed to get Team Member Count")
+ } else if len(tmc) != teamMemberCount + 1 {
+ t.Fatalf("Number of team members not as expected")
+ }
+
+ if cmc, err := GetChannelMemberCount(channel.Id); err != nil {
+ t.Fatalf("Failed to get Channel Member Count")
+ } else if cmc != channelMemberCount {
+ t.Fatalf("Number of channel members not as expected")
+ }
+
+ // Check team member properties.
+ user, err := GetUserByUsername(username);
+ if err != nil {
+ t.Fatalf("Failed to get user from database.")
+ }
+ if teamMember, err := GetTeamMember(team.Id, user.Id); err != nil {
+ t.Fatalf("Failed to get team member from database.")
+ } else if teamMember.Roles != "team_user" {
+ t.Fatalf("Team member properties not as expected")
+ }
+
+ // Test with a valid team & valid channel name in apply mode.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Name: &teamName,
+ Channels: &[]UserChannelImportData{
+ {
+ Name: &channelName,
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, false); err != nil {
+ t.Fatalf("Should have succeeded.")
+ }
+
+ // Check only new channel member object created because dry run mode.
+ if tmc, err := GetTeamMembers(team.Id, 0, 1000); err != nil {
+ t.Fatalf("Failed to get Team Member Count")
+ } else if len(tmc) != teamMemberCount + 1 {
+ t.Fatalf("Number of team members not as expected")
+ }
+
+ if cmc, err := GetChannelMemberCount(channel.Id); err != nil {
+ t.Fatalf("Failed to get Channel Member Count")
+ } else if cmc != channelMemberCount + 1 {
+ t.Fatalf("Number of channel members not as expected")
+ }
+
+ // Check channel member properties.
+ if channelMember, err := GetChannelMember(channel.Id, user.Id); err != nil {
+ t.Fatalf("Failed to get channel member from database.")
+ } else if channelMember.Roles != "channel_user" {
+ t.Fatalf("Channel member properties not as expected")
+ }
+
+ // Test with the properties of the team and channel membership changed.
+ data.Teams = &[]UserTeamImportData{
+ {
+ Name: &teamName,
+ Roles: ptrStr("team_user team_admin"),
+ Channels: &[]UserChannelImportData{
+ {
+ Name: &channelName,
+ Roles: ptrStr("channel_user channel_admin"),
+ },
+ },
+ },
+ }
+ if err := ImportUser(&data, false); err != nil {
+ t.Fatalf("Should have succeeded.")
+ }
+
+ // Check both member properties.
+ if teamMember, err := GetTeamMember(team.Id, user.Id); err != nil {
+ t.Fatalf("Failed to get team member from database.")
+ } else if teamMember.Roles != "team_user team_admin" {
+ t.Fatalf("Team member properties not as expected: %v", teamMember.Roles)
+ }
+
+ if channelMember, err := GetChannelMember(channel.Id, user.Id); err != nil {
+ t.Fatalf("Failed to get channel member from database.")
+ } else if channelMember.Roles != "channel_user channel_admin" {
+ t.Fatalf("Channel member properties not as expected")
+ }
+
+ // No more new member objects.
+ if tmc, err := GetTeamMembers(team.Id, 0, 1000); err != nil {
+ t.Fatalf("Failed to get Team Member Count")
+ } else if len(tmc) != teamMemberCount + 1 {
+ t.Fatalf("Number of team members not as expected")
+ }
+
+ if cmc, err := GetChannelMemberCount(channel.Id); err != nil {
+ t.Fatalf("Failed to get Channel Member Count")
+ } else if cmc != channelMemberCount + 1 {
+ t.Fatalf("Number of channel members not as expected")
+ }
}
func TestImportImportLine(t *testing.T) {
@@ -834,7 +1216,8 @@ func TestImportBulkImport(t *testing.T) {
// Run bulk import with a valid 1 of everything.
data1 := `{"type": "team", "team": {"type": "O", "display_name": "lskmw2d7a5ao7ppwqh5ljchvr4", "name": "` + teamName + `"}}
{"type": "channel", "channel": {"type": "O", "display_name": "xr6m6udffngark2uekvr3hoeny", "team": "` + teamName + `", "name": "` + channelName + `"}}
-{"type": "user", "user": {"username": "kufjgnkxkrhhfgbrip6qxkfsaa", "email": "kufjgnkxkrhhfgbrip6qxkfsaa@example.com"}}`
+{"type": "user", "user": {"username": "kufjgnkxkrhhfgbrip6qxkfsaa", "email": "kufjgnkxkrhhfgbrip6qxkfsaa@example.com"}}
+{"type": "user", "user": {"username": "bwshaim6qnc2ne7oqkd5b2s2rq", "email": "bwshaim6qnc2ne7oqkd5b2s2rq@example.com", "teams": [{"name": "` + teamName + `", "channels": [{"name": "` + channelName + `"}]}]}}`
if err, line := BulkImport(strings.NewReader(data1), false); err != nil || line != 0 {
t.Fatalf("BulkImport should have succeeded: %v, %v", err.Error(), line)
diff --git a/app/team.go b/app/team.go
index 3c7145818..6225f3ee0 100644
--- a/app/team.go
+++ b/app/team.go
@@ -231,7 +231,7 @@ func AddUserToTeamByInviteId(inviteId string, userId string) (*model.Team, *mode
return team, nil
}
-func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError {
+func joinUserToTeam(team *model.Team, user *model.User) (bool, *model.AppError) {
tm := &model.TeamMember{
TeamId: team.Id,
@@ -239,11 +239,8 @@ func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError {
Roles: model.ROLE_TEAM_USER.Id,
}
- channelRole := model.ROLE_CHANNEL_USER.Id
-
if team.Email == user.Email {
tm.Roles = model.ROLE_TEAM_USER.Id + " " + model.ROLE_TEAM_ADMIN.Id
- channelRole = model.ROLE_CHANNEL_USER.Id + " " + model.ROLE_CHANNEL_ADMIN.Id
}
if etmr := <-Srv.Store.Team().GetMember(team.Id, user.Id); etmr.Err == nil {
@@ -252,21 +249,38 @@ func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError {
// Do nothing if already added
if rtm.DeleteAt == 0 {
- return nil
+ return true, nil
}
if tmr := <-Srv.Store.Team().UpdateMember(tm); tmr.Err != nil {
- return tmr.Err
+ return false, tmr.Err
}
} else {
// Membership appears to be missing. Lets try to add.
if tmr := <-Srv.Store.Team().SaveMember(tm); tmr.Err != nil {
- return tmr.Err
+ return false, tmr.Err
}
}
if uua := <-Srv.Store.User().UpdateUpdateAt(user.Id); uua.Err != nil {
- return uua.Err
+ return false, uua.Err
+ }
+
+ return false, nil
+}
+
+func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError {
+
+ if alreadyAdded, err := joinUserToTeam(team, user); err != nil {
+ return err
+ } else if alreadyAdded {
+ return nil
+ }
+
+ channelRole := model.ROLE_CHANNEL_USER.Id
+
+ if team.Email == user.Email {
+ channelRole = model.ROLE_CHANNEL_USER.Id + " " + model.ROLE_CHANNEL_ADMIN.Id
}
// Soft error if there is an issue joining the default channels
diff --git a/i18n/en.json b/i18n/en.json
index cd109f860..c58e113d2 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -2952,6 +2952,22 @@
"translation": "User roles are not valid."
},
{
+ "id": "app.import.validate_user_teams_import_data.team_name_missing.error",
+ "translation": "Team name missing from User's Team Membership."
+ },
+ {
+ "id": "app.import.validate_user_teams_import_data.invalid_roles.error",
+ "translation": "Invalid roles for User's Team Membership."
+ },
+ {
+ "id": "app.import.validate_user_channels_import_data.channel_name_missing.error",
+ "translation": "Channel name missing from User's Channel Membership."
+ },
+ {
+ "id": "app.import.validate_user_channels_import_data.invalid_roles.error",
+ "translation": "Invalid roles for User's Channel Membership."
+ },
+ {
"id": "authentication.permissions.create_team_roles.description",
"translation": "Ability to create new teams"
},