code.gitea.io/gitea@v1.22.3/tests/integration/api_team_test.go (about)

     1  // Copyright 2017 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package integration
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"sort"
    10  	"testing"
    11  
    12  	auth_model "code.gitea.io/gitea/models/auth"
    13  	"code.gitea.io/gitea/models/db"
    14  	"code.gitea.io/gitea/models/organization"
    15  	"code.gitea.io/gitea/models/perm"
    16  	"code.gitea.io/gitea/models/repo"
    17  	"code.gitea.io/gitea/models/unit"
    18  	"code.gitea.io/gitea/models/unittest"
    19  	user_model "code.gitea.io/gitea/models/user"
    20  	api "code.gitea.io/gitea/modules/structs"
    21  	"code.gitea.io/gitea/services/convert"
    22  	"code.gitea.io/gitea/tests"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  func TestAPITeam(t *testing.T) {
    28  	defer tests.PrepareTestEnv(t)()
    29  
    30  	teamUser := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 1})
    31  	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamUser.TeamID})
    32  	org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: teamUser.OrgID})
    33  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID})
    34  
    35  	session := loginUser(t, user.Name)
    36  	token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
    37  	req := NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID).
    38  		AddTokenAuth(token)
    39  	resp := MakeRequest(t, req, http.StatusOK)
    40  
    41  	var apiTeam api.Team
    42  	DecodeJSON(t, resp, &apiTeam)
    43  	assert.EqualValues(t, team.ID, apiTeam.ID)
    44  	assert.Equal(t, team.Name, apiTeam.Name)
    45  	assert.EqualValues(t, convert.ToOrganization(db.DefaultContext, org), apiTeam.Organization)
    46  
    47  	// non team member user will not access the teams details
    48  	teamUser2 := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 3})
    49  	user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser2.UID})
    50  
    51  	session = loginUser(t, user2.Name)
    52  	token = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadOrganization)
    53  	req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID).
    54  		AddTokenAuth(token)
    55  	_ = MakeRequest(t, req, http.StatusForbidden)
    56  
    57  	req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID)
    58  	_ = MakeRequest(t, req, http.StatusUnauthorized)
    59  
    60  	// Get an admin user able to create, update and delete teams.
    61  	user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
    62  	session = loginUser(t, user.Name)
    63  	token = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization)
    64  
    65  	org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 6})
    66  
    67  	// Create team.
    68  	teamToCreate := &api.CreateTeamOption{
    69  		Name:                    "team1",
    70  		Description:             "team one",
    71  		IncludesAllRepositories: true,
    72  		Permission:              "write",
    73  		Units:                   []string{"repo.code", "repo.issues"},
    74  	}
    75  	req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", org.Name), teamToCreate).
    76  		AddTokenAuth(token)
    77  	resp = MakeRequest(t, req, http.StatusCreated)
    78  	apiTeam = api.Team{}
    79  	DecodeJSON(t, resp, &apiTeam)
    80  	checkTeamResponse(t, "CreateTeam1", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
    81  		teamToCreate.Permission, teamToCreate.Units, nil)
    82  	checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
    83  		teamToCreate.Permission, teamToCreate.Units, nil)
    84  	teamID := apiTeam.ID
    85  
    86  	// Edit team.
    87  	editDescription := "team 1"
    88  	editFalse := false
    89  	teamToEdit := &api.EditTeamOption{
    90  		Name:                    "teamone",
    91  		Description:             &editDescription,
    92  		Permission:              "admin",
    93  		IncludesAllRepositories: &editFalse,
    94  		Units:                   []string{"repo.code", "repo.pulls", "repo.releases"},
    95  	}
    96  
    97  	req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEdit).
    98  		AddTokenAuth(token)
    99  	resp = MakeRequest(t, req, http.StatusOK)
   100  	apiTeam = api.Team{}
   101  	DecodeJSON(t, resp, &apiTeam)
   102  	checkTeamResponse(t, "EditTeam1", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
   103  		teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
   104  	checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
   105  		teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
   106  
   107  	// Edit team Description only
   108  	editDescription = "first team"
   109  	teamToEditDesc := api.EditTeamOption{Description: &editDescription}
   110  	req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEditDesc).
   111  		AddTokenAuth(token)
   112  	resp = MakeRequest(t, req, http.StatusOK)
   113  	apiTeam = api.Team{}
   114  	DecodeJSON(t, resp, &apiTeam)
   115  	checkTeamResponse(t, "EditTeam1_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
   116  		teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
   117  	checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
   118  		teamToEdit.Permission, unit.AllUnitKeyNames(), nil)
   119  
   120  	// Read team.
   121  	teamRead := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
   122  	assert.NoError(t, teamRead.LoadUnits(db.DefaultContext))
   123  	req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamID).
   124  		AddTokenAuth(token)
   125  	resp = MakeRequest(t, req, http.StatusOK)
   126  	apiTeam = api.Team{}
   127  	DecodeJSON(t, resp, &apiTeam)
   128  	checkTeamResponse(t, "ReadTeam1", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories,
   129  		teamRead.AccessMode.ToString(), teamRead.GetUnitNames(), teamRead.GetUnitsMap())
   130  
   131  	// Delete team.
   132  	req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID).
   133  		AddTokenAuth(token)
   134  	MakeRequest(t, req, http.StatusNoContent)
   135  	unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
   136  
   137  	// create team again via UnitsMap
   138  	// Create team.
   139  	teamToCreate = &api.CreateTeamOption{
   140  		Name:                    "team2",
   141  		Description:             "team two",
   142  		IncludesAllRepositories: true,
   143  		Permission:              "write",
   144  		UnitsMap:                map[string]string{"repo.code": "read", "repo.issues": "write", "repo.wiki": "none"},
   145  	}
   146  	req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", org.Name), teamToCreate).
   147  		AddTokenAuth(token)
   148  	resp = MakeRequest(t, req, http.StatusCreated)
   149  	apiTeam = api.Team{}
   150  	DecodeJSON(t, resp, &apiTeam)
   151  	checkTeamResponse(t, "CreateTeam2", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
   152  		"read", nil, teamToCreate.UnitsMap)
   153  	checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories,
   154  		"read", nil, teamToCreate.UnitsMap)
   155  	teamID = apiTeam.ID
   156  
   157  	// Edit team.
   158  	editDescription = "team 1"
   159  	editFalse = false
   160  	teamToEdit = &api.EditTeamOption{
   161  		Name:                    "teamtwo",
   162  		Description:             &editDescription,
   163  		Permission:              "write",
   164  		IncludesAllRepositories: &editFalse,
   165  		UnitsMap:                map[string]string{"repo.code": "read", "repo.pulls": "read", "repo.releases": "write"},
   166  	}
   167  
   168  	req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEdit).
   169  		AddTokenAuth(token)
   170  	resp = MakeRequest(t, req, http.StatusOK)
   171  	apiTeam = api.Team{}
   172  	DecodeJSON(t, resp, &apiTeam)
   173  	checkTeamResponse(t, "EditTeam2", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
   174  		"read", nil, teamToEdit.UnitsMap)
   175  	checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories,
   176  		"read", nil, teamToEdit.UnitsMap)
   177  
   178  	// Edit team Description only
   179  	editDescription = "second team"
   180  	teamToEditDesc = api.EditTeamOption{Description: &editDescription}
   181  	req = NewRequestWithJSON(t, "PATCH", fmt.Sprintf("/api/v1/teams/%d", teamID), teamToEditDesc).
   182  		AddTokenAuth(token)
   183  	resp = MakeRequest(t, req, http.StatusOK)
   184  	apiTeam = api.Team{}
   185  	DecodeJSON(t, resp, &apiTeam)
   186  	checkTeamResponse(t, "EditTeam2_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
   187  		"read", nil, teamToEdit.UnitsMap)
   188  	checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories,
   189  		"read", nil, teamToEdit.UnitsMap)
   190  
   191  	// Read team.
   192  	teamRead = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID})
   193  	req = NewRequestf(t, "GET", "/api/v1/teams/%d", teamID).
   194  		AddTokenAuth(token)
   195  	resp = MakeRequest(t, req, http.StatusOK)
   196  	apiTeam = api.Team{}
   197  	DecodeJSON(t, resp, &apiTeam)
   198  	assert.NoError(t, teamRead.LoadUnits(db.DefaultContext))
   199  	checkTeamResponse(t, "ReadTeam2", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories,
   200  		teamRead.AccessMode.ToString(), teamRead.GetUnitNames(), teamRead.GetUnitsMap())
   201  
   202  	// Delete team.
   203  	req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID).
   204  		AddTokenAuth(token)
   205  	MakeRequest(t, req, http.StatusNoContent)
   206  	unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
   207  
   208  	// Create admin team
   209  	teamToCreate = &api.CreateTeamOption{
   210  		Name:                    "teamadmin",
   211  		Description:             "team admin",
   212  		IncludesAllRepositories: true,
   213  		Permission:              "admin",
   214  	}
   215  	req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/orgs/%s/teams", org.Name), teamToCreate).
   216  		AddTokenAuth(token)
   217  	resp = MakeRequest(t, req, http.StatusCreated)
   218  	apiTeam = api.Team{}
   219  	DecodeJSON(t, resp, &apiTeam)
   220  	for _, ut := range unit.AllRepoUnitTypes {
   221  		up := perm.AccessModeAdmin
   222  		if ut == unit.TypeExternalTracker || ut == unit.TypeExternalWiki {
   223  			up = perm.AccessModeRead
   224  		}
   225  		unittest.AssertExistsAndLoadBean(t, &organization.TeamUnit{
   226  			OrgID:      org.ID,
   227  			TeamID:     apiTeam.ID,
   228  			Type:       ut,
   229  			AccessMode: up,
   230  		})
   231  	}
   232  	teamID = apiTeam.ID
   233  
   234  	// Delete team.
   235  	req = NewRequestf(t, "DELETE", "/api/v1/teams/%d", teamID).
   236  		AddTokenAuth(token)
   237  	MakeRequest(t, req, http.StatusNoContent)
   238  	unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID})
   239  }
   240  
   241  func checkTeamResponse(t *testing.T, testName string, apiTeam *api.Team, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
   242  	t.Run(testName, func(t *testing.T) {
   243  		assert.Equal(t, name, apiTeam.Name, "name")
   244  		assert.Equal(t, description, apiTeam.Description, "description")
   245  		assert.Equal(t, includesAllRepositories, apiTeam.IncludesAllRepositories, "includesAllRepositories")
   246  		assert.Equal(t, permission, apiTeam.Permission, "permission")
   247  		if units != nil {
   248  			sort.StringSlice(units).Sort()
   249  			sort.StringSlice(apiTeam.Units).Sort()
   250  			assert.EqualValues(t, units, apiTeam.Units, "units")
   251  		}
   252  		if unitsMap != nil {
   253  			assert.EqualValues(t, unitsMap, apiTeam.UnitsMap, "unitsMap")
   254  		}
   255  	})
   256  }
   257  
   258  func checkTeamBean(t *testing.T, id int64, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) {
   259  	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: id})
   260  	assert.NoError(t, team.LoadUnits(db.DefaultContext), "LoadUnits")
   261  	apiTeam, err := convert.ToTeam(db.DefaultContext, team)
   262  	assert.NoError(t, err)
   263  	checkTeamResponse(t, fmt.Sprintf("checkTeamBean/%s_%s", name, description), apiTeam, name, description, includesAllRepositories, permission, units, unitsMap)
   264  }
   265  
   266  type TeamSearchResults struct {
   267  	OK   bool        `json:"ok"`
   268  	Data []*api.Team `json:"data"`
   269  }
   270  
   271  func TestAPITeamSearch(t *testing.T) {
   272  	defer tests.PrepareTestEnv(t)()
   273  
   274  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
   275  	org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17})
   276  
   277  	var results TeamSearchResults
   278  
   279  	token := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadOrganization)
   280  	req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "_team").
   281  		AddTokenAuth(token)
   282  	resp := MakeRequest(t, req, http.StatusOK)
   283  	DecodeJSON(t, resp, &results)
   284  	assert.NotEmpty(t, results.Data)
   285  	assert.Len(t, results.Data, 1)
   286  	assert.Equal(t, "test_team", results.Data[0].Name)
   287  
   288  	// no access if not organization member
   289  	user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
   290  	token5 := getUserToken(t, user5.Name, auth_model.AccessTokenScopeReadOrganization)
   291  
   292  	req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "team").
   293  		AddTokenAuth(token5)
   294  	MakeRequest(t, req, http.StatusForbidden)
   295  }
   296  
   297  func TestAPIGetTeamRepo(t *testing.T) {
   298  	defer tests.PrepareTestEnv(t)()
   299  
   300  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15})
   301  	teamRepo := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 24})
   302  	team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5})
   303  
   304  	var results api.Repository
   305  
   306  	token := getUserToken(t, user.Name, auth_model.AccessTokenScopeReadOrganization)
   307  	req := NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/", team.ID, teamRepo.FullName()).
   308  		AddTokenAuth(token)
   309  	resp := MakeRequest(t, req, http.StatusOK)
   310  	DecodeJSON(t, resp, &results)
   311  	assert.Equal(t, "big_test_private_4", teamRepo.Name)
   312  
   313  	// no access if not organization member
   314  	user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
   315  	token5 := getUserToken(t, user5.Name, auth_model.AccessTokenScopeReadOrganization)
   316  
   317  	req = NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/", team.ID, teamRepo.FullName()).
   318  		AddTokenAuth(token5)
   319  	MakeRequest(t, req, http.StatusNotFound)
   320  }