code.gitea.io/gitea@v1.21.7/services/convert/repository.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package convert
     5  
     6  import (
     7  	"context"
     8  	"time"
     9  
    10  	"code.gitea.io/gitea/models"
    11  	"code.gitea.io/gitea/models/perm"
    12  	access_model "code.gitea.io/gitea/models/perm/access"
    13  	repo_model "code.gitea.io/gitea/models/repo"
    14  	unit_model "code.gitea.io/gitea/models/unit"
    15  	"code.gitea.io/gitea/modules/log"
    16  	api "code.gitea.io/gitea/modules/structs"
    17  )
    18  
    19  // ToRepo converts a Repository to api.Repository
    20  func ToRepo(ctx context.Context, repo *repo_model.Repository, permissionInRepo access_model.Permission) *api.Repository {
    21  	return innerToRepo(ctx, repo, permissionInRepo, false)
    22  }
    23  
    24  func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInRepo access_model.Permission, isParent bool) *api.Repository {
    25  	var parent *api.Repository
    26  
    27  	if permissionInRepo.Units == nil && permissionInRepo.UnitsMode == nil {
    28  		// If Units and UnitsMode are both nil, it means that it's a hard coded permission,
    29  		// like access_model.Permission{AccessMode: perm.AccessModeAdmin}.
    30  		// So we need to load units for the repo, or UnitAccessMode will always return perm.AccessModeNone.
    31  		_ = repo.LoadUnits(ctx) // the error is not important, so ignore it
    32  		permissionInRepo.Units = repo.Units
    33  	}
    34  
    35  	cloneLink := repo.CloneLink()
    36  	permission := &api.Permission{
    37  		Admin: permissionInRepo.AccessMode >= perm.AccessModeAdmin,
    38  		Push:  permissionInRepo.UnitAccessMode(unit_model.TypeCode) >= perm.AccessModeWrite,
    39  		Pull:  permissionInRepo.UnitAccessMode(unit_model.TypeCode) >= perm.AccessModeRead,
    40  	}
    41  	if !isParent {
    42  		err := repo.GetBaseRepo(ctx)
    43  		if err != nil {
    44  			return nil
    45  		}
    46  		if repo.BaseRepo != nil {
    47  			// FIXME: The permission of the parent repo is not correct.
    48  			//        It's the permission of the current repo, so it's probably different from the parent repo.
    49  			//        But there isn't a good way to get the permission of the parent repo, because the doer is not passed in.
    50  			//        Use the permission of the current repo to keep the behavior consistent with the old API.
    51  			//        Maybe the right way is setting the permission of the parent repo to nil, empty is better than wrong.
    52  			parent = innerToRepo(ctx, repo.BaseRepo, permissionInRepo, true)
    53  		}
    54  	}
    55  
    56  	// check enabled/disabled units
    57  	hasIssues := false
    58  	var externalTracker *api.ExternalTracker
    59  	var internalTracker *api.InternalTracker
    60  	if unit, err := repo.GetUnit(ctx, unit_model.TypeIssues); err == nil {
    61  		config := unit.IssuesConfig()
    62  		hasIssues = true
    63  		internalTracker = &api.InternalTracker{
    64  			EnableTimeTracker:                config.EnableTimetracker,
    65  			AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime,
    66  			EnableIssueDependencies:          config.EnableDependencies,
    67  		}
    68  	} else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalTracker); err == nil {
    69  		config := unit.ExternalTrackerConfig()
    70  		hasIssues = true
    71  		externalTracker = &api.ExternalTracker{
    72  			ExternalTrackerURL:           config.ExternalTrackerURL,
    73  			ExternalTrackerFormat:        config.ExternalTrackerFormat,
    74  			ExternalTrackerStyle:         config.ExternalTrackerStyle,
    75  			ExternalTrackerRegexpPattern: config.ExternalTrackerRegexpPattern,
    76  		}
    77  	}
    78  	hasWiki := false
    79  	var externalWiki *api.ExternalWiki
    80  	if _, err := repo.GetUnit(ctx, unit_model.TypeWiki); err == nil {
    81  		hasWiki = true
    82  	} else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalWiki); err == nil {
    83  		hasWiki = true
    84  		config := unit.ExternalWikiConfig()
    85  		externalWiki = &api.ExternalWiki{
    86  			ExternalWikiURL: config.ExternalWikiURL,
    87  		}
    88  	}
    89  	hasPullRequests := false
    90  	ignoreWhitespaceConflicts := false
    91  	allowMerge := false
    92  	allowRebase := false
    93  	allowRebaseMerge := false
    94  	allowSquash := false
    95  	allowRebaseUpdate := false
    96  	defaultDeleteBranchAfterMerge := false
    97  	defaultMergeStyle := repo_model.MergeStyleMerge
    98  	defaultAllowMaintainerEdit := false
    99  	if unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests); err == nil {
   100  		config := unit.PullRequestsConfig()
   101  		hasPullRequests = true
   102  		ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts
   103  		allowMerge = config.AllowMerge
   104  		allowRebase = config.AllowRebase
   105  		allowRebaseMerge = config.AllowRebaseMerge
   106  		allowSquash = config.AllowSquash
   107  		allowRebaseUpdate = config.AllowRebaseUpdate
   108  		defaultDeleteBranchAfterMerge = config.DefaultDeleteBranchAfterMerge
   109  		defaultMergeStyle = config.GetDefaultMergeStyle()
   110  		defaultAllowMaintainerEdit = config.DefaultAllowMaintainerEdit
   111  	}
   112  	hasProjects := false
   113  	if _, err := repo.GetUnit(ctx, unit_model.TypeProjects); err == nil {
   114  		hasProjects = true
   115  	}
   116  
   117  	hasReleases := false
   118  	if _, err := repo.GetUnit(ctx, unit_model.TypeReleases); err == nil {
   119  		hasReleases = true
   120  	}
   121  
   122  	hasPackages := false
   123  	if _, err := repo.GetUnit(ctx, unit_model.TypePackages); err == nil {
   124  		hasPackages = true
   125  	}
   126  
   127  	hasActions := false
   128  	if _, err := repo.GetUnit(ctx, unit_model.TypeActions); err == nil {
   129  		hasActions = true
   130  	}
   131  
   132  	if err := repo.LoadOwner(ctx); err != nil {
   133  		return nil
   134  	}
   135  
   136  	numReleases, _ := repo_model.GetReleaseCountByRepoID(ctx, repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false})
   137  
   138  	mirrorInterval := ""
   139  	var mirrorUpdated time.Time
   140  	if repo.IsMirror {
   141  		pullMirror, err := repo_model.GetMirrorByRepoID(ctx, repo.ID)
   142  		if err == nil {
   143  			mirrorInterval = pullMirror.Interval.String()
   144  			mirrorUpdated = pullMirror.UpdatedUnix.AsTime()
   145  		}
   146  	}
   147  
   148  	var transfer *api.RepoTransfer
   149  	if repo.Status == repo_model.RepositoryPendingTransfer {
   150  		t, err := models.GetPendingRepositoryTransfer(ctx, repo)
   151  		if err != nil && !models.IsErrNoPendingTransfer(err) {
   152  			log.Warn("GetPendingRepositoryTransfer: %v", err)
   153  		} else {
   154  			if err := t.LoadAttributes(ctx); err != nil {
   155  				log.Warn("LoadAttributes of RepoTransfer: %v", err)
   156  			} else {
   157  				transfer = ToRepoTransfer(ctx, t)
   158  			}
   159  		}
   160  	}
   161  
   162  	var language string
   163  	if repo.PrimaryLanguage != nil {
   164  		language = repo.PrimaryLanguage.Language
   165  	}
   166  
   167  	repoAPIURL := repo.APIURL()
   168  
   169  	return &api.Repository{
   170  		ID:                            repo.ID,
   171  		Owner:                         ToUserWithAccessMode(ctx, repo.Owner, permissionInRepo.AccessMode),
   172  		Name:                          repo.Name,
   173  		FullName:                      repo.FullName(),
   174  		Description:                   repo.Description,
   175  		Private:                       repo.IsPrivate,
   176  		Template:                      repo.IsTemplate,
   177  		Empty:                         repo.IsEmpty,
   178  		Archived:                      repo.IsArchived,
   179  		Size:                          int(repo.Size / 1024),
   180  		Fork:                          repo.IsFork,
   181  		Parent:                        parent,
   182  		Mirror:                        repo.IsMirror,
   183  		HTMLURL:                       repo.HTMLURL(),
   184  		URL:                           repoAPIURL,
   185  		SSHURL:                        cloneLink.SSH,
   186  		CloneURL:                      cloneLink.HTTPS,
   187  		OriginalURL:                   repo.SanitizedOriginalURL(),
   188  		Website:                       repo.Website,
   189  		Language:                      language,
   190  		LanguagesURL:                  repoAPIURL + "/languages",
   191  		Stars:                         repo.NumStars,
   192  		Forks:                         repo.NumForks,
   193  		Watchers:                      repo.NumWatches,
   194  		OpenIssues:                    repo.NumOpenIssues,
   195  		OpenPulls:                     repo.NumOpenPulls,
   196  		Releases:                      int(numReleases),
   197  		DefaultBranch:                 repo.DefaultBranch,
   198  		Created:                       repo.CreatedUnix.AsTime(),
   199  		Updated:                       repo.UpdatedUnix.AsTime(),
   200  		ArchivedAt:                    repo.ArchivedUnix.AsTime(),
   201  		Permissions:                   permission,
   202  		HasIssues:                     hasIssues,
   203  		ExternalTracker:               externalTracker,
   204  		InternalTracker:               internalTracker,
   205  		HasWiki:                       hasWiki,
   206  		HasProjects:                   hasProjects,
   207  		HasReleases:                   hasReleases,
   208  		HasPackages:                   hasPackages,
   209  		HasActions:                    hasActions,
   210  		ExternalWiki:                  externalWiki,
   211  		HasPullRequests:               hasPullRequests,
   212  		IgnoreWhitespaceConflicts:     ignoreWhitespaceConflicts,
   213  		AllowMerge:                    allowMerge,
   214  		AllowRebase:                   allowRebase,
   215  		AllowRebaseMerge:              allowRebaseMerge,
   216  		AllowSquash:                   allowSquash,
   217  		AllowRebaseUpdate:             allowRebaseUpdate,
   218  		DefaultDeleteBranchAfterMerge: defaultDeleteBranchAfterMerge,
   219  		DefaultMergeStyle:             string(defaultMergeStyle),
   220  		DefaultAllowMaintainerEdit:    defaultAllowMaintainerEdit,
   221  		AvatarURL:                     repo.AvatarLink(ctx),
   222  		Internal:                      !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
   223  		MirrorInterval:                mirrorInterval,
   224  		MirrorUpdated:                 mirrorUpdated,
   225  		RepoTransfer:                  transfer,
   226  	}
   227  }
   228  
   229  // ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer
   230  func ToRepoTransfer(ctx context.Context, t *models.RepoTransfer) *api.RepoTransfer {
   231  	teams, _ := ToTeams(ctx, t.Teams, false)
   232  
   233  	return &api.RepoTransfer{
   234  		Doer:      ToUser(ctx, t.Doer, nil),
   235  		Recipient: ToUser(ctx, t.Recipient, nil),
   236  		Teams:     teams,
   237  	}
   238  }