MM-20977 - Inviting multiple users with valid/allowed and inva… (#13779)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
682a1d5d15
Коммит
4b39d8487b
46
api4/team.go
46
api4/team.go
@@ -945,6 +945,8 @@ func importTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func inviteUsersToTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
graceful := r.URL.Query().Get("graceful") != ""
|
||||
|
||||
c.RequireTeamId()
|
||||
if c.Err != nil {
|
||||
return
|
||||
@@ -967,16 +969,26 @@ func inviteUsersToTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
err := c.App.InviteNewUsersToTeam(emailList, c.Params.TeamId, c.App.Session.UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
if graceful {
|
||||
invitesWithError, err := c.App.InviteNewUsersToTeamGracefully(emailList, c.Params.TeamId, c.App.Session.UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
// in graceful mode we return both the succesful ones and the failed ones
|
||||
w.Write([]byte(model.EmailInviteWithErrorToJson(invitesWithError)))
|
||||
} else {
|
||||
err := c.App.InviteNewUsersToTeam(emailList, c.Params.TeamId, c.App.Session.UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
func inviteGuestsToChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
graceful := r.URL.Query().Get("graceful") != ""
|
||||
if c.App.License() == nil {
|
||||
c.Err = model.NewAppError("Api4.InviteGuestsToChannels", "api.team.invate_guests_to_channels.license.error", nil, "", http.StatusNotImplemented)
|
||||
return
|
||||
@@ -1002,14 +1014,22 @@ func inviteGuestsToChannels(c *Context, w http.ResponseWriter, r *http.Request)
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
|
||||
err := c.App.InviteGuestsToChannels(c.Params.TeamId, guestsInvite, c.App.Session.UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
if graceful {
|
||||
invitesWithError, err := c.App.InviteGuestsToChannelsGracefully(c.Params.TeamId, guestsInvite, c.App.Session.UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
// in graceful mode we return both the succesful ones and the failed ones
|
||||
w.Write([]byte(model.EmailInviteWithErrorToJson(invitesWithError)))
|
||||
} else {
|
||||
err := c.App.InviteGuestsToChannels(c.Params.TeamId, guestsInvite, c.App.Session.UserId)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
}
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
ReturnStatusOK(w)
|
||||
}
|
||||
|
||||
func getInviteInfo(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -2343,6 +2343,13 @@ func TestInviteUsersToTeam(t *testing.T) {
|
||||
|
||||
require.Equalf(t, err.Where, "InviteNewUsersToTeam", "%v, Got wrong error message!", err)
|
||||
require.Equalf(t, err.Id, "api.team.invite_members.invalid_email.app_error", "%v, Got wrong error message!", err)
|
||||
|
||||
res, err := th.App.InviteNewUsersToTeamGracefully(emailList, th.BasicTeam.Id, th.BasicUser.Id)
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Len(t, res, 2)
|
||||
require.NotNil(t, res[0].Error)
|
||||
require.NotNil(t, res[1].Error)
|
||||
})
|
||||
|
||||
t.Run("override restricted domains", func(t *testing.T) {
|
||||
@@ -2363,6 +2370,12 @@ func TestInviteUsersToTeam(t *testing.T) {
|
||||
|
||||
err = th.App.InviteNewUsersToTeam([]string{"test@invalid.com"}, th.BasicTeam.Id, th.BasicUser.Id)
|
||||
require.NotNilf(t, err, "%v, Should not invite user", err)
|
||||
|
||||
res, err := th.App.InviteNewUsersToTeamGracefully([]string{"test@invalid.com", "test@common.com"}, th.BasicTeam.Id, th.BasicUser.Id)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, res, 2)
|
||||
require.NotNil(t, res[0].Error)
|
||||
require.Nil(t, res[1].Error)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2457,6 +2470,12 @@ func TestInviteGuestsToTeam(t *testing.T) {
|
||||
err := th.App.InviteGuestsToChannels(th.BasicTeam.Id, &model.GuestsInvite{Emails: []string{"guest1@invalid.com"}, Channels: []string{th.BasicChannel.Id}, Message: "test message"}, th.BasicUser.Id)
|
||||
require.NotNil(t, err, "guest user invites should be affected by the guest domain restrictions")
|
||||
|
||||
res, err := th.App.InviteGuestsToChannelsGracefully(th.BasicTeam.Id, &model.GuestsInvite{Emails: []string{"guest1@invalid.com", "guest1@guest.com"}, Channels: []string{th.BasicChannel.Id}, Message: "test message"}, th.BasicUser.Id)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, res, 2)
|
||||
require.NotNil(t, res[0].Error)
|
||||
require.Nil(t, res[1].Error)
|
||||
|
||||
err = th.App.InviteGuestsToChannels(th.BasicTeam.Id, &model.GuestsInvite{Emails: []string{"guest1@guest.com"}, Channels: []string{th.BasicChannel.Id}, Message: "test message"}, th.BasicUser.Id)
|
||||
require.Nil(t, err, "whitelisted guest user email should be allowed by the guest domain restrictions")
|
||||
})
|
||||
|
||||
198
app/team.go
198
app/team.go
@@ -1043,16 +1043,7 @@ func (a *App) postRemoveFromTeamMessage(user *model.User, channel *model.Channel
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string) *model.AppError {
|
||||
if !*a.Config().ServiceSettings.EnableEmailInvitations {
|
||||
return model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if len(emailList) == 0 {
|
||||
err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.no_one.app_error", nil, "", http.StatusBadRequest)
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *App) prepareInviteNewUsersToTeam(teamId, senderId string) (*model.User, *model.Team, *model.AppError) {
|
||||
tchan := make(chan store.StoreResult, 1)
|
||||
go func() {
|
||||
team, err := a.Srv.Store.Team().Get(teamId)
|
||||
@@ -1069,15 +1060,152 @@ func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string)
|
||||
|
||||
result := <-tchan
|
||||
if result.Err != nil {
|
||||
return result.Err
|
||||
return nil, nil, result.Err
|
||||
}
|
||||
team := result.Data.(*model.Team)
|
||||
|
||||
result = <-uchan
|
||||
if result.Err != nil {
|
||||
return result.Err
|
||||
return nil, nil, result.Err
|
||||
}
|
||||
user := result.Data.(*model.User)
|
||||
return user, team, nil
|
||||
}
|
||||
|
||||
func (a *App) InviteNewUsersToTeamGracefully(emailList []string, teamId, senderId string) ([]*model.EmailInviteWithError, *model.AppError) {
|
||||
if !*a.Config().ServiceSettings.EnableEmailInvitations {
|
||||
return nil, model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if len(emailList) == 0 {
|
||||
err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.no_one.app_error", nil, "", http.StatusBadRequest)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user, team, err := a.prepareInviteNewUsersToTeam(teamId, senderId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var inviteListWithErrors []*model.EmailInviteWithError
|
||||
var goodEmails []string
|
||||
for _, email := range emailList {
|
||||
invite := &model.EmailInviteWithError{
|
||||
Email: email,
|
||||
Error: nil,
|
||||
}
|
||||
if !a.isTeamEmailAddressAllowed(email, team.AllowedDomains) {
|
||||
invite.Error = model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": email}, "", http.StatusBadRequest)
|
||||
} else {
|
||||
goodEmails = append(goodEmails, email)
|
||||
}
|
||||
inviteListWithErrors = append(inviteListWithErrors, invite)
|
||||
}
|
||||
|
||||
if len(goodEmails) > 0 {
|
||||
nameFormat := *a.Config().TeamSettings.TeammateNameDisplay
|
||||
a.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, goodEmails, a.GetSiteURL())
|
||||
}
|
||||
|
||||
return inviteListWithErrors, nil
|
||||
}
|
||||
|
||||
func (a *App) prepareInviteGuestsToChannels(teamId string, guestsInvite *model.GuestsInvite, senderId string) (*model.User, *model.Team, []*model.Channel, *model.AppError) {
|
||||
if err := guestsInvite.IsValid(); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
tchan := make(chan store.StoreResult, 1)
|
||||
go func() {
|
||||
team, err := a.Srv.Store.Team().Get(teamId)
|
||||
tchan <- store.StoreResult{Data: team, Err: err}
|
||||
close(tchan)
|
||||
}()
|
||||
cchan := make(chan store.StoreResult, 1)
|
||||
go func() {
|
||||
channels, err := a.Srv.Store.Channel().GetChannelsByIds(guestsInvite.Channels)
|
||||
cchan <- store.StoreResult{Data: channels, Err: err}
|
||||
close(cchan)
|
||||
}()
|
||||
uchan := make(chan store.StoreResult, 1)
|
||||
go func() {
|
||||
user, err := a.Srv.Store.User().Get(senderId)
|
||||
uchan <- store.StoreResult{Data: user, Err: err}
|
||||
close(uchan)
|
||||
}()
|
||||
|
||||
result := <-cchan
|
||||
if result.Err != nil {
|
||||
return nil, nil, nil, result.Err
|
||||
}
|
||||
channels := result.Data.([]*model.Channel)
|
||||
|
||||
result = <-uchan
|
||||
if result.Err != nil {
|
||||
return nil, nil, nil, result.Err
|
||||
}
|
||||
user := result.Data.(*model.User)
|
||||
|
||||
result = <-tchan
|
||||
if result.Err != nil {
|
||||
return nil, nil, nil, result.Err
|
||||
}
|
||||
team := result.Data.(*model.Team)
|
||||
|
||||
for _, channel := range channels {
|
||||
if channel.TeamId != teamId {
|
||||
return nil, nil, nil, model.NewAppError("InviteGuestsToChannels", "api.team.invite_guests.channel_in_invalid_team.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
return user, team, channels, nil
|
||||
}
|
||||
|
||||
func (a *App) InviteGuestsToChannelsGracefully(teamId string, guestsInvite *model.GuestsInvite, senderId string) ([]*model.EmailInviteWithError, *model.AppError) {
|
||||
if !*a.Config().ServiceSettings.EnableEmailInvitations {
|
||||
return nil, model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
user, team, channels, err := a.prepareInviteGuestsToChannels(teamId, guestsInvite, senderId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var inviteListWithErrors []*model.EmailInviteWithError
|
||||
var goodEmails []string
|
||||
for _, email := range guestsInvite.Emails {
|
||||
invite := &model.EmailInviteWithError{
|
||||
Email: email,
|
||||
Error: nil,
|
||||
}
|
||||
if !CheckEmailDomain(email, *a.Config().GuestAccountsSettings.RestrictCreationToDomains) {
|
||||
invite.Error = model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": email}, "", http.StatusBadRequest)
|
||||
} else {
|
||||
goodEmails = append(goodEmails, email)
|
||||
}
|
||||
inviteListWithErrors = append(inviteListWithErrors, invite)
|
||||
}
|
||||
|
||||
if len(goodEmails) > 0 {
|
||||
nameFormat := *a.Config().TeamSettings.TeammateNameDisplay
|
||||
a.SendGuestInviteEmails(team, channels, user.GetDisplayName(nameFormat), user.Id, goodEmails, a.GetSiteURL(), guestsInvite.Message)
|
||||
}
|
||||
|
||||
return inviteListWithErrors, nil
|
||||
}
|
||||
|
||||
func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string) *model.AppError {
|
||||
if !*a.Config().ServiceSettings.EnableEmailInvitations {
|
||||
return model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if len(emailList) == 0 {
|
||||
err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.no_one.app_error", nil, "", http.StatusBadRequest)
|
||||
return err
|
||||
}
|
||||
|
||||
user, team, err := a.prepareInviteNewUsersToTeam(teamId, senderId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var invalidEmailList []string
|
||||
|
||||
@@ -1104,53 +1232,11 @@ func (a *App) InviteGuestsToChannels(teamId string, guestsInvite *model.GuestsIn
|
||||
return model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
if err := guestsInvite.IsValid(); err != nil {
|
||||
user, team, channels, err := a.prepareInviteGuestsToChannels(teamId, guestsInvite, senderId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tchan := make(chan store.StoreResult, 1)
|
||||
go func() {
|
||||
team, err := a.Srv.Store.Team().Get(teamId)
|
||||
tchan <- store.StoreResult{Data: team, Err: err}
|
||||
close(tchan)
|
||||
}()
|
||||
cchan := make(chan store.StoreResult, 1)
|
||||
go func() {
|
||||
channels, err := a.Srv.Store.Channel().GetChannelsByIds(guestsInvite.Channels)
|
||||
cchan <- store.StoreResult{Data: channels, Err: err}
|
||||
close(cchan)
|
||||
}()
|
||||
uchan := make(chan store.StoreResult, 1)
|
||||
go func() {
|
||||
user, err := a.Srv.Store.User().Get(senderId)
|
||||
uchan <- store.StoreResult{Data: user, Err: err}
|
||||
close(uchan)
|
||||
}()
|
||||
|
||||
result := <-cchan
|
||||
if result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
channels := result.Data.([]*model.Channel)
|
||||
|
||||
result = <-uchan
|
||||
if result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
user := result.Data.(*model.User)
|
||||
|
||||
result = <-tchan
|
||||
if result.Err != nil {
|
||||
return result.Err
|
||||
}
|
||||
team := result.Data.(*model.Team)
|
||||
|
||||
for _, channel := range channels {
|
||||
if channel.TeamId != teamId {
|
||||
return model.NewAppError("InviteGuestsToChannels", "api.team.invite_guests.channel_in_invalid_team.app_error", nil, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
var invalidEmailList []string
|
||||
for _, email := range guestsInvite.Emails {
|
||||
if !CheckEmailDomain(email, *a.Config().GuestAccountsSettings.RestrictCreationToDomains) {
|
||||
|
||||
@@ -1985,6 +1985,31 @@ func (c *Client4) InviteGuestsToTeam(teamId string, userEmails []string, channel
|
||||
return CheckStatusOK(r), BuildResponse(r)
|
||||
}
|
||||
|
||||
// InviteUsersToTeam invite users by email to the team.
|
||||
func (c *Client4) InviteUsersToTeamGracefully(teamId string, userEmails []string) ([]*EmailInviteWithError, *Response) {
|
||||
r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email?graceful=true", ArrayToJson(userEmails))
|
||||
if err != nil {
|
||||
return nil, BuildErrorResponse(r, err)
|
||||
}
|
||||
defer closeBody(r)
|
||||
return EmailInviteWithErrorFromJson(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
// InviteGuestsToTeam invite guest by email to some channels in a team.
|
||||
func (c *Client4) InviteGuestsToTeamGracefully(teamId string, userEmails []string, channels []string, message string) ([]*EmailInviteWithError, *Response) {
|
||||
guestsInvite := GuestsInvite{
|
||||
Emails: userEmails,
|
||||
Channels: channels,
|
||||
Message: message,
|
||||
}
|
||||
r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite-guests/email?graceful=true", guestsInvite.ToJson())
|
||||
if err != nil {
|
||||
return nil, BuildErrorResponse(r, err)
|
||||
}
|
||||
defer closeBody(r)
|
||||
return EmailInviteWithErrorFromJson(r.Body), BuildResponse(r)
|
||||
}
|
||||
|
||||
// InvalidateEmailInvites will invalidate active email invitations that have not been accepted by the user.
|
||||
func (c *Client4) InvalidateEmailInvites() (bool, *Response) {
|
||||
r, err := c.DoApiDelete(c.GetTeamsRoute() + "/invites/email")
|
||||
|
||||
@@ -38,6 +38,11 @@ type TeamMemberWithError struct {
|
||||
Error *AppError `json:"error"`
|
||||
}
|
||||
|
||||
type EmailInviteWithError struct {
|
||||
Email string `json:"email"`
|
||||
Error *AppError `json:"error"`
|
||||
}
|
||||
|
||||
func (o *TeamMember) ToJson() string {
|
||||
b, _ := json.Marshal(o)
|
||||
return string(b)
|
||||
@@ -60,6 +65,30 @@ func TeamUnreadFromJson(data io.Reader) *TeamUnread {
|
||||
return o
|
||||
}
|
||||
|
||||
func EmailInviteWithErrorFromJson(data io.Reader) []*EmailInviteWithError {
|
||||
var o []*EmailInviteWithError
|
||||
json.NewDecoder(data).Decode(&o)
|
||||
return o
|
||||
}
|
||||
|
||||
func EmailInviteWithErrorToEmails(o []*EmailInviteWithError) []string {
|
||||
var ret []string
|
||||
for _, o := range o {
|
||||
if o.Error == nil {
|
||||
ret = append(ret, o.Email)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func EmailInviteWithErrorToJson(o []*EmailInviteWithError) string {
|
||||
if b, err := json.Marshal(o); err != nil {
|
||||
return "[]"
|
||||
} else {
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
|
||||
func TeamMembersWithErrorToTeamMembers(o []*TeamMemberWithError) []*TeamMember {
|
||||
var ret []*TeamMember
|
||||
for _, o := range o {
|
||||
|
||||
Ссылка в новой задаче
Block a user