MM-20977 - Inviting multiple users with valid/allowed and inva… (#13372)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
51a61f6bc1
Коммит
e77ef9733c
13
api4/team.go
13
api4/team.go
@@ -522,6 +522,8 @@ func addUserToTeamFromInvite(c *Context, w http.ResponseWriter, r *http.Request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addTeamMembers(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()
|
c.RequireTeamId()
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
return
|
return
|
||||||
@@ -587,7 +589,7 @@ func addTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
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 {
|
if err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
@@ -595,7 +597,14 @@ func addTeamMembers(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusCreated)
|
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) {
|
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) {
|
func TestAddTeamMembers(t *testing.T) {
|
||||||
th := Setup().InitBasic()
|
th := Setup().InitBasic()
|
||||||
defer th.TearDown()
|
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) {
|
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 {
|
func (api *PluginAPI) DeleteTeamMember(teamId, userId, requestorId string) *model.AppError {
|
||||||
|
|||||||
18
app/team.go
18
app/team.go
@@ -777,11 +777,18 @@ func (a *App) AddTeamMember(teamId, userId string) (*model.TeamMember, *model.Ap
|
|||||||
return teamMember, nil
|
return teamMember, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId string) ([]*model.TeamMember, *model.AppError) {
|
func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId string, graceful bool) ([]*model.TeamMemberWithError, *model.AppError) {
|
||||||
var members []*model.TeamMember
|
var membersWithErrors []*model.TeamMemberWithError
|
||||||
|
|
||||||
for _, userId := range userIds {
|
for _, userId := range userIds {
|
||||||
if _, err := a.AddUserToTeam(teamId, userId, userRequestorId); err != nil {
|
if _, err := a.AddUserToTeam(teamId, userId, userRequestorId); err != nil {
|
||||||
|
if graceful {
|
||||||
|
membersWithErrors = append(membersWithErrors, &model.TeamMemberWithError{
|
||||||
|
UserId: userId,
|
||||||
|
Error: err,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -789,7 +796,10 @@ func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId st
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", userId, nil)
|
||||||
message.Add("team_id", teamId)
|
message.Add("team_id", teamId)
|
||||||
@@ -797,7 +807,7 @@ func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId st
|
|||||||
a.Publish(message)
|
a.Publish(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
return members, nil
|
return membersWithErrors, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) AddTeamMemberByToken(userId, tokenId string) (*model.TeamMember, *model.AppError) {
|
func (a *App) AddTeamMemberByToken(userId, tokenId string) (*model.TeamMember, *model.AppError) {
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -39,7 +39,7 @@ require (
|
|||||||
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428
|
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428
|
||||||
github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43
|
github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
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/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||||
github.com/lib/pq v1.2.0
|
github.com/lib/pq v1.2.0
|
||||||
github.com/magiconair/properties v1.8.1 // indirect
|
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)
|
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.
|
// RemoveTeamMember will remove a user from a team.
|
||||||
func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) {
|
func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) {
|
||||||
r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId))
|
r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId))
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ type TeamMemberForExport struct {
|
|||||||
TeamName string
|
TeamName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TeamMemberWithError struct {
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
Member *TeamMember `json:"member"`
|
||||||
|
Error *AppError `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
func (o *TeamMember) ToJson() string {
|
func (o *TeamMember) ToJson() string {
|
||||||
b, _ := json.Marshal(o)
|
b, _ := json.Marshal(o)
|
||||||
return string(b)
|
return string(b)
|
||||||
@@ -54,6 +60,30 @@ func TeamUnreadFromJson(data io.Reader) *TeamUnread {
|
|||||||
return o
|
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 {
|
func TeamMembersToJson(o []*TeamMember) string {
|
||||||
if b, err := json.Marshal(o); err != nil {
|
if b, err := json.Marshal(o); err != nil {
|
||||||
return "[]"
|
return "[]"
|
||||||
|
|||||||
@@ -288,6 +288,13 @@ type API interface {
|
|||||||
// Minimum server version: 5.2
|
// Minimum server version: 5.2
|
||||||
CreateTeamMembers(teamId string, userIds []string, requestorId string) ([]*model.TeamMember, *model.AppError)
|
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.
|
// DeleteTeamMember deletes a team membership.
|
||||||
//
|
//
|
||||||
// @tag Team
|
// @tag Team
|
||||||
|
|||||||
@@ -1682,6 +1682,37 @@ func (s *apiRPCServer) CreateTeamMembers(args *Z_CreateTeamMembersArgs, returns
|
|||||||
return nil
|
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 {
|
type Z_DeleteTeamMemberArgs struct {
|
||||||
A string
|
A string
|
||||||
B string
|
B string
|
||||||
|
|||||||
@@ -268,6 +268,31 @@ func (_m *API) CreateTeamMembers(teamId string, userIds []string, requestorId st
|
|||||||
return r0, r1
|
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
|
// CreateUser provides a mock function with given fields: user
|
||||||
func (_m *API) CreateUser(user *model.User) (*model.User, *model.AppError) {
|
func (_m *API) CreateUser(user *model.User) (*model.User, *model.AppError) {
|
||||||
ret := _m.Called(user)
|
ret := _m.Called(user)
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user