diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 8c40bbc01df59..1a882b5dbf051 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2629,6 +2629,10 @@ members.remove = Remove members.remove.detail = Remove %[1]s from %[2]s? members.leave = Leave members.leave.detail = Leave %s? +members.invite = Invite +members.invite_member = Invite Member +members.to = To +members.team = Team members.invite_desc = Add a new member to %s: members.invite_now = Invite Now diff --git a/routers/web/org/members.go b/routers/web/org/members.go index 15a615c706fe6..b880b346d25be 100644 --- a/routers/web/org/members.go +++ b/routers/web/org/members.go @@ -6,6 +6,7 @@ package org import ( "net/http" + "net/url" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" @@ -14,11 +15,13 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" shared_user "code.gitea.io/gitea/routers/web/shared/user" + org_service "code.gitea.io/gitea/services/org" ) const ( // tplMembers template for organization members page - tplMembers base.TplName = "org/member/members" + tplMembers base.TplName = "org/member/members" + tplMembersInvite base.TplName = "org/member/invite" ) // Members render organization users page @@ -76,6 +79,48 @@ func Members(ctx *context.Context) { ctx.HTML(http.StatusOK, tplMembers) } +// MembersInvite render organization members invite page +func MembersInvite(ctx *context.Context) { + org := ctx.Org.Organization + ctx.Data["Title"] = org.FullName + ctx.Data["PageIsOrgMembers"] = true + ctx.Data["Teams"] = ctx.Org.Teams + ctx.Data["IsEmailInviteEnabled"] = setting.MailService != nil + if err := shared_user.LoadHeaderCount(ctx); err != nil { + ctx.ServerError("LoadHeaderCount", err) + return + } + ctx.HTML(http.StatusOK, tplMembersInvite) +} + +// MembersInviteAction response for invite a member to organization +func MembersInviteAction(ctx *context.Context) { + var err error + if !ctx.Org.IsOwner { + ctx.Error(http.StatusNotFound) + return + } + var team *organization.Team + team, err = organization.GetTeam(ctx, ctx.Org.Organization.ID, ctx.FormString("team")) + if err != nil { + if organization.IsErrTeamNotExist(err) { + ctx.Flash.Error(ctx.Tr("form.team_not_exist")) + } else { + ctx.ServerError("GetTeam", err) + } + return + } + var isServerError bool + isServerError, err = org_service.AddTeamMember(ctx, ctx.Doer, team, ctx.FormString("uname"), ctx.Locale) + if isServerError { + ctx.ServerError("AddTeamMember", err) + return + } else if err != nil { + ctx.Flash.Error(err.Error()) + } + ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(team.LowerName)) +} + // MembersAction response for operation to a member of organization func MembersAction(ctx *context.Context) { uid := ctx.FormInt64("uid") diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 9e65c8ba9cd95..3fe8e6fb1654d 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -10,7 +10,6 @@ import ( "net/url" "path" "strconv" - "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" @@ -24,7 +23,6 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" - "code.gitea.io/gitea/routers/utils" shared_user "code.gitea.io/gitea/routers/web/shared/user" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" @@ -127,44 +125,18 @@ func TeamsAction(ctx *context.Context) { ctx.Error(http.StatusNotFound) return } - uname := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.FormString("uname"))) - var u *user_model.User - u, err = user_model.GetUserByName(ctx, uname) - if err != nil { - if user_model.IsErrUserNotExist(err) { - if setting.MailService != nil && user_model.ValidateEmail(uname) == nil { - if err := org_service.CreateTeamInvite(ctx, ctx.Doer, ctx.Org.Team, uname); err != nil { - if org_model.IsErrTeamInviteAlreadyExist(err) { - ctx.Flash.Error(ctx.Tr("form.duplicate_invite_to_team")) - } else if org_model.IsErrUserEmailAlreadyAdded(err) { - ctx.Flash.Error(ctx.Tr("org.teams.add_duplicate_users")) - } else { - ctx.ServerError("CreateTeamInvite", err) - return - } - } - } else { - ctx.Flash.Error(ctx.Tr("form.user_not_exist")) - } - ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(ctx.Org.Team.LowerName)) - } else { - ctx.ServerError("GetUserByName", err) - } - return - } - if u.IsOrganization() { - ctx.Flash.Error(ctx.Tr("form.cannot_add_org_to_team")) + var isServerError bool + isServerError, err = org_service.AddTeamMember(ctx, ctx.Doer, ctx.Org.Team, ctx.FormString("uname"), ctx.Locale) + if !isServerError { + ctx.ServerError("AddTeamMember", err) + return + } else if err != nil { + ctx.Flash.Error(err.Error()) ctx.Redirect(ctx.Org.OrgLink + "/teams/" + url.PathEscape(ctx.Org.Team.LowerName)) return } - if ctx.Org.Team.IsMember(ctx, u.ID) { - ctx.Flash.Error(ctx.Tr("org.teams.add_duplicate_users")) - } else { - err = models.AddTeamMember(ctx, ctx.Org.Team, u.ID) - } - page = "team" case "remove_invite": if !ctx.Org.IsOwner { diff --git a/routers/web/web.go b/routers/web/web.go index 6449f7716cf75..ce7fdabe09135 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -796,6 +796,8 @@ func registerRoutes(m *web.Route) { m.Group("/org", func() { m.Group("/{org}", func() { m.Get("/members", org.Members) + m.Get("/members/invite", org.MembersInvite) + m.Post("/members/invite", org.MembersInviteAction) }, context.OrgAssignment()) }, ignSignIn) diff --git a/services/org/team_invite.go b/services/org/team_invite.go index 3f28044dbf65f..774e45eebbd15 100644 --- a/services/org/team_invite.go +++ b/services/org/team_invite.go @@ -5,9 +5,16 @@ package org import ( "context" + "errors" + "strings" + "code.gitea.io/gitea/models" org_model "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/routers/utils" "code.gitea.io/gitea/services/mailer" ) @@ -20,3 +27,43 @@ func CreateTeamInvite(ctx context.Context, inviter *user_model.User, team *org_m return mailer.MailTeamInvite(ctx, inviter, team, invite) } + +// AddTeamMember add user to a team +func AddTeamMember(ctx context.Context, inviter *user_model.User, team *org_model.Team, username string, locale translation.Locale) (isServerError bool, err error) { + uname := utils.RemoveUsernameParameterSuffix(strings.ToLower(username)) + var u *user_model.User + if u, err = user_model.GetUserByName(ctx, uname); err != nil { + if user_model.IsErrUserNotExist(err) { + if setting.MailService != nil && user_model.ValidateEmail(uname) == nil { + if err := CreateTeamInvite(ctx, inviter, team, uname); err != nil { + if org_model.IsErrTeamInviteAlreadyExist(err) { + return false, errors.New(locale.Tr("form.duplicate_invite_to_team")) + } else if org_model.IsErrUserEmailAlreadyAdded(err) { + return false, errors.New(locale.Tr("org.teams.add_duplicate_users")) + } + log.Error("CreateTeamInvite: %v", err) + return true, err + } + } else { + err = errors.New(locale.Tr("form.user_not_exist")) + } + } else { + log.Error("GetUserByName: %v", err) + return true, err + } + return false, err + } + + if u.IsOrganization() { + return false, errors.New(locale.Tr("form.cannot_add_org_to_team")) + } + + if team.IsMember(ctx, u.ID) { + err = errors.New(locale.Tr("org.teams.add_duplicate_users")) + } else { + if err = models.AddTeamMember(ctx, team, u.ID); err != nil { + return true, err + } + } + return false, err +} diff --git a/templates/org/member/invite.tmpl b/templates/org/member/invite.tmpl new file mode 100644 index 0000000000000..db965764d84b0 --- /dev/null +++ b/templates/org/member/invite.tmpl @@ -0,0 +1,30 @@ +{{template "base/head" .}} +