mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Update team invitation email link (#26550)
Co-authored-by: Kyle D <kdumontnu@gmail.com> Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
This commit is contained in:
		@@ -398,6 +398,11 @@ func SignUp(ctx *context.Context) {
 | 
				
			|||||||
	// Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true
 | 
						// Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true
 | 
				
			||||||
	ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration || setting.Service.AllowOnlyExternalRegistration
 | 
						ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration || setting.Service.AllowOnlyExternalRegistration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						redirectTo := ctx.FormString("redirect_to")
 | 
				
			||||||
 | 
						if len(redirectTo) > 0 {
 | 
				
			||||||
 | 
							middleware.SetRedirectToCookie(ctx.Resp, redirectTo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.HTML(http.StatusOK, tplSignUp)
 | 
						ctx.HTML(http.StatusOK, tplSignUp)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -729,6 +734,12 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Flash.Success(ctx.Tr("auth.account_activated"))
 | 
						ctx.Flash.Success(ctx.Tr("auth.account_activated"))
 | 
				
			||||||
 | 
						if redirectTo := ctx.GetSiteCookie("redirect_to"); len(redirectTo) > 0 {
 | 
				
			||||||
 | 
							middleware.DeleteRedirectToCookie(ctx.Resp)
 | 
				
			||||||
 | 
							ctx.RedirectToFirst(redirectTo)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.Redirect(setting.AppSubURL + "/")
 | 
						ctx.Redirect(setting.AppSubURL + "/")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,9 +120,9 @@ func VerifyAuthWithOptions(options *VerifyOptions) func(ctx *context.Context) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Redirect to dashboard if user tries to visit any non-login page.
 | 
							// Redirect to dashboard (or alternate location) if user tries to visit any non-login page.
 | 
				
			||||||
		if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" {
 | 
							if options.SignOutRequired && ctx.IsSigned && ctx.Req.URL.RequestURI() != "/" {
 | 
				
			||||||
			ctx.Redirect(setting.AppSubURL + "/")
 | 
								ctx.RedirectToFirst(ctx.FormString("redirect_to"))
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@ package mailer
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	org_model "code.gitea.io/gitea/models/organization"
 | 
						org_model "code.gitea.io/gitea/models/organization"
 | 
				
			||||||
	user_model "code.gitea.io/gitea/models/user"
 | 
						user_model "code.gitea.io/gitea/models/user"
 | 
				
			||||||
@@ -33,6 +35,22 @@ func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_mod
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	locale := translation.NewLocale(inviter.Language)
 | 
						locale := translation.NewLocale(inviter.Language)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// check if a user with this email already exists
 | 
				
			||||||
 | 
						user, err := user_model.GetUserByEmail(ctx, invite.Email)
 | 
				
			||||||
 | 
						if err != nil && !user_model.IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						} else if user != nil && user.ProhibitLogin {
 | 
				
			||||||
 | 
							return fmt.Errorf("login is prohibited for the invited user")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						inviteRedirect := url.QueryEscape(fmt.Sprintf("/org/invite/%s", invite.Token))
 | 
				
			||||||
 | 
						inviteURL := fmt.Sprintf("%suser/sign_up?redirect_to=%s", setting.AppURL, inviteRedirect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err == nil && user != nil {
 | 
				
			||||||
 | 
							// user account exists
 | 
				
			||||||
 | 
							inviteURL = fmt.Sprintf("%suser/login?redirect_to=%s", setting.AppURL, inviteRedirect)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	subject := locale.Tr("mail.team_invite.subject", inviter.DisplayName(), org.DisplayName())
 | 
						subject := locale.Tr("mail.team_invite.subject", inviter.DisplayName(), org.DisplayName())
 | 
				
			||||||
	mailMeta := map[string]any{
 | 
						mailMeta := map[string]any{
 | 
				
			||||||
		"Inviter":      inviter,
 | 
							"Inviter":      inviter,
 | 
				
			||||||
@@ -40,6 +58,7 @@ func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_mod
 | 
				
			|||||||
		"Team":         team,
 | 
							"Team":         team,
 | 
				
			||||||
		"Invite":       invite,
 | 
							"Invite":       invite,
 | 
				
			||||||
		"Subject":      subject,
 | 
							"Subject":      subject,
 | 
				
			||||||
 | 
							"InviteURL":    inviteURL,
 | 
				
			||||||
		// helper
 | 
							// helper
 | 
				
			||||||
		"locale":    locale,
 | 
							"locale":    locale,
 | 
				
			||||||
		"Str2html":  templates.Str2html,
 | 
							"Str2html":  templates.Str2html,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,9 @@
 | 
				
			|||||||
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 | 
						<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 | 
				
			||||||
	<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no">
 | 
						<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no">
 | 
				
			||||||
</head>
 | 
					</head>
 | 
				
			||||||
{{$invite_url := printf "%sorg/invite/%s" AppUrl (QueryEscape .Invite.Token)}}
 | 
					 | 
				
			||||||
<body>
 | 
					<body>
 | 
				
			||||||
	<p>{{.locale.Tr "mail.team_invite.text_1" (DotEscape .Inviter.DisplayName) (DotEscape .Team.Name) (DotEscape .Organization.DisplayName) | Str2html}}</p>
 | 
						<p>{{.locale.Tr "mail.team_invite.text_1" (DotEscape .Inviter.DisplayName) (DotEscape .Team.Name) (DotEscape .Organization.DisplayName) | Str2html}}</p>
 | 
				
			||||||
	<p>{{.locale.Tr "mail.team_invite.text_2"}}</p><p><a href="{{$invite_url}}">{{$invite_url}}</a></p>
 | 
						<p>{{.locale.Tr "mail.team_invite.text_2"}}</p><p><a href="{{.InviteURL}}">{{.InviteURL}}</a></p>
 | 
				
			||||||
	<p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p>
 | 
						<p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p>
 | 
				
			||||||
	<p>{{.locale.Tr "mail.team_invite.text_3" .Invite.Email}}</p>
 | 
						<p>{{.locale.Tr "mail.team_invite.text_3" .Invite.Email}}</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,8 @@ package integration
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
@@ -37,9 +39,9 @@ func TestOrgTeamEmailInvite(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
						session := loginUser(t, "user1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	url := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
 | 
						teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
 | 
				
			||||||
	csrf := GetCSRF(t, session, url)
 | 
						csrf := GetCSRF(t, session, teamURL)
 | 
				
			||||||
	req := NewRequestWithValues(t, "POST", url+"/action/add", map[string]string{
 | 
						req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{
 | 
				
			||||||
		"_csrf": csrf,
 | 
							"_csrf": csrf,
 | 
				
			||||||
		"uid":   "1",
 | 
							"uid":   "1",
 | 
				
			||||||
		"uname": user.Email,
 | 
							"uname": user.Email,
 | 
				
			||||||
@@ -56,9 +58,9 @@ func TestOrgTeamEmailInvite(t *testing.T) {
 | 
				
			|||||||
	session = loginUser(t, user.Name)
 | 
						session = loginUser(t, user.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// join the team
 | 
						// join the team
 | 
				
			||||||
	url = fmt.Sprintf("/org/invite/%s", invites[0].Token)
 | 
						inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
 | 
				
			||||||
	csrf = GetCSRF(t, session, url)
 | 
						csrf = GetCSRF(t, session, inviteURL)
 | 
				
			||||||
	req = NewRequestWithValues(t, "POST", url, map[string]string{
 | 
						req = NewRequestWithValues(t, "POST", inviteURL, map[string]string{
 | 
				
			||||||
		"_csrf": csrf,
 | 
							"_csrf": csrf,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusSeeOther)
 | 
						resp = session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
@@ -69,3 +71,308 @@ func TestOrgTeamEmailInvite(t *testing.T) {
 | 
				
			|||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.True(t, isMember)
 | 
						assert.True(t, isMember)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Check that users are redirected to accept the invitation correctly after login
 | 
				
			||||||
 | 
					func TestOrgTeamEmailInviteRedirectsExistingUser(t *testing.T) {
 | 
				
			||||||
 | 
						if setting.MailService == nil {
 | 
				
			||||||
 | 
							t.Skip()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer tests.PrepareTestEnv(t)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
 | 
				
			||||||
 | 
						team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2})
 | 
				
			||||||
 | 
						user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.False(t, isMember)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create the invite
 | 
				
			||||||
 | 
						session := loginUser(t, "user1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
 | 
				
			||||||
 | 
						req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{
 | 
				
			||||||
 | 
							"_csrf": GetCSRF(t, session, teamURL),
 | 
				
			||||||
 | 
							"uid":   "1",
 | 
				
			||||||
 | 
							"uname": user.Email,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", test.RedirectURL(resp))
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get the invite token
 | 
				
			||||||
 | 
						invites, err := organization.GetInvitesByTeamID(db.DefaultContext, team.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.Len(t, invites, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// accept the invite
 | 
				
			||||||
 | 
						inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", fmt.Sprintf("/user/login?redirect_to=%s", url.QueryEscape(inviteURL)))
 | 
				
			||||||
 | 
						resp = MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", "/user/login", map[string]string{
 | 
				
			||||||
 | 
							"_csrf":     doc.GetCSRF(),
 | 
				
			||||||
 | 
							"user_name": "user5",
 | 
				
			||||||
 | 
							"password":  "password",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						for _, c := range resp.Result().Cookies() {
 | 
				
			||||||
 | 
							req.AddCookie(c)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp = MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						assert.Equal(t, inviteURL, test.RedirectURL(resp))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// complete the login process
 | 
				
			||||||
 | 
						ch := http.Header{}
 | 
				
			||||||
 | 
						ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";"))
 | 
				
			||||||
 | 
						cr := http.Request{Header: ch}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						session = emptyTestSession(t)
 | 
				
			||||||
 | 
						baseURL, err := url.Parse(setting.AppURL)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						session.jar.SetCookies(baseURL, cr.Cookies())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// make the request
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{
 | 
				
			||||||
 | 
							"_csrf": GetCSRF(t, session, test.RedirectURL(resp)),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", test.RedirectURL(resp))
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isMember, err = organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.True(t, isMember)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Check that newly signed up users are redirected to accept the invitation correctly
 | 
				
			||||||
 | 
					func TestOrgTeamEmailInviteRedirectsNewUser(t *testing.T) {
 | 
				
			||||||
 | 
						if setting.MailService == nil {
 | 
				
			||||||
 | 
							t.Skip()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer tests.PrepareTestEnv(t)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
 | 
				
			||||||
 | 
						team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create the invite
 | 
				
			||||||
 | 
						session := loginUser(t, "user1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
 | 
				
			||||||
 | 
						req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{
 | 
				
			||||||
 | 
							"_csrf": GetCSRF(t, session, teamURL),
 | 
				
			||||||
 | 
							"uid":   "1",
 | 
				
			||||||
 | 
							"uname": "doesnotexist@example.com",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", test.RedirectURL(resp))
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get the invite token
 | 
				
			||||||
 | 
						invites, err := organization.GetInvitesByTeamID(db.DefaultContext, team.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.Len(t, invites, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// accept the invite
 | 
				
			||||||
 | 
						inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL)))
 | 
				
			||||||
 | 
						resp = MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
 | 
				
			||||||
 | 
							"_csrf":     doc.GetCSRF(),
 | 
				
			||||||
 | 
							"user_name": "doesnotexist",
 | 
				
			||||||
 | 
							"email":     "doesnotexist@example.com",
 | 
				
			||||||
 | 
							"password":  "examplePassword!1",
 | 
				
			||||||
 | 
							"retype":    "examplePassword!1",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						for _, c := range resp.Result().Cookies() {
 | 
				
			||||||
 | 
							req.AddCookie(c)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp = MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						assert.Equal(t, inviteURL, test.RedirectURL(resp))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// complete the signup process
 | 
				
			||||||
 | 
						ch := http.Header{}
 | 
				
			||||||
 | 
						ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";"))
 | 
				
			||||||
 | 
						cr := http.Request{Header: ch}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						session = emptyTestSession(t)
 | 
				
			||||||
 | 
						baseURL, err := url.Parse(setting.AppURL)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						session.jar.SetCookies(baseURL, cr.Cookies())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// make the redirected request
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{
 | 
				
			||||||
 | 
							"_csrf": GetCSRF(t, session, test.RedirectURL(resp)),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", test.RedirectURL(resp))
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get the new user
 | 
				
			||||||
 | 
						newUser, err := user_model.GetUserByName(db.DefaultContext, "doesnotexist")
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, newUser.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.True(t, isMember)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Check that users are redirected correctly after confirming their email
 | 
				
			||||||
 | 
					func TestOrgTeamEmailInviteRedirectsNewUserWithActivation(t *testing.T) {
 | 
				
			||||||
 | 
						if setting.MailService == nil {
 | 
				
			||||||
 | 
							t.Skip()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// enable email confirmation temporarily
 | 
				
			||||||
 | 
						defer func(prevVal bool) {
 | 
				
			||||||
 | 
							setting.Service.RegisterEmailConfirm = prevVal
 | 
				
			||||||
 | 
						}(setting.Service.RegisterEmailConfirm)
 | 
				
			||||||
 | 
						setting.Service.RegisterEmailConfirm = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer tests.PrepareTestEnv(t)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
 | 
				
			||||||
 | 
						team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create the invite
 | 
				
			||||||
 | 
						session := loginUser(t, "user1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
 | 
				
			||||||
 | 
						req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{
 | 
				
			||||||
 | 
							"_csrf": GetCSRF(t, session, teamURL),
 | 
				
			||||||
 | 
							"uid":   "1",
 | 
				
			||||||
 | 
							"uname": "doesnotexist@example.com",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", test.RedirectURL(resp))
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get the invite token
 | 
				
			||||||
 | 
						invites, err := organization.GetInvitesByTeamID(db.DefaultContext, team.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.Len(t, invites, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// accept the invite
 | 
				
			||||||
 | 
						inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL)))
 | 
				
			||||||
 | 
						inviteResp := MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
 | 
				
			||||||
 | 
							"_csrf":     doc.GetCSRF(),
 | 
				
			||||||
 | 
							"user_name": "doesnotexist",
 | 
				
			||||||
 | 
							"email":     "doesnotexist@example.com",
 | 
				
			||||||
 | 
							"password":  "examplePassword!1",
 | 
				
			||||||
 | 
							"retype":    "examplePassword!1",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						for _, c := range inviteResp.Result().Cookies() {
 | 
				
			||||||
 | 
							req.AddCookie(c)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp = MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user, err := user_model.GetUserByName(db.DefaultContext, "doesnotexist")
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ch := http.Header{}
 | 
				
			||||||
 | 
						ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";"))
 | 
				
			||||||
 | 
						cr := http.Request{Header: ch}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						session = emptyTestSession(t)
 | 
				
			||||||
 | 
						baseURL, err := url.Parse(setting.AppURL)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						session.jar.SetCookies(baseURL, cr.Cookies())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						activateURL := fmt.Sprintf("/user/activate?code=%s", user.GenerateEmailActivateCode("doesnotexist@example.com"))
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", activateURL, map[string]string{
 | 
				
			||||||
 | 
							"password": "examplePassword!1",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// use the cookies set by the signup request
 | 
				
			||||||
 | 
						for _, c := range inviteResp.Result().Cookies() {
 | 
				
			||||||
 | 
							req.AddCookie(c)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						// should be redirected to accept the invite
 | 
				
			||||||
 | 
						assert.Equal(t, inviteURL, test.RedirectURL(resp))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{
 | 
				
			||||||
 | 
							"_csrf": GetCSRF(t, session, test.RedirectURL(resp)),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", test.RedirectURL(resp))
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.True(t, isMember)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Test that a logged-in user who navigates to the sign-up link is then redirected using redirect_to
 | 
				
			||||||
 | 
					// For example: an invite may have been created before the user account was created, but they may be
 | 
				
			||||||
 | 
					// accepting the invite after having created an account separately
 | 
				
			||||||
 | 
					func TestOrgTeamEmailInviteRedirectsExistingUserWithLogin(t *testing.T) {
 | 
				
			||||||
 | 
						if setting.MailService == nil {
 | 
				
			||||||
 | 
							t.Skip()
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						defer tests.PrepareTestEnv(t)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
 | 
				
			||||||
 | 
						team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2})
 | 
				
			||||||
 | 
						user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.False(t, isMember)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// create the invite
 | 
				
			||||||
 | 
						session := loginUser(t, "user1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
 | 
				
			||||||
 | 
						req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{
 | 
				
			||||||
 | 
							"_csrf": GetCSRF(t, session, teamURL),
 | 
				
			||||||
 | 
							"uid":   "1",
 | 
				
			||||||
 | 
							"uname": user.Email,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", test.RedirectURL(resp))
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// get the invite token
 | 
				
			||||||
 | 
						invites, err := organization.GetInvitesByTeamID(db.DefaultContext, team.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.Len(t, invites, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// note: the invited user has logged in
 | 
				
			||||||
 | 
						session = loginUser(t, "user5")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// accept the invite (note: this uses the sign_up url)
 | 
				
			||||||
 | 
						inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL)))
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						assert.Equal(t, inviteURL, test.RedirectURL(resp))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// make the request
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{
 | 
				
			||||||
 | 
							"_csrf": GetCSRF(t, session, test.RedirectURL(resp)),
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, http.StatusSeeOther)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", test.RedirectURL(resp))
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						isMember, err = organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID)
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.True(t, isMember)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user