mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-07-18 23:47:50 +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>
525 lines
21 KiB
Go
525 lines
21 KiB
Go
// Copyright 2017 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package integration
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"sort"
|
|
"testing"
|
|
|
|
auth_model "forgejo.org/models/auth"
|
|
"forgejo.org/models/db"
|
|
"forgejo.org/models/organization"
|
|
"forgejo.org/models/perm"
|
|
"forgejo.org/models/repo"
|
|
"forgejo.org/models/unit"
|
|
"forgejo.org/models/unittest"
|
|
user_model "forgejo.org/models/user"
|
|
"forgejo.org/modules/optional"
|
|
"forgejo.org/modules/setting"
|
|
api "forgejo.org/modules/structs"
|
|
"forgejo.org/modules/test"
|
|
"forgejo.org/services/convert"
|
|
"forgejo.org/tests"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestAPITeam(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
teamUser := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 1})
|
|
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamUser.TeamID})
|
|
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: teamUser.OrgID})
|
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID})
|
|
|
|
session := loginUser(t, user.Name)
|
|
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
|
|
req := NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID).
|
|
AddTokenAuth(token)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
|
|
var apiTeam api.Team
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
assert.Equal(t, team.ID, apiTeam.ID)
|
|
assert.Equal(t, team.Name, apiTeam.Name)
|
|
|
|
toOrg := convert.ToOrganization(db.DefaultContext, org)
|
|
assert.Equal(t, toOrg.ID, apiTeam.Organization.ID)
|
|
assert.Equal(t, toOrg.AvatarURL, apiTeam.Organization.AvatarURL)
|
|
assert.Equal(t, toOrg.Name, apiTeam.Organization.Name)
|
|
assert.Equal(t, toOrg.FullName, apiTeam.Organization.FullName)
|
|
assert.Equal(t, toOrg.Description, apiTeam.Organization.Description)
|
|
assert.Equal(t, toOrg.Website, apiTeam.Organization.Website)
|
|
assert.Equal(t, toOrg.Location, apiTeam.Organization.Location)
|
|
assert.Equal(t, toOrg.Visibility, apiTeam.Organization.Visibility)
|
|
assert.Equal(t, toOrg.RepoAdminChangeTeamAccess, apiTeam.Organization.RepoAdminChangeTeamAccess)
|
|
assert.Equal(t, toOrg.Created.Local(), apiTeam.Organization.Created.Local())
|
|
|
|
// non team member user will not access the teams details
|
|
teamUser2 := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 3})
|
|
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser2.UID})
|
|
|
|
session = loginUser(t, user2.Name)
|
|
token = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
|
|
req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID).
|
|
AddTokenAuth(token)
|
|
_ = MakeRequest(t, req, http.StatusForbidden)
|
|
|
|
req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID)
|
|
_ = MakeRequest(t, req, http.StatusUnauthorized)
|
|
|
|
// Get an admin user able to create, update and delete teams.
|
|
user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
|
|
session = loginUser(t, user.Name)
|
|
token = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization)
|
|
|
|
org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 6})
|
|
|
|
// Create team.
|
|
teamToCreate := &api.CreateTeamOption{
|
|
Name: "team1",
|
|
Description: "team one",
|
|
IncludesAllRepositories: true,
|
|
Permission: "write",
|
|
Units: []string{"repo.code", "repo.issues"},
|
|
}
|
|
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", org.Name), teamToCreate).
|
|
AddTokenAuth(token)
|
|
resp = MakeRequest(t, req, http.StatusCreated)
|
|
apiTeam = api.Team{}
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
checkTeamResponse(t, "CreateTeam1", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
|
|
teamToCreate.Permission, teamToCreate.Units, nil)
|
|
checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
|
|
teamToCreate.Permission, teamToCreate.Units, nil)
|
|
teamID := apiTeam.ID
|
|
|
|
// Edit team.
|
|
editDescription := "team 1"
|
|
editFalse := false
|
|
teamToEdit := &api.EditTeamOption{
|
|
Name: "teamone",
|
|
Description: &editDescription,
|
|
Permission: "admin",
|
|
IncludesAllRepositories: &editFalse,
|
|
Units: []string{"repo.code", "repo.pulls", "repo.releases"},
|
|
}
|
|
|
|
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEdit).
|
|
AddTokenAuth(token)
|
|
resp = MakeRequest(t, req, http.StatusOK)
|
|
apiTeam = api.Team{}
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
checkTeamResponse(t, "EditTeam1", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
|
|
teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
|
|
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
|
|
teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
|
|
|
|
// Edit team Description only
|
|
editDescription = "first team"
|
|
teamToEditDesc := api.EditTeamOption{Description: &editDescription}
|
|
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEditDesc).
|
|
AddTokenAuth(token)
|
|
resp = MakeRequest(t, req, http.StatusOK)
|
|
apiTeam = api.Team{}
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
checkTeamResponse(t, "EditTeam1_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
|
|
teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
|
|
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
|
|
teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
|
|
|
|
// Read team.
|
|
teamRead := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
|
|
require.NoError(t, teamRead.LoadUnits(db.DefaultContext))
|
|
req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamID).
|
|
AddTokenAuth(token)
|
|
resp = MakeRequest(t, req, http.StatusOK)
|
|
apiTeam = api.Team{}
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
checkTeamResponse(t, "ReadTeam1", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories,
|
|
teamRead.AccessMode.String(), teamRead.GetUnitNames(), teamRead.GetUnitsMap())
|
|
|
|
// Delete team.
|
|
req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID).
|
|
AddTokenAuth(token)
|
|
MakeRequest(t, req, http.StatusNoContent)
|
|
unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
|
|
|
|
// create team again via UnitsMap
|
|
// Create team.
|
|
teamToCreate = &api.CreateTeamOption{
|
|
Name: "team2",
|
|
Description: "team two",
|
|
IncludesAllRepositories: true,
|
|
Permission: "write",
|
|
UnitsMap: map[string]string{"repo.code": "read", "repo.issues": "write", "repo.wiki": "none"},
|
|
}
|
|
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", org.Name), teamToCreate).
|
|
AddTokenAuth(token)
|
|
resp = MakeRequest(t, req, http.StatusCreated)
|
|
apiTeam = api.Team{}
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
checkTeamResponse(t, "CreateTeam2", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
|
|
"read", nil, teamToCreate.UnitsMap)
|
|
checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
|
|
"read", nil, teamToCreate.UnitsMap)
|
|
teamID = apiTeam.ID
|
|
|
|
// Edit team.
|
|
editDescription = "team 1"
|
|
editFalse = false
|
|
teamToEdit = &api.EditTeamOption{
|
|
Name: "teamtwo",
|
|
Description: &editDescription,
|
|
Permission: "write",
|
|
IncludesAllRepositories: &editFalse,
|
|
UnitsMap: map[string]string{"repo.code": "read", "repo.pulls": "read", "repo.releases": "write"},
|
|
}
|
|
|
|
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEdit).
|
|
AddTokenAuth(token)
|
|
resp = MakeRequest(t, req, http.StatusOK)
|
|
apiTeam = api.Team{}
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
checkTeamResponse(t, "EditTeam2", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
|
|
"read", nil, teamToEdit.UnitsMap)
|
|
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
|
|
"read", nil, teamToEdit.UnitsMap)
|
|
|
|
// Edit team Description only
|
|
editDescription = "second team"
|
|
teamToEditDesc = api.EditTeamOption{Description: &editDescription}
|
|
req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEditDesc).
|
|
AddTokenAuth(token)
|
|
resp = MakeRequest(t, req, http.StatusOK)
|
|
apiTeam = api.Team{}
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
checkTeamResponse(t, "EditTeam2_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
|
|
"read", nil, teamToEdit.UnitsMap)
|
|
checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
|
|
"read", nil, teamToEdit.UnitsMap)
|
|
|
|
// Read team.
|
|
teamRead = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
|
|
req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamID).
|
|
AddTokenAuth(token)
|
|
resp = MakeRequest(t, req, http.StatusOK)
|
|
apiTeam = api.Team{}
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
require.NoError(t, teamRead.LoadUnits(db.DefaultContext))
|
|
checkTeamResponse(t, "ReadTeam2", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories,
|
|
teamRead.AccessMode.String(), teamRead.GetUnitNames(), teamRead.GetUnitsMap())
|
|
|
|
// Delete team.
|
|
req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID).
|
|
AddTokenAuth(token)
|
|
MakeRequest(t, req, http.StatusNoContent)
|
|
unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
|
|
|
|
// Create admin team
|
|
teamToCreate = &api.CreateTeamOption{
|
|
Name: "teamadmin",
|
|
Description: "team admin",
|
|
IncludesAllRepositories: true,
|
|
Permission: "admin",
|
|
}
|
|
req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", org.Name), teamToCreate).
|
|
AddTokenAuth(token)
|
|
resp = MakeRequest(t, req, http.StatusCreated)
|
|
apiTeam = api.Team{}
|
|
DecodeJSON(t, resp, &apiTeam)
|
|
for _, ut := range unit.AllRepoUnitTypes {
|
|
up := perm.AccessModeAdmin
|
|
if ut == unit.TypeExternalTracker || ut == unit.TypeExternalWiki {
|
|
up = perm.AccessModeRead
|
|
}
|
|
unittest.AssertExistsAndLoadBean(t, &organization.TeamUnit{
|
|
OrgID: org.ID,
|
|
TeamID: apiTeam.ID,
|
|
Type: ut,
|
|
AccessMode: up,
|
|
})
|
|
}
|
|
teamID = apiTeam.ID
|
|
|
|
// Delete team.
|
|
req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID).
|
|
AddTokenAuth(token)
|
|
MakeRequest(t, req, http.StatusNoContent)
|
|
unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
|
|
}
|
|
|
|
func checkTeamResponse(t *testing.T, testName string, apiTeam *api.Team, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
|
|
t.Run(testName, func(t *testing.T) {
|
|
assert.Equal(t, name, apiTeam.Name, "name")
|
|
assert.Equal(t, description, apiTeam.Description, "description")
|
|
assert.Equal(t, includesAllRepositories, apiTeam.IncludesAllRepositories, "includesAllRepositories")
|
|
assert.Equal(t, permission, apiTeam.Permission, "permission")
|
|
if units != nil {
|
|
sort.StringSlice(units).Sort()
|
|
sort.StringSlice(apiTeam.Units).Sort()
|
|
assert.Equal(t, units, apiTeam.Units, "units")
|
|
}
|
|
if unitsMap != nil {
|
|
assert.Equal(t, unitsMap, apiTeam.UnitsMap, "unitsMap")
|
|
}
|
|
})
|
|
}
|
|
|
|
func checkTeamBean(t *testing.T, id int64, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
|
|
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: id})
|
|
require.NoError(t, team.LoadUnits(db.DefaultContext), "LoadUnits")
|
|
apiTeam, err := convert.ToTeam(db.DefaultContext, team)
|
|
require.NoError(t, err)
|
|
checkTeamResponse(t, fmt.Sprintf("checkTeamBean/%s_%s", name, description), apiTeam, name, description, includesAllRepositories, permission, units, unitsMap)
|
|
}
|
|
|
|
type TeamSearchResults struct {
|
|
OK bool `json:"ok"`
|
|
Data []*api.Team `json:"data"`
|
|
}
|
|
|
|
func TestAPITeamSearch(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
|
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17})
|
|
|
|
var results TeamSearchResults
|
|
|
|
token := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadOrganization)
|
|
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "_team").
|
|
AddTokenAuth(token)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &results)
|
|
assert.NotEmpty(t, results.Data)
|
|
assert.Len(t, results.Data, 1)
|
|
assert.Equal(t, "test_team", results.Data[0].Name)
|
|
|
|
// no access if not organization member
|
|
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
|
token5 := getUserToken(t, user5.Name, auth_model.AccessTokenScopeReadOrganization)
|
|
|
|
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "team").
|
|
AddTokenAuth(token5)
|
|
MakeRequest(t, req, http.StatusForbidden)
|
|
}
|
|
|
|
func TestAPIGetTeamReposAccessTokenResources(t *testing.T) {
|
|
defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIGetTeamReposAccessTokenResources")()
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
var repos []api.Repository
|
|
|
|
// Test cases org3/repo21 (public), org3/repo3 (private), org3/repo5 (private) --
|
|
// TestAPIGetTeamReposAccessTokenResources fixtures create a team w/ ID=26 that contains all three repos.
|
|
session := loginUser(t, "user2")
|
|
|
|
find := func() (bool, bool, bool) {
|
|
foundRepo21 := false // public org3/repo21
|
|
foundRepo3 := false // private org3/repo3
|
|
foundRepo5 := false // second private repo org3/repo5 used in fine-grain testing, included as baseline
|
|
for _, repo := range repos {
|
|
switch repo.Name {
|
|
case "repo21":
|
|
foundRepo21 = true
|
|
case "repo3":
|
|
foundRepo3 = true
|
|
case "repo5":
|
|
foundRepo5 = true
|
|
}
|
|
}
|
|
return foundRepo21, foundRepo3, foundRepo5
|
|
}
|
|
|
|
t.Run("all access token", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
allToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
|
|
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos").AddTokenAuth(allToken)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &repos)
|
|
foundRepo21, foundRepo3, foundRepo5 := find()
|
|
|
|
assert.True(t, foundRepo21) // public org3/repo21
|
|
assert.True(t, foundRepo3) // private org3/repo3
|
|
assert.True(t, foundRepo5) // private org3/repo5, used in fine-grain testing, included as baseline
|
|
})
|
|
|
|
t.Run("public-only access token", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopePublicOnly, auth_model.AccessTokenScopeReadOrganization)
|
|
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos").AddTokenAuth(publicOnlyToken)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &repos)
|
|
foundRepo21, foundRepo3, foundRepo5 := find()
|
|
|
|
assert.True(t, foundRepo21) // public org3/repo21
|
|
assert.False(t, foundRepo3) // private org3/repo3
|
|
assert.False(t, foundRepo5) // private org3/repo5
|
|
})
|
|
|
|
t.Run("specific repo access token", func(t *testing.T) {
|
|
defer tests.PrintCurrentTest(t)()
|
|
|
|
repo2OnlyToken := createFineGrainedRepoAccessToken(t, "user2",
|
|
[]auth_model.AccessTokenScope{auth_model.AccessTokenScopeReadOrganization},
|
|
[]int64{3},
|
|
)
|
|
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos").AddTokenAuth(repo2OnlyToken)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &repos)
|
|
foundRepo21, foundRepo3, foundRepo5 := find()
|
|
|
|
assert.True(t, foundRepo21) // public org3/repo21, allowed as it's public and read-access only
|
|
assert.True(t, foundRepo3) // private org3/repo3, allowed inside fine-grain
|
|
assert.False(t, foundRepo5) // private org3/repo5, denied outside fine-grain
|
|
})
|
|
}
|
|
|
|
func TestAPIGetTeamRepo(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
|
|
teamRepo := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 24})
|
|
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5})
|
|
|
|
var results api.Repository
|
|
|
|
token := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadOrganization)
|
|
req := NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/", team.ID, teamRepo.FullName()).
|
|
AddTokenAuth(token)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &results)
|
|
assert.Equal(t, "big_test_private_4", teamRepo.Name)
|
|
|
|
// no access if not organization member
|
|
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
|
token5 := getUserToken(t, user5.Name, auth_model.AccessTokenScopeReadOrganization)
|
|
|
|
req = NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/", team.ID, teamRepo.FullName()).
|
|
AddTokenAuth(token5)
|
|
MakeRequest(t, req, http.StatusNotFound)
|
|
}
|
|
|
|
func TestAPIGetTeamRepoAccessTokenResources(t *testing.T) {
|
|
defer unittest.OverrideFixtures("tests/integration/fixtures/TestAPIGetTeamRepoAccessTokenResources")()
|
|
defer tests.PrepareTestEnv(t)()
|
|
|
|
// Test cases org3/repo21 (public), org3/repo3 (private), org3/repo5 (private) --
|
|
// TestAPIGetTeamRepoAccessTokenResources fixtures create a team w/ ID=26 that contains all three repos.
|
|
session := loginUser(t, "user2")
|
|
|
|
var repo api.Repository
|
|
|
|
t.Run("all access token", func(t *testing.T) {
|
|
allToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
|
|
|
|
t.Run("allowed public repo21", func(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos/org3/repo21").AddTokenAuth(allToken)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &repo)
|
|
assert.False(t, repo.Private)
|
|
})
|
|
t.Run("allowed private repo3", func(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos/org3/repo3").AddTokenAuth(allToken)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &repo)
|
|
assert.True(t, repo.Private)
|
|
})
|
|
// org3/repo5 is a second repo used in fine-grain testing below, so we include it in other tests as a baseline
|
|
t.Run("allowed private repo5", func(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos/org3/repo5").AddTokenAuth(allToken)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &repo)
|
|
assert.True(t, repo.Private)
|
|
})
|
|
})
|
|
|
|
t.Run("public-only access token", func(t *testing.T) {
|
|
publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopePublicOnly, auth_model.AccessTokenScopeReadOrganization)
|
|
|
|
t.Run("allowed public repo21", func(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos/org3/repo21").AddTokenAuth(publicOnlyToken)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &repo)
|
|
assert.False(t, repo.Private)
|
|
})
|
|
t.Run("denied private repo3", func(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos/org3/repo3").AddTokenAuth(publicOnlyToken)
|
|
MakeRequest(t, req, http.StatusNotFound)
|
|
})
|
|
t.Run("denied private repo5", func(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos/org3/repo5").AddTokenAuth(publicOnlyToken)
|
|
MakeRequest(t, req, http.StatusNotFound)
|
|
})
|
|
})
|
|
|
|
t.Run("specific repo access token", func(t *testing.T) {
|
|
repo2OnlyToken := createFineGrainedRepoAccessToken(t, "user2",
|
|
[]auth_model.AccessTokenScope{auth_model.AccessTokenScopeReadOrganization},
|
|
[]int64{3},
|
|
)
|
|
|
|
t.Run("allowed public repo21", func(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos/org3/repo21").AddTokenAuth(repo2OnlyToken)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &repo)
|
|
assert.False(t, repo.Private)
|
|
})
|
|
t.Run("allowed inside fine-grain repo3", func(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos/org3/repo3").AddTokenAuth(repo2OnlyToken)
|
|
resp := MakeRequest(t, req, http.StatusOK)
|
|
DecodeJSON(t, resp, &repo)
|
|
assert.True(t, repo.Private)
|
|
})
|
|
t.Run("denied private outside fine-grain repo5", func(t *testing.T) {
|
|
req := NewRequest(t, "GET", "/api/v1/teams/26/repos/org3/repo5").AddTokenAuth(repo2OnlyToken)
|
|
MakeRequest(t, req, http.StatusNotFound)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestAPIAddMemberDirectly(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
defer test.MockVariableValue(&setting.Service.AddMembersByInvitations, false)()
|
|
token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteOrganization)
|
|
|
|
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2})
|
|
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
|
|
|
req := NewRequestf(t, "PUT", "/api/v1/teams/%d/members/%s", team.ID, user5.Name).
|
|
AddTokenAuth(token)
|
|
MakeRequest(t, req, http.StatusNoContent)
|
|
|
|
isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user5.ID)
|
|
require.NoError(t, err)
|
|
assert.True(t, isMember)
|
|
}
|
|
|
|
func TestAPIAddMemberGeneratesInvite(t *testing.T) {
|
|
defer tests.PrepareTestEnv(t)()
|
|
defer test.MockVariableValue(&setting.Service.AddMembersByInvitations, true)()
|
|
|
|
token := getUserToken(t, "user1", auth_model.AccessTokenScopeWriteOrganization)
|
|
|
|
team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2})
|
|
user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
|
|
|
|
req := NewRequestf(t, "PUT", "/api/v1/teams/%d/members/%s", team.ID, user5.Name).
|
|
AddTokenAuth(token)
|
|
MakeRequest(t, req, http.StatusNoContent)
|
|
|
|
isMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, user5.ID)
|
|
require.NoError(t, err)
|
|
assert.False(t, isMember)
|
|
unittest.AssertExistsAndLoadBean(t, &organization.TeamInvite{TeamID: team.ID, InviterID: 1, InvitedID: optional.Some(user5.ID)})
|
|
}
|