adapters.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. package v1
  2. import (
  3. "context"
  4. "fmt"
  5. "strconv"
  6. "strings"
  7. "github.com/gogs/git-module"
  8. "gogs.io/gogs/internal/conf"
  9. "gogs.io/gogs/internal/database"
  10. "gogs.io/gogs/internal/markup"
  11. "gogs.io/gogs/internal/route/api/v1/types"
  12. )
  13. // toAllowedPageSize makes sure page size is in allowed range.
  14. func toAllowedPageSize(size int) int {
  15. if size <= 0 {
  16. size = 10
  17. } else if size > conf.API.MaxResponseItems {
  18. size = conf.API.MaxResponseItems
  19. }
  20. return size
  21. }
  22. // toUser converts a database user to an API user with the full name sanitized
  23. // for safe HTML rendering.
  24. func toUser(u *database.User) *types.User {
  25. return &types.User{
  26. ID: u.ID,
  27. UserName: u.Name,
  28. Login: u.Name,
  29. FullName: markup.Sanitize(u.FullName),
  30. Email: u.Email,
  31. AvatarURL: u.AvatarURL(),
  32. }
  33. }
  34. func toUserEmail(email *database.EmailAddress) *types.UserEmail {
  35. return &types.UserEmail{
  36. Email: email.Email,
  37. Verified: email.IsActivated,
  38. Primary: email.IsPrimary,
  39. }
  40. }
  41. func toBranch(b *database.Branch, c *git.Commit) *types.RepositoryBranch {
  42. return &types.RepositoryBranch{
  43. Name: b.Name,
  44. Commit: toPayloadCommit(c),
  45. }
  46. }
  47. func toTag(b *database.Tag, c *git.Commit) *tag {
  48. return &tag{
  49. Name: b.Name,
  50. Commit: toPayloadCommit(c),
  51. }
  52. }
  53. func toPayloadCommit(c *git.Commit) *types.WebhookPayloadCommit {
  54. authorUsername := ""
  55. author, err := database.Handle.Users().GetByEmail(context.TODO(), c.Author.Email)
  56. if err == nil {
  57. authorUsername = author.Name
  58. }
  59. committerUsername := ""
  60. committer, err := database.Handle.Users().GetByEmail(context.TODO(), c.Committer.Email)
  61. if err == nil {
  62. committerUsername = committer.Name
  63. }
  64. return &types.WebhookPayloadCommit{
  65. ID: c.ID.String(),
  66. Message: c.Message,
  67. URL: "Not implemented",
  68. Author: &types.WebhookPayloadUser{
  69. Name: c.Author.Name,
  70. Email: c.Author.Email,
  71. UserName: authorUsername,
  72. },
  73. Committer: &types.WebhookPayloadUser{
  74. Name: c.Committer.Name,
  75. Email: c.Committer.Email,
  76. UserName: committerUsername,
  77. },
  78. Timestamp: c.Author.When,
  79. }
  80. }
  81. func toUserPublicKey(apiLink string, key *database.PublicKey) *types.UserPublicKey {
  82. return &types.UserPublicKey{
  83. ID: key.ID,
  84. Key: key.Content,
  85. URL: apiLink + strconv.FormatInt(key.ID, 10),
  86. Title: key.Name,
  87. Created: key.Created,
  88. }
  89. }
  90. func toRepositoryHook(repoLink string, w *database.Webhook) *types.RepositoryHook {
  91. config := map[string]string{
  92. "url": w.URL,
  93. "content_type": w.ContentType.Name(),
  94. }
  95. if w.HookTaskType == database.SLACK {
  96. s := w.SlackMeta()
  97. config["channel"] = s.Channel
  98. config["username"] = s.Username
  99. config["icon_url"] = s.IconURL
  100. config["color"] = s.Color
  101. }
  102. return &types.RepositoryHook{
  103. ID: w.ID,
  104. Type: w.HookTaskType.Name(),
  105. URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID),
  106. Active: w.IsActive,
  107. Config: config,
  108. Events: w.EventsArray(),
  109. Updated: w.Updated,
  110. Created: w.Created,
  111. }
  112. }
  113. func toDeployKey(apiLink string, key *database.DeployKey) *types.RepositoryDeployKey {
  114. return &types.RepositoryDeployKey{
  115. ID: key.ID,
  116. Key: key.Content,
  117. URL: apiLink + strconv.FormatInt(key.ID, 10),
  118. Title: key.Name,
  119. Created: key.Created,
  120. ReadOnly: true, // All deploy keys are read-only.
  121. }
  122. }
  123. func toOrganization(org *database.User) *types.Organization {
  124. return &types.Organization{
  125. ID: org.ID,
  126. AvatarURL: org.AvatarURL(),
  127. UserName: org.Name,
  128. FullName: org.FullName,
  129. Description: org.Description,
  130. Website: org.Website,
  131. Location: org.Location,
  132. }
  133. }
  134. func toOrganizationTeam(team *database.Team) *types.OrganizationTeam {
  135. return &types.OrganizationTeam{
  136. ID: team.ID,
  137. Name: team.Name,
  138. Description: team.Description,
  139. Permission: team.Authorize.String(),
  140. }
  141. }
  142. func toIssueLabel(l *database.Label) *types.IssueLabel {
  143. return &types.IssueLabel{
  144. ID: l.ID,
  145. Name: l.Name,
  146. Color: strings.TrimLeft(l.Color, "#"),
  147. }
  148. }
  149. func issueState(isClosed bool) types.IssueStateType {
  150. if isClosed {
  151. return types.IssueStateClosed
  152. }
  153. return types.IssueStateOpen
  154. }
  155. // toIssue converts a database issue to an API issue.
  156. // It assumes the following fields have been assigned with valid values:
  157. // Required - Poster, Labels
  158. // Optional - Milestone, Assignee, PullRequest
  159. func toIssue(issue *database.Issue) *types.Issue {
  160. labels := make([]*types.IssueLabel, len(issue.Labels))
  161. for i := range issue.Labels {
  162. labels[i] = toIssueLabel(issue.Labels[i])
  163. }
  164. apiIssue := &types.Issue{
  165. ID: issue.ID,
  166. Index: issue.Index,
  167. Poster: toUser(issue.Poster),
  168. Title: issue.Title,
  169. Body: issue.Content,
  170. Labels: labels,
  171. State: issueState(issue.IsClosed),
  172. Comments: issue.NumComments,
  173. Created: issue.Created,
  174. Updated: issue.Updated,
  175. }
  176. if issue.Milestone != nil {
  177. apiIssue.Milestone = toIssueMilestone(issue.Milestone)
  178. }
  179. if issue.Assignee != nil {
  180. apiIssue.Assignee = toUser(issue.Assignee)
  181. }
  182. if issue.IsPull {
  183. apiIssue.PullRequest = &types.PullRequestMeta{
  184. HasMerged: issue.PullRequest.HasMerged,
  185. }
  186. if issue.PullRequest.HasMerged {
  187. apiIssue.PullRequest.Merged = &issue.PullRequest.Merged
  188. }
  189. }
  190. return apiIssue
  191. }
  192. func toIssueComment(c *database.Comment) *types.IssueComment {
  193. return &types.IssueComment{
  194. ID: c.ID,
  195. HTMLURL: c.HTMLURL(),
  196. Poster: toUser(c.Poster),
  197. Body: c.Content,
  198. Created: c.Created,
  199. Updated: c.Updated,
  200. }
  201. }
  202. func toIssueMilestone(m *database.Milestone) *types.IssueMilestone {
  203. ms := &types.IssueMilestone{
  204. ID: m.ID,
  205. State: issueState(m.IsClosed),
  206. Title: m.Name,
  207. Description: m.Content,
  208. OpenIssues: m.NumOpenIssues,
  209. ClosedIssues: m.NumClosedIssues,
  210. }
  211. if m.IsClosed {
  212. ms.Closed = &m.ClosedDate
  213. }
  214. if m.Deadline.Year() < 9999 {
  215. ms.Deadline = &m.Deadline
  216. }
  217. return ms
  218. }
  219. // toRelease converts a database release to an API release.
  220. // It assumes the Publisher field has been assigned.
  221. func toRelease(r *database.Release) *types.RepositoryRelease {
  222. return &types.RepositoryRelease{
  223. ID: r.ID,
  224. TagName: r.TagName,
  225. TargetCommitish: r.Target,
  226. Name: r.Title,
  227. Body: r.Note,
  228. Draft: r.IsDraft,
  229. Prerelease: r.IsPrerelease,
  230. Author: toUser(r.Publisher),
  231. Created: r.Created,
  232. }
  233. }
  234. func toRepositoryCollaborator(c *database.Collaborator) *types.RepositoryCollaborator {
  235. return &types.RepositoryCollaborator{
  236. User: toUser(c.User),
  237. Permissions: types.RepositoryPermission{
  238. Admin: c.Collaboration.Mode >= database.AccessModeAdmin,
  239. Push: c.Collaboration.Mode >= database.AccessModeWrite,
  240. Pull: c.Collaboration.Mode >= database.AccessModeRead,
  241. },
  242. }
  243. }
  244. // toRepository converts a database repository to an API repository.
  245. // It assumes the Owner field has been loaded on the repo.
  246. func toRepository(repo *database.Repository, perm *types.RepositoryPermission) *types.Repository {
  247. cloneLink := repo.CloneLink()
  248. apiRepo := &types.Repository{
  249. ID: repo.ID,
  250. Owner: toUser(repo.Owner),
  251. Name: repo.Name,
  252. FullName: repo.FullName(),
  253. Description: repo.Description,
  254. Private: repo.IsPrivate,
  255. Fork: repo.IsFork,
  256. Empty: repo.IsBare,
  257. Mirror: repo.IsMirror,
  258. Size: repo.Size,
  259. HTMLURL: repo.HTMLURL(),
  260. SSHURL: cloneLink.SSH,
  261. CloneURL: cloneLink.HTTPS,
  262. Website: repo.Website,
  263. Stars: repo.NumStars,
  264. Forks: repo.NumForks,
  265. Watchers: repo.NumWatches,
  266. OpenIssues: repo.NumOpenIssues,
  267. DefaultBranch: repo.DefaultBranch,
  268. Created: repo.Created,
  269. Updated: repo.Updated,
  270. Permissions: perm,
  271. }
  272. if repo.IsFork {
  273. p := &types.RepositoryPermission{Pull: true}
  274. apiRepo.Parent = toRepository(repo.BaseRepo, p)
  275. }
  276. return apiRepo
  277. }