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 }