mirror of
https://gitea.com/gitea/tea.git
synced 2026-10-26 11:01:25 +01:00
fix(team): merge team edit --unit into the current unit policy
Gitea replaces a team's whole unit policy on edit, so `tea team edit 5 --unit repo.wiki=write` revoked code, issue and pull request access. team edit now merges --unit into the current policy; --unit-replace keeps the old replacing behavior. Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
4 files changed
+83
-8
No files matched your search
@@ -6,6 +6,7 @@ package services
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"maps"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
@@ -47,6 +48,8 @@ type TeamOptions struct {
|
||||
CanCreateRepo *bool `json:"can_create_org_repo,omitempty"`
|
||||
AllRepositories *bool `json:"includes_all_repositories,omitempty"`
|
||||
Units map[string]string `json:"units_map,omitempty"`
|
||||
// ReplaceUnits makes Edit replace the unit policy with Units instead of merging Units into it.
|
||||
ReplaceUnits bool `json:"-"`
|
||||
}
|
||||
|
||||
// Teams implements team, member and repository access operations.
|
||||
@@ -101,19 +104,28 @@ func (s Teams) Create(ctx context.Context, org string, opts TeamOptions) (Team,
|
||||
return teamFrom(team), nil
|
||||
}
|
||||
|
||||
// Edit preserves unit permissions when changing access to all repositories.
|
||||
// Edit merges Units into the current unit policy unless ReplaceUnits is set, and preserves unit
|
||||
// permissions when changing access to all repositories. Gitea replaces the whole policy on edit.
|
||||
func (s Teams) Edit(ctx context.Context, id int64, opts TeamOptions) (Team, error) {
|
||||
if opts.AllRepositories != nil && opts.Permission == nil {
|
||||
repositoryPolicy := opts.AllRepositories != nil && opts.Permission == nil
|
||||
if repositoryPolicy || (opts.Units != nil && !opts.ReplaceUnits) {
|
||||
current, err := s.View(ctx, id)
|
||||
if err != nil {
|
||||
return Team{}, err
|
||||
}
|
||||
if current.Permission == "owner" {
|
||||
return Team{}, &CapabilityError{Feature: "owner-team repository policy editing", Reason: "owner teams already manage all organization repositories"}
|
||||
if repositoryPolicy {
|
||||
if current.Permission == "owner" {
|
||||
return Team{}, &CapabilityError{Feature: "owner-team repository policy editing", Reason: "owner teams already manage all organization repositories"}
|
||||
}
|
||||
opts.Permission = ¤t.Permission
|
||||
}
|
||||
opts.Permission = ¤t.Permission
|
||||
if opts.Units == nil {
|
||||
switch {
|
||||
case opts.Units == nil:
|
||||
opts.Units = current.Units
|
||||
case !opts.ReplaceUnits:
|
||||
units := maps.Clone(current.Units)
|
||||
maps.Copy(units, opts.Units)
|
||||
opts.Units = units
|
||||
}
|
||||
}
|
||||
var team gitea.Team
|
||||
|
||||
@@ -37,6 +37,34 @@ func TestTeamRepositoryPolicyPreservesUnitPermissions(t *testing.T) {
|
||||
require.Equal(t, 1, mutations)
|
||||
}
|
||||
|
||||
func TestTeamEditMergesUnitsUnlessReplaced(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
replace bool
|
||||
reads int
|
||||
want map[string]any
|
||||
}{
|
||||
{false, 1, map[string]any{"repo.code": "write", "repo.issues": "read", "repo.wiki": "write"}},
|
||||
{true, 0, map[string]any{"repo.wiki": "write"}},
|
||||
} {
|
||||
reads := 0
|
||||
client := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, "/api/v1/teams/5", r.URL.Path)
|
||||
if r.Method == http.MethodGet {
|
||||
reads++
|
||||
_, _ = w.Write([]byte(`{"id":5,"permission":"write","units_map":{"repo.code":"write","repo.issues":"read","repo.wiki":"none"}}`))
|
||||
return
|
||||
}
|
||||
body := requestJSON(t, r)
|
||||
require.Equal(t, test.want, body["units_map"])
|
||||
require.NotContains(t, body, "permission")
|
||||
_, _ = w.Write([]byte(`{"id":5}`))
|
||||
}))
|
||||
_, err := (Teams{Client: client}).Edit(context.Background(), 5, TeamOptions{Units: map[string]string{"repo.wiki": "write"}, ReplaceUnits: test.replace})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, test.reads, reads)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTeamCreateSendsPermissionAndUnits(t *testing.T) {
|
||||
client := newTestClient(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
require.Equal(t, http.MethodPost, r.Method)
|
||||
|
||||
Reference in new issue
Block a user