code.gitea.io/gitea@v1.22.3/tests/integration/org_team_invite_test.go (about) 1 // Copyright 2022 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package integration 5 6 import ( 7 "fmt" 8 "net/http" 9 "net/url" 10 "strings" 11 "testing" 12 13 "code.gitea.io/gitea/models/db" 14 "code.gitea.io/gitea/models/organization" 15 "code.gitea.io/gitea/models/unittest" 16 user_model "code.gitea.io/gitea/models/user" 17 "code.gitea.io/gitea/modules/setting" 18 "code.gitea.io/gitea/modules/test" 19 "code.gitea.io/gitea/tests" 20 21 "github.com/stretchr/testify/assert" 22 ) 23 24 func TestOrgTeamEmailInvite(t *testing.T) { 25 if setting.MailService == nil { 26 t.Skip() 27 return 28 } 29 30 defer tests.PrepareTestEnv(t)() 31 32 org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) 33 team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) 34 user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) 35 36 isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID) 37 assert.NoError(t, err) 38 assert.False(t, isMember) 39 40 session := loginUser(t, "user1") 41 42 teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) 43 csrf := GetCSRF(t, session, teamURL) 44 req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ 45 "_csrf": csrf, 46 "uid": "1", 47 "uname": user.Email, 48 }) 49 resp := session.MakeRequest(t, req, http.StatusSeeOther) 50 req = NewRequest(t, "GET", test.RedirectURL(resp)) 51 session.MakeRequest(t, req, http.StatusOK) 52 53 // get the invite token 54 invites, err := organization.GetInvitesByTeamID(db.DefaultContext, team.ID) 55 assert.NoError(t, err) 56 assert.Len(t, invites, 1) 57 58 session = loginUser(t, user.Name) 59 60 // join the team 61 inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token) 62 csrf = GetCSRF(t, session, inviteURL) 63 req = NewRequestWithValues(t, "POST", inviteURL, map[string]string{ 64 "_csrf": csrf, 65 }) 66 resp = session.MakeRequest(t, req, http.StatusSeeOther) 67 req = NewRequest(t, "GET", test.RedirectURL(resp)) 68 session.MakeRequest(t, req, http.StatusOK) 69 70 isMember, err = organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID) 71 assert.NoError(t, err) 72 assert.True(t, isMember) 73 } 74 75 // Check that users are redirected to accept the invitation correctly after login 76 func TestOrgTeamEmailInviteRedirectsExistingUser(t *testing.T) { 77 if setting.MailService == nil { 78 t.Skip() 79 return 80 } 81 82 defer tests.PrepareTestEnv(t)() 83 84 org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) 85 team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) 86 user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) 87 88 isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID) 89 assert.NoError(t, err) 90 assert.False(t, isMember) 91 92 // create the invite 93 session := loginUser(t, "user1") 94 95 teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) 96 req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ 97 "_csrf": GetCSRF(t, session, teamURL), 98 "uid": "1", 99 "uname": user.Email, 100 }) 101 resp := session.MakeRequest(t, req, http.StatusSeeOther) 102 req = NewRequest(t, "GET", test.RedirectURL(resp)) 103 session.MakeRequest(t, req, http.StatusOK) 104 105 // get the invite token 106 invites, err := organization.GetInvitesByTeamID(db.DefaultContext, team.ID) 107 assert.NoError(t, err) 108 assert.Len(t, invites, 1) 109 110 // accept the invite 111 inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token) 112 req = NewRequest(t, "GET", fmt.Sprintf("/user/login?redirect_to=%s", url.QueryEscape(inviteURL))) 113 resp = MakeRequest(t, req, http.StatusOK) 114 115 doc := NewHTMLParser(t, resp.Body) 116 req = NewRequestWithValues(t, "POST", "/user/login", map[string]string{ 117 "_csrf": doc.GetCSRF(), 118 "user_name": "user5", 119 "password": "password", 120 }) 121 for _, c := range resp.Result().Cookies() { 122 req.AddCookie(c) 123 } 124 125 resp = MakeRequest(t, req, http.StatusSeeOther) 126 assert.Equal(t, inviteURL, test.RedirectURL(resp)) 127 128 // complete the login process 129 ch := http.Header{} 130 ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) 131 cr := http.Request{Header: ch} 132 133 session = emptyTestSession(t) 134 baseURL, err := url.Parse(setting.AppURL) 135 assert.NoError(t, err) 136 session.jar.SetCookies(baseURL, cr.Cookies()) 137 138 // make the request 139 req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{ 140 "_csrf": GetCSRF(t, session, test.RedirectURL(resp)), 141 }) 142 resp = session.MakeRequest(t, req, http.StatusSeeOther) 143 req = NewRequest(t, "GET", test.RedirectURL(resp)) 144 session.MakeRequest(t, req, http.StatusOK) 145 146 isMember, err = organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID) 147 assert.NoError(t, err) 148 assert.True(t, isMember) 149 } 150 151 // Check that newly signed up users are redirected to accept the invitation correctly 152 func TestOrgTeamEmailInviteRedirectsNewUser(t *testing.T) { 153 if setting.MailService == nil { 154 t.Skip() 155 return 156 } 157 158 defer tests.PrepareTestEnv(t)() 159 160 org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) 161 team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) 162 163 // create the invite 164 session := loginUser(t, "user1") 165 166 teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) 167 req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ 168 "_csrf": GetCSRF(t, session, teamURL), 169 "uid": "1", 170 "uname": "doesnotexist@example.com", 171 }) 172 resp := session.MakeRequest(t, req, http.StatusSeeOther) 173 req = NewRequest(t, "GET", test.RedirectURL(resp)) 174 session.MakeRequest(t, req, http.StatusOK) 175 176 // get the invite token 177 invites, err := organization.GetInvitesByTeamID(db.DefaultContext, team.ID) 178 assert.NoError(t, err) 179 assert.Len(t, invites, 1) 180 181 // accept the invite 182 inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token) 183 req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL))) 184 resp = MakeRequest(t, req, http.StatusOK) 185 186 doc := NewHTMLParser(t, resp.Body) 187 req = NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{ 188 "_csrf": doc.GetCSRF(), 189 "user_name": "doesnotexist", 190 "email": "doesnotexist@example.com", 191 "password": "examplePassword!1", 192 "retype": "examplePassword!1", 193 }) 194 for _, c := range resp.Result().Cookies() { 195 req.AddCookie(c) 196 } 197 198 resp = MakeRequest(t, req, http.StatusSeeOther) 199 assert.Equal(t, inviteURL, test.RedirectURL(resp)) 200 201 // complete the signup process 202 ch := http.Header{} 203 ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) 204 cr := http.Request{Header: ch} 205 206 session = emptyTestSession(t) 207 baseURL, err := url.Parse(setting.AppURL) 208 assert.NoError(t, err) 209 session.jar.SetCookies(baseURL, cr.Cookies()) 210 211 // make the redirected request 212 req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{ 213 "_csrf": GetCSRF(t, session, test.RedirectURL(resp)), 214 }) 215 resp = session.MakeRequest(t, req, http.StatusSeeOther) 216 req = NewRequest(t, "GET", test.RedirectURL(resp)) 217 session.MakeRequest(t, req, http.StatusOK) 218 219 // get the new user 220 newUser, err := user_model.GetUserByName(db.DefaultContext, "doesnotexist") 221 assert.NoError(t, err) 222 223 isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, newUser.ID) 224 assert.NoError(t, err) 225 assert.True(t, isMember) 226 } 227 228 // Check that users are redirected correctly after confirming their email 229 func TestOrgTeamEmailInviteRedirectsNewUserWithActivation(t *testing.T) { 230 if setting.MailService == nil { 231 t.Skip() 232 return 233 } 234 235 // enable email confirmation temporarily 236 defer func(prevVal bool) { 237 setting.Service.RegisterEmailConfirm = prevVal 238 }(setting.Service.RegisterEmailConfirm) 239 setting.Service.RegisterEmailConfirm = true 240 241 defer tests.PrepareTestEnv(t)() 242 243 org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) 244 team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) 245 246 // create the invite 247 session := loginUser(t, "user1") 248 249 teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) 250 req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ 251 "_csrf": GetCSRF(t, session, teamURL), 252 "uid": "1", 253 "uname": "doesnotexist@example.com", 254 }) 255 resp := session.MakeRequest(t, req, http.StatusSeeOther) 256 req = NewRequest(t, "GET", test.RedirectURL(resp)) 257 session.MakeRequest(t, req, http.StatusOK) 258 259 // get the invite token 260 invites, err := organization.GetInvitesByTeamID(db.DefaultContext, team.ID) 261 assert.NoError(t, err) 262 assert.Len(t, invites, 1) 263 264 // accept the invite 265 inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token) 266 req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL))) 267 inviteResp := MakeRequest(t, req, http.StatusOK) 268 269 doc := NewHTMLParser(t, resp.Body) 270 req = NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{ 271 "_csrf": doc.GetCSRF(), 272 "user_name": "doesnotexist", 273 "email": "doesnotexist@example.com", 274 "password": "examplePassword!1", 275 "retype": "examplePassword!1", 276 }) 277 for _, c := range inviteResp.Result().Cookies() { 278 req.AddCookie(c) 279 } 280 281 resp = MakeRequest(t, req, http.StatusOK) 282 283 user, err := user_model.GetUserByName(db.DefaultContext, "doesnotexist") 284 assert.NoError(t, err) 285 286 ch := http.Header{} 287 ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) 288 cr := http.Request{Header: ch} 289 290 session = emptyTestSession(t) 291 baseURL, err := url.Parse(setting.AppURL) 292 assert.NoError(t, err) 293 session.jar.SetCookies(baseURL, cr.Cookies()) 294 295 activateURL := fmt.Sprintf("/user/activate?code=%s", user.GenerateEmailActivateCode("doesnotexist@example.com")) 296 req = NewRequestWithValues(t, "POST", activateURL, map[string]string{ 297 "password": "examplePassword!1", 298 }) 299 300 // use the cookies set by the signup request 301 for _, c := range inviteResp.Result().Cookies() { 302 req.AddCookie(c) 303 } 304 305 resp = session.MakeRequest(t, req, http.StatusSeeOther) 306 // should be redirected to accept the invite 307 assert.Equal(t, inviteURL, test.RedirectURL(resp)) 308 309 req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{ 310 "_csrf": GetCSRF(t, session, test.RedirectURL(resp)), 311 }) 312 resp = session.MakeRequest(t, req, http.StatusSeeOther) 313 req = NewRequest(t, "GET", test.RedirectURL(resp)) 314 session.MakeRequest(t, req, http.StatusOK) 315 316 isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID) 317 assert.NoError(t, err) 318 assert.True(t, isMember) 319 } 320 321 // Test that a logged-in user who navigates to the sign-up link is then redirected using redirect_to 322 // For example: an invite may have been created before the user account was created, but they may be 323 // accepting the invite after having created an account separately 324 func TestOrgTeamEmailInviteRedirectsExistingUserWithLogin(t *testing.T) { 325 if setting.MailService == nil { 326 t.Skip() 327 return 328 } 329 330 defer tests.PrepareTestEnv(t)() 331 332 org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) 333 team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) 334 user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) 335 336 isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID) 337 assert.NoError(t, err) 338 assert.False(t, isMember) 339 340 // create the invite 341 session := loginUser(t, "user1") 342 343 teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) 344 req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ 345 "_csrf": GetCSRF(t, session, teamURL), 346 "uid": "1", 347 "uname": user.Email, 348 }) 349 resp := session.MakeRequest(t, req, http.StatusSeeOther) 350 req = NewRequest(t, "GET", test.RedirectURL(resp)) 351 session.MakeRequest(t, req, http.StatusOK) 352 353 // get the invite token 354 invites, err := organization.GetInvitesByTeamID(db.DefaultContext, team.ID) 355 assert.NoError(t, err) 356 assert.Len(t, invites, 1) 357 358 // note: the invited user has logged in 359 session = loginUser(t, "user5") 360 361 // accept the invite (note: this uses the sign_up url) 362 inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token) 363 req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL))) 364 resp = session.MakeRequest(t, req, http.StatusSeeOther) 365 assert.Equal(t, inviteURL, test.RedirectURL(resp)) 366 367 // make the request 368 req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{ 369 "_csrf": GetCSRF(t, session, test.RedirectURL(resp)), 370 }) 371 resp = session.MakeRequest(t, req, http.StatusSeeOther) 372 req = NewRequest(t, "GET", test.RedirectURL(resp)) 373 session.MakeRequest(t, req, http.StatusOK) 374 375 isMember, err = organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID) 376 assert.NoError(t, err) 377 assert.True(t, isMember) 378 }