mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-07-18 07:28:47 +00:00
Fixes #12564. Fixes #8951. This introduces a new setting, `ADD_MEMBERS_BY_INVITATIONS`, which is turned off by default. When turned on, adding a user to a team issues an invitation instead of adding them directly to the team. A prerequisite for this work was to be able to link invitations to existing users (so far, they were only associated to an email address, since those invitations were meant to be issued to users who didn't have an account yet). --- I plan to work on the following improvements, which I propose to do in separate PRs given that this one is already a bit big: * generate an in-app notification for the invited user * advertise the invitation to the invited user from the org page as well (#12120) * show the list of invited users in the list of organization members (not just on the team page) and various other improvements to invitations (#12570, #12716). Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12845 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
123 lines
4.8 KiB
Go
123 lines
4.8 KiB
Go
// Copyright 2026 The Forgejo Authors
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package integration
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
|
|
"forgejo.org/models/db"
|
|
"forgejo.org/models/organization"
|
|
"forgejo.org/models/unittest"
|
|
user_model "forgejo.org/models/user"
|
|
"forgejo.org/modules/setting"
|
|
"forgejo.org/modules/test"
|
|
"forgejo.org/tests"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestPaginatedMembers(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
// To make sure that pagination kicks in even though the test team has few members
|
|
defer test.MockVariableValue(&setting.UI.MembersPagingNum, 2)()
|
|
|
|
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 17})
|
|
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 9})
|
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29})
|
|
|
|
assert.GreaterOrEqual(t, org.NumMembers, 3)
|
|
isOrgMember, err := organization.IsOrganizationMember(db.DefaultContext, org.ID, user.ID)
|
|
require.NoError(t, err)
|
|
assert.True(t, isOrgMember)
|
|
isTeamMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID)
|
|
require.NoError(t, err)
|
|
assert.True(t, isTeamMember)
|
|
assert.Equal(t, org.ID, team.OrgID)
|
|
|
|
session := loginUser(t, user.Name)
|
|
|
|
teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.LowerName)
|
|
newVar := session.MakeRequest(t, NewRequest(t, "GET", teamURL), http.StatusOK).Body
|
|
doc := NewHTMLParser(t, newVar)
|
|
assert.Contains(t, strings.TrimSpace(doc.Find("a.item.navigation:contains('Next')").AttrOr("href", "")), fmt.Sprintf("%s?page=2", teamURL))
|
|
}
|
|
|
|
func TestPaginatedRepos(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
// To make sure that pagination kicks in even though the test team has few repos
|
|
defer test.MockVariableValue(&setting.UI.User.RepoPagingNum, 2)()
|
|
|
|
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
|
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1})
|
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
|
|
assert.GreaterOrEqual(t, team.NumRepos, 3)
|
|
isOrgMember, err := organization.IsOrganizationMember(db.DefaultContext, org.ID, user.ID)
|
|
require.NoError(t, err)
|
|
assert.True(t, isOrgMember)
|
|
isTeamMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user.ID)
|
|
require.NoError(t, err)
|
|
assert.True(t, isTeamMember)
|
|
assert.Equal(t, org.ID, team.OrgID)
|
|
|
|
session := loginUser(t, user.Name)
|
|
|
|
teamURL := fmt.Sprintf("/org/%s/teams/%s/repositories", org.Name, team.LowerName)
|
|
body := session.MakeRequest(t, NewRequest(t, "GET", teamURL), http.StatusOK).Body
|
|
doc := NewHTMLParser(t, body)
|
|
assert.Contains(t, strings.TrimSpace(doc.Find("a.item.navigation:contains('Next')").AttrOr("href", "")), fmt.Sprintf("%s?page=2", teamURL))
|
|
}
|
|
|
|
func TestDisplayInvites(t *testing.T) {
|
|
defer unittest.OverrideFixtures("tests/integration/fixtures/TestDisplayInvites")()
|
|
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: 1})
|
|
|
|
session := loginUser(t, user.Name)
|
|
|
|
teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.LowerName)
|
|
body := session.MakeRequest(t, NewRequest(t, "GET", teamURL), http.StatusOK).Body
|
|
doc := NewHTMLParser(t, body)
|
|
|
|
// the two invited users are shown
|
|
assert.Equal(t, "/user31", doc.Find("a:contains('user31')").AttrOr("href", ""))
|
|
assert.Equal(t, 1, doc.Find("div.flex-item-main:contains('external_user@example.com')").Length())
|
|
}
|
|
|
|
func TestAddMembersByInvitations(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
defer test.MockVariableValue(&setting.Service.AddMembersByInvitations, true)()
|
|
|
|
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
|
|
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2})
|
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
|
|
session := loginUser(t, user.Name)
|
|
|
|
teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.LowerName)
|
|
body := session.MakeRequest(t, NewRequest(t, "GET", teamURL), http.StatusOK).Body
|
|
|
|
// the button to add a team member says "invite"
|
|
doc := NewHTMLParser(t, body)
|
|
doc.AssertElement(t, "button.primary:contains('Invite to team')", true)
|
|
|
|
// invite user "user31" to the team
|
|
req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/action/add", teamURL), map[string]string{
|
|
"uname": "user31",
|
|
})
|
|
resp := session.MakeRequest(t, req, http.StatusSeeOther)
|
|
assert.Equal(t, teamURL, resp.Header().Get("Location"))
|
|
|
|
// the invited user is listed on the team page
|
|
body = session.MakeRequest(t, NewRequest(t, "GET", teamURL), http.StatusOK).Body
|
|
doc = NewHTMLParser(t, body)
|
|
assert.Equal(t, "/user31", doc.Find("a:contains('user31')").AttrOr("href", ""))
|
|
}
|