code.gitea.io/gitea@v1.21.7/models/organization/team.go (about)

     1  // Copyright 2018 The Gitea Authors. All rights reserved.
     2  // Copyright 2016 The Gogs Authors. All rights reserved.
     3  // SPDX-License-Identifier: MIT
     4  
     5  package organization
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"strings"
    11  
    12  	"code.gitea.io/gitea/models/db"
    13  	"code.gitea.io/gitea/models/perm"
    14  	repo_model "code.gitea.io/gitea/models/repo"
    15  	"code.gitea.io/gitea/models/unit"
    16  	user_model "code.gitea.io/gitea/models/user"
    17  	"code.gitea.io/gitea/modules/log"
    18  	"code.gitea.io/gitea/modules/util"
    19  )
    20  
    21  // ___________
    22  // \__    ___/___ _____    _____
    23  //   |    |_/ __ \\__  \  /     \
    24  //   |    |\  ___/ / __ \|  Y Y  \
    25  //   |____| \___  >____  /__|_|  /
    26  //              \/     \/      \/
    27  
    28  // ErrTeamAlreadyExist represents a "TeamAlreadyExist" kind of error.
    29  type ErrTeamAlreadyExist struct {
    30  	OrgID int64
    31  	Name  string
    32  }
    33  
    34  // IsErrTeamAlreadyExist checks if an error is a ErrTeamAlreadyExist.
    35  func IsErrTeamAlreadyExist(err error) bool {
    36  	_, ok := err.(ErrTeamAlreadyExist)
    37  	return ok
    38  }
    39  
    40  func (err ErrTeamAlreadyExist) Error() string {
    41  	return fmt.Sprintf("team already exists [org_id: %d, name: %s]", err.OrgID, err.Name)
    42  }
    43  
    44  func (err ErrTeamAlreadyExist) Unwrap() error {
    45  	return util.ErrAlreadyExist
    46  }
    47  
    48  // ErrTeamNotExist represents a "TeamNotExist" error
    49  type ErrTeamNotExist struct {
    50  	OrgID  int64
    51  	TeamID int64
    52  	Name   string
    53  }
    54  
    55  // IsErrTeamNotExist checks if an error is a ErrTeamNotExist.
    56  func IsErrTeamNotExist(err error) bool {
    57  	_, ok := err.(ErrTeamNotExist)
    58  	return ok
    59  }
    60  
    61  func (err ErrTeamNotExist) Error() string {
    62  	return fmt.Sprintf("team does not exist [org_id %d, team_id %d, name: %s]", err.OrgID, err.TeamID, err.Name)
    63  }
    64  
    65  func (err ErrTeamNotExist) Unwrap() error {
    66  	return util.ErrNotExist
    67  }
    68  
    69  // OwnerTeamName return the owner team name
    70  const OwnerTeamName = "Owners"
    71  
    72  // Team represents a organization team.
    73  type Team struct {
    74  	ID                      int64 `xorm:"pk autoincr"`
    75  	OrgID                   int64 `xorm:"INDEX"`
    76  	LowerName               string
    77  	Name                    string
    78  	Description             string
    79  	AccessMode              perm.AccessMode          `xorm:"'authorize'"`
    80  	Repos                   []*repo_model.Repository `xorm:"-"`
    81  	Members                 []*user_model.User       `xorm:"-"`
    82  	NumRepos                int
    83  	NumMembers              int
    84  	Units                   []*TeamUnit `xorm:"-"`
    85  	IncludesAllRepositories bool        `xorm:"NOT NULL DEFAULT false"`
    86  	CanCreateOrgRepo        bool        `xorm:"NOT NULL DEFAULT false"`
    87  }
    88  
    89  func init() {
    90  	db.RegisterModel(new(Team))
    91  	db.RegisterModel(new(TeamUser))
    92  	db.RegisterModel(new(TeamRepo))
    93  	db.RegisterModel(new(TeamUnit))
    94  	db.RegisterModel(new(TeamInvite))
    95  }
    96  
    97  func (t *Team) LogString() string {
    98  	if t == nil {
    99  		return "<Team nil>"
   100  	}
   101  	return fmt.Sprintf("<Team %d:%s OrgID=%d AccessMode=%s>", t.ID, t.Name, t.OrgID, t.AccessMode.LogString())
   102  }
   103  
   104  // LoadUnits load a list of available units for a team
   105  func (t *Team) LoadUnits(ctx context.Context) (err error) {
   106  	if t.Units != nil {
   107  		return nil
   108  	}
   109  
   110  	t.Units, err = getUnitsByTeamID(ctx, t.ID)
   111  	return err
   112  }
   113  
   114  // GetUnitNames returns the team units names
   115  func (t *Team) GetUnitNames() (res []string) {
   116  	if t.AccessMode >= perm.AccessModeAdmin {
   117  		return unit.AllUnitKeyNames()
   118  	}
   119  
   120  	for _, u := range t.Units {
   121  		res = append(res, unit.Units[u.Type].NameKey)
   122  	}
   123  	return res
   124  }
   125  
   126  // GetUnitsMap returns the team units permissions
   127  func (t *Team) GetUnitsMap() map[string]string {
   128  	m := make(map[string]string)
   129  	if t.AccessMode >= perm.AccessModeAdmin {
   130  		for _, u := range unit.Units {
   131  			m[u.NameKey] = t.AccessMode.String()
   132  		}
   133  	} else {
   134  		for _, u := range t.Units {
   135  			m[u.Unit().NameKey] = u.AccessMode.String()
   136  		}
   137  	}
   138  	return m
   139  }
   140  
   141  // IsOwnerTeam returns true if team is owner team.
   142  func (t *Team) IsOwnerTeam() bool {
   143  	return t.Name == OwnerTeamName
   144  }
   145  
   146  // IsMember returns true if given user is a member of team.
   147  func (t *Team) IsMember(userID int64) bool {
   148  	isMember, err := IsTeamMember(db.DefaultContext, t.OrgID, t.ID, userID)
   149  	if err != nil {
   150  		log.Error("IsMember: %v", err)
   151  		return false
   152  	}
   153  	return isMember
   154  }
   155  
   156  // LoadRepositories returns paginated repositories in team of organization.
   157  func (t *Team) LoadRepositories(ctx context.Context) (err error) {
   158  	if t.Repos != nil {
   159  		return nil
   160  	}
   161  	t.Repos, err = GetTeamRepositories(ctx, &SearchTeamRepoOptions{
   162  		TeamID: t.ID,
   163  	})
   164  	return err
   165  }
   166  
   167  // LoadMembers returns paginated members in team of organization.
   168  func (t *Team) LoadMembers(ctx context.Context) (err error) {
   169  	t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{
   170  		TeamID: t.ID,
   171  	})
   172  	return err
   173  }
   174  
   175  // UnitEnabled returns if the team has the given unit type enabled
   176  func (t *Team) UnitEnabled(ctx context.Context, tp unit.Type) bool {
   177  	return t.UnitAccessMode(ctx, tp) > perm.AccessModeNone
   178  }
   179  
   180  // UnitAccessMode returns if the team has the given unit type enabled
   181  func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode {
   182  	if err := t.LoadUnits(ctx); err != nil {
   183  		log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error())
   184  	}
   185  
   186  	for _, unit := range t.Units {
   187  		if unit.Type == tp {
   188  			return unit.AccessMode
   189  		}
   190  	}
   191  	return perm.AccessModeNone
   192  }
   193  
   194  // IsUsableTeamName tests if a name could be as team name
   195  func IsUsableTeamName(name string) error {
   196  	switch name {
   197  	case "new":
   198  		return db.ErrNameReserved{Name: name}
   199  	default:
   200  		return nil
   201  	}
   202  }
   203  
   204  // GetTeam returns team by given team name and organization.
   205  func GetTeam(ctx context.Context, orgID int64, name string) (*Team, error) {
   206  	t := &Team{
   207  		OrgID:     orgID,
   208  		LowerName: strings.ToLower(name),
   209  	}
   210  	has, err := db.GetByBean(ctx, t)
   211  	if err != nil {
   212  		return nil, err
   213  	} else if !has {
   214  		return nil, ErrTeamNotExist{orgID, 0, name}
   215  	}
   216  	return t, nil
   217  }
   218  
   219  // GetTeamIDsByNames returns a slice of team ids corresponds to names.
   220  func GetTeamIDsByNames(orgID int64, names []string, ignoreNonExistent bool) ([]int64, error) {
   221  	ids := make([]int64, 0, len(names))
   222  	for _, name := range names {
   223  		u, err := GetTeam(db.DefaultContext, orgID, name)
   224  		if err != nil {
   225  			if ignoreNonExistent {
   226  				continue
   227  			} else {
   228  				return nil, err
   229  			}
   230  		}
   231  		ids = append(ids, u.ID)
   232  	}
   233  	return ids, nil
   234  }
   235  
   236  // GetOwnerTeam returns team by given team name and organization.
   237  func GetOwnerTeam(ctx context.Context, orgID int64) (*Team, error) {
   238  	return GetTeam(ctx, orgID, OwnerTeamName)
   239  }
   240  
   241  // GetTeamByID returns team by given ID.
   242  func GetTeamByID(ctx context.Context, teamID int64) (*Team, error) {
   243  	t := new(Team)
   244  	has, err := db.GetEngine(ctx).ID(teamID).Get(t)
   245  	if err != nil {
   246  		return nil, err
   247  	} else if !has {
   248  		return nil, ErrTeamNotExist{0, teamID, ""}
   249  	}
   250  	return t, nil
   251  }
   252  
   253  // GetTeamNamesByID returns team's lower name from a list of team ids.
   254  func GetTeamNamesByID(teamIDs []int64) ([]string, error) {
   255  	if len(teamIDs) == 0 {
   256  		return []string{}, nil
   257  	}
   258  
   259  	var teamNames []string
   260  	err := db.GetEngine(db.DefaultContext).Table("team").
   261  		Select("lower_name").
   262  		In("id", teamIDs).
   263  		Asc("name").
   264  		Find(&teamNames)
   265  
   266  	return teamNames, err
   267  }
   268  
   269  // IncrTeamRepoNum increases the number of repos for the given team by 1
   270  func IncrTeamRepoNum(ctx context.Context, teamID int64) error {
   271  	_, err := db.GetEngine(ctx).Incr("num_repos").ID(teamID).Update(new(Team))
   272  	return err
   273  }