gitea源码

repository.go 10KB

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