MM-20977 - Inviting multiple users with valid/allowed and inva… (#13372)

Этот коммит содержится в:
Eli Yukelzon
2020-01-14 15:29:50 +02:00
коммит произвёл GitHub
родитель 51a61f6bc1
Коммит e77ef9733c
10 изменённых файлов: 204 добавлений и 8 удалений

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

@@ -522,6 +522,8 @@ func addUserToTeamFromInvite(c *Context, w http.ResponseWriter, r *http.Request)
}
func addTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
graceful := r.URL.Query().Get("graceful") != ""
c.RequireTeamId()
if c.Err != nil {
return
@@ -587,7 +589,7 @@ func addTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
members, err = c.App.AddTeamMembers(c.Params.TeamId, userIds, c.App.Session.UserId)
membersWithErrors, err := c.App.AddTeamMembers(c.Params.TeamId, userIds, c.App.Session.UserId, graceful)
if err != nil {
c.Err = err
@@ -595,7 +597,14 @@ func addTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
}
w.WriteHeader(http.StatusCreated)
w.Write([]byte(model.TeamMembersToJson(members)))
if graceful {
// in 'graceful' mode we allow a different return value, notifying the client which users were not added
w.Write([]byte(model.TeamMembersWithErrorToJson(membersWithErrors)))
} else {
w.Write([]byte(model.TeamMembersToJson(model.TeamMembersWithErrorToTeamMembers(membersWithErrors))))
}
}
func removeTeamMember(c *Context, w http.ResponseWriter, r *http.Request) {

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

@@ -1651,6 +1651,66 @@ func TestAddTeamMemberMyself(t *testing.T) {
}
func TestAddTeamMembersDomainConstrained(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
client := th.SystemAdminClient
team := th.BasicTeam
team.AllowedDomains = "domain1.com, domain2.com"
_, response := client.UpdateTeam(team)
require.Nil(t, response.Error)
// create two users on allowed domains
user1, response := client.CreateUser(&model.User{
Email: "user@domain1.com",
Password: "Pa$$word11",
Username: GenerateTestUsername(),
})
require.Nil(t, response.Error)
user2, response := client.CreateUser(&model.User{
Email: "user@domain2.com",
Password: "Pa$$word11",
Username: GenerateTestUsername(),
})
require.Nil(t, response.Error)
userList := []string{
user1.Id,
user2.Id,
}
// validate that they can be added
tm, response := client.AddTeamMembers(team.Id, userList)
require.Nil(t, response.Error)
require.Len(t, tm, 2)
// cleanup
_, response = client.RemoveTeamMember(team.Id, user1.Id)
require.Nil(t, response.Error)
_, response = client.RemoveTeamMember(team.Id, user2.Id)
require.Nil(t, response.Error)
// disable one of the allowed domains
team.AllowedDomains = "domain1.com"
_, response = client.UpdateTeam(team)
require.Nil(t, response.Error)
// validate that they cannot be added
_, response = client.AddTeamMembers(team.Id, userList)
require.NotNil(t, response.Error)
// validate that one user can be added gracefully
members, response := client.AddTeamMembersGracefully(team.Id, userList)
require.Nil(t, response.Error)
require.Len(t, members, 2)
require.NotNil(t, members[0].Member)
require.NotNil(t, members[1].Error)
require.Equal(t, members[0].UserId, user1.Id)
require.Equal(t, members[1].UserId, user2.Id)
require.Nil(t, members[0].Error)
require.Nil(t, members[1].Member)
}
func TestAddTeamMembers(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()

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

@@ -174,7 +174,15 @@ func (api *PluginAPI) CreateTeamMember(teamId, userId string) (*model.TeamMember
}
func (api *PluginAPI) CreateTeamMembers(teamId string, userIds []string, requestorId string) ([]*model.TeamMember, *model.AppError) {
return api.app.AddTeamMembers(teamId, userIds, requestorId)
members, err := api.app.AddTeamMembers(teamId, userIds, requestorId, false)
if err != nil {
return nil, err
}
return model.TeamMembersWithErrorToTeamMembers(members), nil
}
func (api *PluginAPI) CreateTeamMembersGracefully(teamId string, userIds []string, requestorId string) ([]*model.TeamMemberWithError, *model.AppError) {
return api.app.AddTeamMembers(teamId, userIds, requestorId, true)
}
func (api *PluginAPI) DeleteTeamMember(teamId, userId, requestorId string) *model.AppError {

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

@@ -777,11 +777,18 @@ func (a *App) AddTeamMember(teamId, userId string) (*model.TeamMember, *model.Ap
return teamMember, nil
}
func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId string) ([]*model.TeamMember, *model.AppError) {
var members []*model.TeamMember
func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId string, graceful bool) ([]*model.TeamMemberWithError, *model.AppError) {
var membersWithErrors []*model.TeamMemberWithError
for _, userId := range userIds {
if _, err := a.AddUserToTeam(teamId, userId, userRequestorId); err != nil {
if graceful {
membersWithErrors = append(membersWithErrors, &model.TeamMemberWithError{
UserId: userId,
Error: err,
})
continue
}
return nil, err
}
@@ -789,7 +796,10 @@ func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId st
if err != nil {
return nil, err
}
members = append(members, teamMember)
membersWithErrors = append(membersWithErrors, &model.TeamMemberWithError{
UserId: userId,
Member: teamMember,
})
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", userId, nil)
message.Add("team_id", teamId)
@@ -797,7 +807,7 @@ func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId st
a.Publish(message)
}
return members, nil
return membersWithErrors, nil
}
func (a *App) AddTeamMemberByToken(userId, tokenId string) (*model.TeamMember, *model.AppError) {

2
go.mod
Просмотреть файл

@@ -39,7 +39,7 @@ require (
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428
github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43
github.com/jmoiron/sqlx v1.2.0
github.com/jonboulle/clockwork v0.1.0
github.com/jonboulle/clockwork v0.1.0 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/lib/pq v1.2.0
github.com/magiconair/properties v1.8.1 // indirect

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

@@ -1861,6 +1861,22 @@ func (c *Client4) AddTeamMembers(teamId string, userIds []string) ([]*TeamMember
return TeamMembersFromJson(r.Body), BuildResponse(r)
}
// AddTeamMembers adds a number of users to a team and returns the team members.
func (c *Client4) AddTeamMembersGracefully(teamId string, userIds []string) ([]*TeamMemberWithError, *Response) {
var members []*TeamMember
for _, userId := range userIds {
member := &TeamMember{TeamId: teamId, UserId: userId}
members = append(members, member)
}
r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch?graceful=true", TeamMembersToJson(members))
if err != nil {
return nil, BuildErrorResponse(r, err)
}
defer closeBody(r)
return TeamMembersWithErrorFromJson(r.Body), BuildResponse(r)
}
// RemoveTeamMember will remove a user from a team.
func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) {
r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId))

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

@@ -32,6 +32,12 @@ type TeamMemberForExport struct {
TeamName string
}
type TeamMemberWithError struct {
UserId string `json:"user_id"`
Member *TeamMember `json:"member"`
Error *AppError `json:"error"`
}
func (o *TeamMember) ToJson() string {
b, _ := json.Marshal(o)
return string(b)
@@ -54,6 +60,30 @@ func TeamUnreadFromJson(data io.Reader) *TeamUnread {
return o
}
func TeamMembersWithErrorToTeamMembers(o []*TeamMemberWithError) []*TeamMember {
var ret []*TeamMember
for _, o := range o {
if o.Error == nil {
ret = append(ret, o.Member)
}
}
return ret
}
func TeamMembersWithErrorToJson(o []*TeamMemberWithError) string {
if b, err := json.Marshal(o); err != nil {
return "[]"
} else {
return string(b)
}
}
func TeamMembersWithErrorFromJson(data io.Reader) []*TeamMemberWithError {
var o []*TeamMemberWithError
json.NewDecoder(data).Decode(&o)
return o
}
func TeamMembersToJson(o []*TeamMember) string {
if b, err := json.Marshal(o); err != nil {
return "[]"

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

@@ -288,6 +288,13 @@ type API interface {
// Minimum server version: 5.2
CreateTeamMembers(teamId string, userIds []string, requestorId string) ([]*model.TeamMember, *model.AppError)
// CreateTeamMembersGracefully creates a team membership for all provided user ids and reports the users that were not added.
//
// @tag Team
// @tag User
// Minimum server version: 5.20
CreateTeamMembersGracefully(teamId string, userIds []string, requestorId string) ([]*model.TeamMemberWithError, *model.AppError)
// DeleteTeamMember deletes a team membership.
//
// @tag Team

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

@@ -1682,6 +1682,37 @@ func (s *apiRPCServer) CreateTeamMembers(args *Z_CreateTeamMembersArgs, returns
return nil
}
type Z_CreateTeamMembersGracefullyArgs struct {
A string
B []string
C string
}
type Z_CreateTeamMembersGracefullyReturns struct {
A []*model.TeamMemberWithError
B *model.AppError
}
func (g *apiRPCClient) CreateTeamMembersGracefully(teamId string, userIds []string, requestorId string) ([]*model.TeamMemberWithError, *model.AppError) {
_args := &Z_CreateTeamMembersGracefullyArgs{teamId, userIds, requestorId}
_returns := &Z_CreateTeamMembersGracefullyReturns{}
if err := g.client.Call("Plugin.CreateTeamMembersGracefully", _args, _returns); err != nil {
log.Printf("RPC call to CreateTeamMembersGracefully API failed: %s", err.Error())
}
return _returns.A, _returns.B
}
func (s *apiRPCServer) CreateTeamMembersGracefully(args *Z_CreateTeamMembersGracefullyArgs, returns *Z_CreateTeamMembersGracefullyReturns) error {
if hook, ok := s.impl.(interface {
CreateTeamMembersGracefully(teamId string, userIds []string, requestorId string) ([]*model.TeamMemberWithError, *model.AppError)
}); ok {
returns.A, returns.B = hook.CreateTeamMembersGracefully(args.A, args.B, args.C)
} else {
return encodableError(fmt.Errorf("API CreateTeamMembersGracefully called but not implemented."))
}
return nil
}
type Z_DeleteTeamMemberArgs struct {
A string
B string

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

@@ -268,6 +268,31 @@ func (_m *API) CreateTeamMembers(teamId string, userIds []string, requestorId st
return r0, r1
}
// CreateTeamMembersGracefully provides a mock function with given fields: teamId, userIds, requestorId
func (_m *API) CreateTeamMembersGracefully(teamId string, userIds []string, requestorId string) ([]*model.TeamMemberWithError, *model.AppError) {
ret := _m.Called(teamId, userIds, requestorId)
var r0 []*model.TeamMemberWithError
if rf, ok := ret.Get(0).(func(string, []string, string) []*model.TeamMemberWithError); ok {
r0 = rf(teamId, userIds, requestorId)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.TeamMemberWithError)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, []string, string) *model.AppError); ok {
r1 = rf(teamId, userIds, requestorId)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// CreateUser provides a mock function with given fields: user
func (_m *API) CreateUser(user *model.User) (*model.User, *model.AppError) {
ret := _m.Called(user)