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