You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

repository.go 9.0KB

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