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

Этот коммит содержится в:
Eli Yukelzon
2020-01-29 12:56:59 +02:00
коммит произвёл GitHub
родитель 682a1d5d15
Коммит 4b39d8487b
5 изменённых файлов: 248 добавлений и 69 удалений

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

@@ -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")
})

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

@@ -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 {