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.

file.go 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright 2019 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package files
  4. import (
  5. "context"
  6. "fmt"
  7. "net/url"
  8. "strings"
  9. "time"
  10. repo_model "code.gitea.io/gitea/models/repo"
  11. user_model "code.gitea.io/gitea/models/user"
  12. "code.gitea.io/gitea/modules/git"
  13. api "code.gitea.io/gitea/modules/structs"
  14. "code.gitea.io/gitea/modules/util"
  15. )
  16. func GetFilesResponseFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, branch string, treeNames []string) (*api.FilesResponse, error) {
  17. files := []*api.ContentsResponse{}
  18. for _, file := range treeNames {
  19. fileContents, _ := GetContents(ctx, repo, file, branch, false) // ok if fails, then will be nil
  20. files = append(files, fileContents)
  21. }
  22. fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil
  23. verification := GetPayloadCommitVerification(ctx, commit)
  24. filesResponse := &api.FilesResponse{
  25. Files: files,
  26. Commit: fileCommitResponse,
  27. Verification: verification,
  28. }
  29. return filesResponse, nil
  30. }
  31. // GetFileResponseFromCommit Constructs a FileResponse from a Commit object
  32. func GetFileResponseFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, branch, treeName string) (*api.FileResponse, error) {
  33. fileContents, _ := GetContents(ctx, repo, treeName, branch, false) // ok if fails, then will be nil
  34. fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil
  35. verification := GetPayloadCommitVerification(ctx, commit)
  36. fileResponse := &api.FileResponse{
  37. Content: fileContents,
  38. Commit: fileCommitResponse,
  39. Verification: verification,
  40. }
  41. return fileResponse, nil
  42. }
  43. // constructs a FileResponse with the file at the index from FilesResponse
  44. func GetFileResponseFromFilesResponse(filesResponse *api.FilesResponse, index int) *api.FileResponse {
  45. content := &api.ContentsResponse{}
  46. if len(filesResponse.Files) > index {
  47. content = filesResponse.Files[index]
  48. }
  49. fileResponse := &api.FileResponse{
  50. Content: content,
  51. Commit: filesResponse.Commit,
  52. Verification: filesResponse.Verification,
  53. }
  54. return fileResponse
  55. }
  56. // GetFileCommitResponse Constructs a FileCommitResponse from a Commit object
  57. func GetFileCommitResponse(repo *repo_model.Repository, commit *git.Commit) (*api.FileCommitResponse, error) {
  58. if repo == nil {
  59. return nil, fmt.Errorf("repo cannot be nil")
  60. }
  61. if commit == nil {
  62. return nil, fmt.Errorf("commit cannot be nil")
  63. }
  64. commitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String()))
  65. commitTreeURL, _ := url.Parse(repo.APIURL() + "/git/trees/" + url.PathEscape(commit.Tree.ID.String()))
  66. parents := make([]*api.CommitMeta, commit.ParentCount())
  67. for i := 0; i <= commit.ParentCount(); i++ {
  68. if parent, err := commit.Parent(i); err == nil && parent != nil {
  69. parentCommitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(parent.ID.String()))
  70. parents[i] = &api.CommitMeta{
  71. SHA: parent.ID.String(),
  72. URL: parentCommitURL.String(),
  73. }
  74. }
  75. }
  76. commitHTMLURL, _ := url.Parse(repo.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String()))
  77. fileCommit := &api.FileCommitResponse{
  78. CommitMeta: api.CommitMeta{
  79. SHA: commit.ID.String(),
  80. URL: commitURL.String(),
  81. },
  82. HTMLURL: commitHTMLURL.String(),
  83. Author: &api.CommitUser{
  84. Identity: api.Identity{
  85. Name: commit.Author.Name,
  86. Email: commit.Author.Email,
  87. },
  88. Date: commit.Author.When.UTC().Format(time.RFC3339),
  89. },
  90. Committer: &api.CommitUser{
  91. Identity: api.Identity{
  92. Name: commit.Committer.Name,
  93. Email: commit.Committer.Email,
  94. },
  95. Date: commit.Committer.When.UTC().Format(time.RFC3339),
  96. },
  97. Message: commit.Message(),
  98. Tree: &api.CommitMeta{
  99. URL: commitTreeURL.String(),
  100. SHA: commit.Tree.ID.String(),
  101. },
  102. Parents: parents,
  103. }
  104. return fileCommit, nil
  105. }
  106. // GetAuthorAndCommitterUsers Gets the author and committer user objects from the IdentityOptions
  107. func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *user_model.User) (authorUser, committerUser *user_model.User) {
  108. // Committer and author are optional. If they are not the doer (not same email address)
  109. // then we use bogus User objects for them to store their FullName and Email.
  110. // If only one of the two are provided, we set both of them to it.
  111. // If neither are provided, both are the doer.
  112. if committer != nil && committer.Email != "" {
  113. if doer != nil && strings.EqualFold(doer.Email, committer.Email) {
  114. committerUser = doer // the committer is the doer, so will use their user object
  115. if committer.Name != "" {
  116. committerUser.FullName = committer.Name
  117. }
  118. } else {
  119. committerUser = &user_model.User{
  120. FullName: committer.Name,
  121. Email: committer.Email,
  122. }
  123. }
  124. }
  125. if author != nil && author.Email != "" {
  126. if doer != nil && strings.EqualFold(doer.Email, author.Email) {
  127. authorUser = doer // the author is the doer, so will use their user object
  128. if authorUser.Name != "" {
  129. authorUser.FullName = author.Name
  130. }
  131. } else {
  132. authorUser = &user_model.User{
  133. FullName: author.Name,
  134. Email: author.Email,
  135. }
  136. }
  137. }
  138. if authorUser == nil {
  139. if committerUser != nil {
  140. authorUser = committerUser // No valid author was given so use the committer
  141. } else if doer != nil {
  142. authorUser = doer // No valid author was given and no valid committer so use the doer
  143. }
  144. }
  145. if committerUser == nil {
  146. committerUser = authorUser // No valid committer so use the author as the committer (was set to a valid user above)
  147. }
  148. return authorUser, committerUser
  149. }
  150. // CleanUploadFileName Trims a filename and returns empty string if it is a .git directory
  151. func CleanUploadFileName(name string) string {
  152. // Rebase the filename
  153. name = util.PathJoinRel(name)
  154. // Git disallows any filenames to have a .git directory in them.
  155. for _, part := range strings.Split(name, "/") {
  156. if strings.ToLower(part) == ".git" {
  157. return ""
  158. }
  159. }
  160. return name
  161. }