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.6KB

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