Skip to content

Update team invitation email link #26550

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Aug 31, 2023
Merged
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c220423
update url for email invitation
jackHay22 Aug 16, 2023
4b4b030
Merge branch 'main' into jh/feat-email-invite-link
kdumontnu Aug 21, 2023
80dc1bc
Merge branch 'main' into jh/feat-email-invite-link
jackHay22 Aug 22, 2023
35c0deb
return error for user with prohibited login
jackHay22 Aug 23, 2023
9f18774
Merge branch 'main' into jh/feat-email-invite-link
jackHay22 Aug 23, 2023
4aa72a1
Check that user is not nil before ProhibitLogin
jackHay22 Aug 23, 2023
d55a191
Merge branch 'main' into jh/feat-email-invite-link
kdumontnu Aug 24, 2023
b947704
Merge branch 'main' into jh/feat-email-invite-link
GiteaBot Aug 24, 2023
743dbc8
Merge branch 'main' into jh/feat-email-invite-link
GiteaBot Aug 24, 2023
68c58ac
Merge branch 'main' into jh/feat-email-invite-link
GiteaBot Aug 24, 2023
61bf1e7
account activation should obey the redirect cookie
jackHay22 Aug 24, 2023
27d8590
signup -> login redirect should use redirect_to if available
jackHay22 Aug 24, 2023
3e6edfe
Merge branch 'main' into jh/feat-email-invite-link
jackHay22 Aug 24, 2023
079febe
update comment
jackHay22 Aug 24, 2023
f6be26e
add integration tests for login and sign up redirects
jackHay22 Aug 30, 2023
a3f1dee
linting fix
jackHay22 Aug 30, 2023
472ba2f
add more integration tests for invites
jackHay22 Aug 30, 2023
ebab62c
Merge branch 'main' into jh/feat-email-invite-link
jackHay22 Aug 30, 2023
6846f4e
cleanup
jackHay22 Aug 30, 2023
9de9041
construct invite url outside of template
jackHay22 Aug 31, 2023
3453d5b
Merge branch 'main' into jh/feat-email-invite-link
kdumontnu Aug 31, 2023
bbf905b
Merge branch 'main' into jh/feat-email-invite-link
GiteaBot Aug 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add more integration tests for invites
  • Loading branch information
jackHay22 committed Aug 30, 2023
commit 472ba2f9d3d51f3ed40530e6694f471f497f8cfd
177 changes: 160 additions & 17 deletions tests/integration/org_team_invite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ func TestOrgTeamEmailInvite(t *testing.T) {

session := loginUser(t, "user1")

url := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
csrf := GetCSRF(t, session, url)
req := NewRequestWithValues(t, "POST", url+"/action/add", map[string]string{
teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
csrf := GetCSRF(t, session, teamURL)
req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{
"_csrf": csrf,
"uid": "1",
"uname": user.Email,
Expand All @@ -58,9 +58,9 @@ func TestOrgTeamEmailInvite(t *testing.T) {
session = loginUser(t, user.Name)

// join the team
url = fmt.Sprintf("/org/invite/%s", invites[0].Token)
csrf = GetCSRF(t, session, url)
req = NewRequestWithValues(t, "POST", url, map[string]string{
inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token)
csrf = GetCSRF(t, session, inviteURL)
req = NewRequestWithValues(t, "POST", inviteURL, map[string]string{
"_csrf": csrf,
})
resp = session.MakeRequest(t, req, http.StatusSeeOther)
Expand All @@ -72,6 +72,7 @@ func TestOrgTeamEmailInvite(t *testing.T) {
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()
Expand All @@ -92,9 +93,8 @@ func TestOrgTeamEmailInviteRedirectsExistingUser(t *testing.T) {
session := loginUser(t, "user1")

teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
csrf := GetCSRF(t, session, teamURL)
req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{
"_csrf": csrf,
"_csrf": GetCSRF(t, session, teamURL),
"uid": "1",
"uname": user.Email,
})
Expand Down Expand Up @@ -136,12 +136,8 @@ func TestOrgTeamEmailInviteRedirectsExistingUser(t *testing.T) {
session.jar.SetCookies(baseURL, cr.Cookies())

// make the request
req = NewRequest(t, "GET", test.RedirectURL(resp))
session.MakeRequest(t, req, http.StatusOK)

csrf = GetCSRF(t, session, test.RedirectURL(resp))
req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{
"_csrf": csrf,
"_csrf": GetCSRF(t, session, test.RedirectURL(resp)),
})
resp = session.MakeRequest(t, req, http.StatusSeeOther)
req = NewRequest(t, "GET", test.RedirectURL(resp))
Expand All @@ -152,6 +148,7 @@ func TestOrgTeamEmailInviteRedirectsExistingUser(t *testing.T) {
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()
Expand All @@ -167,9 +164,8 @@ func TestOrgTeamEmailInviteRedirectsNewUser(t *testing.T) {
session := loginUser(t, "user1")

teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name)
csrf := GetCSRF(t, session, teamURL)
req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{
"_csrf": csrf,
"_csrf": GetCSRF(t, session, teamURL),
"uid": "1",
"uname": "doesnotexist@example.com",
})
Expand Down Expand Up @@ -216,9 +212,8 @@ func TestOrgTeamEmailInviteRedirectsNewUser(t *testing.T) {
req = NewRequest(t, "GET", test.RedirectURL(resp))
session.MakeRequest(t, req, http.StatusOK)

csrf = GetCSRF(t, session, test.RedirectURL(resp))
req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{
"_csrf": csrf,
"_csrf": GetCSRF(t, session, test.RedirectURL(resp)),
})
resp = session.MakeRequest(t, req, http.StatusSeeOther)
req = NewRequest(t, "GET", test.RedirectURL(resp))
Expand All @@ -232,3 +227,151 @@ func TestOrgTeamEmailInviteRedirectsNewUser(t *testing.T) {
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
}

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