2019-04-17 12:06:35 -04:00
|
|
|
// Copyright 2019 The Gitea Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a MIT-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2021-11-24 02:56:24 -05:00
|
|
|
package files
|
2019-04-17 12:06:35 -04:00
|
|
|
|
|
|
|
import (
|
2022-01-19 18:26:57 -05:00
|
|
|
"context"
|
2019-04-17 12:06:35 -04:00
|
|
|
"fmt"
|
|
|
|
"net/url"
|
2021-11-24 02:56:24 -05:00
|
|
|
"path"
|
2019-04-17 12:06:35 -04:00
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2021-12-09 20:27:50 -05:00
|
|
|
repo_model "code.gitea.io/gitea/models/repo"
|
2021-11-24 04:49:20 -05:00
|
|
|
user_model "code.gitea.io/gitea/models/user"
|
2019-04-17 12:06:35 -04:00
|
|
|
"code.gitea.io/gitea/modules/git"
|
2019-05-11 06:21:34 -04:00
|
|
|
api "code.gitea.io/gitea/modules/structs"
|
2019-04-17 12:06:35 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// GetFileResponseFromCommit Constructs a FileResponse from a Commit object
|
2022-01-19 18:26:57 -05:00
|
|
|
func GetFileResponseFromCommit(ctx context.Context, repo *repo_model.Repository, commit *git.Commit, branch, treeName string) (*api.FileResponse, error) {
|
|
|
|
fileContents, _ := GetContents(ctx, repo, treeName, branch, false) // ok if fails, then will be nil
|
|
|
|
fileCommitResponse, _ := GetFileCommitResponse(repo, commit) // ok if fails, then will be nil
|
2019-04-17 12:06:35 -04:00
|
|
|
verification := GetPayloadCommitVerification(commit)
|
|
|
|
fileResponse := &api.FileResponse{
|
|
|
|
Content: fileContents,
|
|
|
|
Commit: fileCommitResponse,
|
|
|
|
Verification: verification,
|
|
|
|
}
|
|
|
|
return fileResponse, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetFileCommitResponse Constructs a FileCommitResponse from a Commit object
|
2021-12-09 20:27:50 -05:00
|
|
|
func GetFileCommitResponse(repo *repo_model.Repository, commit *git.Commit) (*api.FileCommitResponse, error) {
|
2019-04-17 12:06:35 -04:00
|
|
|
if repo == nil {
|
|
|
|
return nil, fmt.Errorf("repo cannot be nil")
|
|
|
|
}
|
|
|
|
if commit == nil {
|
|
|
|
return nil, fmt.Errorf("commit cannot be nil")
|
|
|
|
}
|
2021-11-16 13:18:25 -05:00
|
|
|
commitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(commit.ID.String()))
|
|
|
|
commitTreeURL, _ := url.Parse(repo.APIURL() + "/git/trees/" + url.PathEscape(commit.Tree.ID.String()))
|
2019-04-17 12:06:35 -04:00
|
|
|
parents := make([]*api.CommitMeta, commit.ParentCount())
|
|
|
|
for i := 0; i <= commit.ParentCount(); i++ {
|
|
|
|
if parent, err := commit.Parent(i); err == nil && parent != nil {
|
2021-11-16 13:18:25 -05:00
|
|
|
parentCommitURL, _ := url.Parse(repo.APIURL() + "/git/commits/" + url.PathEscape(parent.ID.String()))
|
2019-04-17 12:06:35 -04:00
|
|
|
parents[i] = &api.CommitMeta{
|
|
|
|
SHA: parent.ID.String(),
|
|
|
|
URL: parentCommitURL.String(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-16 13:18:25 -05:00
|
|
|
commitHTMLURL, _ := url.Parse(repo.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String()))
|
2019-04-17 12:06:35 -04:00
|
|
|
fileCommit := &api.FileCommitResponse{
|
|
|
|
CommitMeta: api.CommitMeta{
|
|
|
|
SHA: commit.ID.String(),
|
|
|
|
URL: commitURL.String(),
|
|
|
|
},
|
|
|
|
HTMLURL: commitHTMLURL.String(),
|
|
|
|
Author: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: commit.Author.Name,
|
|
|
|
Email: commit.Author.Email,
|
|
|
|
},
|
|
|
|
Date: commit.Author.When.UTC().Format(time.RFC3339),
|
|
|
|
},
|
|
|
|
Committer: &api.CommitUser{
|
|
|
|
Identity: api.Identity{
|
|
|
|
Name: commit.Committer.Name,
|
|
|
|
Email: commit.Committer.Email,
|
|
|
|
},
|
|
|
|
Date: commit.Committer.When.UTC().Format(time.RFC3339),
|
|
|
|
},
|
|
|
|
Message: commit.Message(),
|
|
|
|
Tree: &api.CommitMeta{
|
|
|
|
URL: commitTreeURL.String(),
|
|
|
|
SHA: commit.Tree.ID.String(),
|
|
|
|
},
|
|
|
|
Parents: parents,
|
|
|
|
}
|
|
|
|
return fileCommit, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetAuthorAndCommitterUsers Gets the author and committer user objects from the IdentityOptions
|
2021-11-24 04:49:20 -05:00
|
|
|
func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *user_model.User) (authorUser, committerUser *user_model.User) {
|
2019-04-17 12:06:35 -04:00
|
|
|
// Committer and author are optional. If they are not the doer (not same email address)
|
|
|
|
// then we use bogus User objects for them to store their FullName and Email.
|
|
|
|
// If only one of the two are provided, we set both of them to it.
|
|
|
|
// If neither are provided, both are the doer.
|
|
|
|
if committer != nil && committer.Email != "" {
|
2019-06-12 15:41:28 -04:00
|
|
|
if doer != nil && strings.EqualFold(doer.Email, committer.Email) {
|
2019-04-17 12:06:35 -04:00
|
|
|
committerUser = doer // the committer is the doer, so will use their user object
|
|
|
|
if committer.Name != "" {
|
|
|
|
committerUser.FullName = committer.Name
|
|
|
|
}
|
|
|
|
} else {
|
2021-11-24 04:49:20 -05:00
|
|
|
committerUser = &user_model.User{
|
2019-04-17 12:06:35 -04:00
|
|
|
FullName: committer.Name,
|
|
|
|
Email: committer.Email,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if author != nil && author.Email != "" {
|
2019-06-12 15:41:28 -04:00
|
|
|
if doer != nil && strings.EqualFold(doer.Email, author.Email) {
|
2019-04-17 12:06:35 -04:00
|
|
|
authorUser = doer // the author is the doer, so will use their user object
|
|
|
|
if authorUser.Name != "" {
|
|
|
|
authorUser.FullName = author.Name
|
|
|
|
}
|
|
|
|
} else {
|
2021-11-24 04:49:20 -05:00
|
|
|
authorUser = &user_model.User{
|
2019-04-17 12:06:35 -04:00
|
|
|
FullName: author.Name,
|
|
|
|
Email: author.Email,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if authorUser == nil {
|
|
|
|
if committerUser != nil {
|
|
|
|
authorUser = committerUser // No valid author was given so use the committer
|
|
|
|
} else if doer != nil {
|
|
|
|
authorUser = doer // No valid author was given and no valid committer so use the doer
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if committerUser == nil {
|
|
|
|
committerUser = authorUser // No valid committer so use the author as the committer (was set to a valid user above)
|
|
|
|
}
|
|
|
|
return authorUser, committerUser
|
|
|
|
}
|
2021-11-24 02:56:24 -05:00
|
|
|
|
|
|
|
// CleanUploadFileName Trims a filename and returns empty string if it is a .git directory
|
|
|
|
func CleanUploadFileName(name string) string {
|
|
|
|
// Rebase the filename
|
2022-01-19 16:03:15 -05:00
|
|
|
name = strings.Trim(path.Clean("/"+name), "/")
|
2021-11-24 02:56:24 -05:00
|
|
|
// Git disallows any filenames to have a .git directory in them.
|
|
|
|
for _, part := range strings.Split(name, "/") {
|
|
|
|
if strings.ToLower(part) == ".git" {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return name
|
|
|
|
}
|