gitea-github-proxy/api/routes_rest_api.go

186 lines
4.8 KiB
Go
Raw Normal View History

package api
import (
gitea "code.gitea.io/sdk/gitea"
"encoding/json"
"fmt"
"git.lumeweb.com/LumeWeb/gitea-github-proxy/config"
"github.com/google/go-github/v59/github"
"github.com/gorilla/mux"
"go.uber.org/zap"
"net/http"
"strconv"
)
type restApi struct {
config *config.Config
logger *zap.Logger
}
func newRestApi(cfg *config.Config, logger *zap.Logger) *restApi {
return &restApi{config: cfg, logger: logger}
}
func (r restApi) handlerGetPullRequestFiles(w http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
owner := vars["owner"]
repo := vars["repo"]
pullNumber := vars["pull_number"]
client := r.getClientOrError(w)
if client == nil {
return
}
parsedPullNumber, err := strconv.ParseInt(pullNumber, 10, 64)
if err != nil {
http.Error(w, "Failed to parse pull number", http.StatusBadRequest)
r.logger.Error("Failed to parse pull number", zap.Error(err))
return
}
files, r2, err := client.ListPullRequestFiles(owner, repo, parsedPullNumber, gitea.ListPullRequestFilesOptions{
ListOptions: r.getPagingOptions(request),
})
if err != nil {
http.Error(w, "Failed to get pull request files", http.StatusInternalServerError)
r.logger.Error("Failed to get pull request files", zap.Error(err))
return
}
githubFiles := make([]*github.CommitFile, len(files))
for i, file := range files {
githubFiles[i] = convertCommitFile(file)
}
r.sendPagingHeaders(w, r2)
r.respond(w, http.StatusOK, githubFiles)
}
func (r restApi) getPagingOptions(request *http.Request) gitea.ListOptions {
page, _ := strconv.Atoi(request.URL.Query().Get("page"))
perPage, _ := strconv.Atoi(request.URL.Query().Get("per_page"))
return gitea.ListOptions{
Page: page,
PageSize: perPage,
}
}
func (r restApi) sendPagingHeaders(w http.ResponseWriter, apiResponse *gitea.Response) {
links := []string{}
baseURL := fmt.Sprintf("https://%s", r.config.Domain)
joinStrings := func(elements []string, separator string) string {
if len(elements) == 0 {
return ""
}
result := elements[0]
for i := 1; i < len(elements); i++ {
result += separator + elements[i]
}
return result
}
joinLinks := func(links []string) string {
return fmt.Sprintf("%s", joinStrings(links, ", "))
}
if apiResponse.FirstPage > 0 {
links = append(links, fmt.Sprintf(`<%s?page=%d>; rel="first"`, baseURL, apiResponse.FirstPage))
}
if apiResponse.PrevPage > 0 {
links = append(links, fmt.Sprintf(`<%s?page=%d>; rel="prev"`, baseURL, apiResponse.PrevPage))
}
if apiResponse.NextPage > 0 {
links = append(links, fmt.Sprintf(`<%s?page=%d>; rel="next"`, baseURL, apiResponse.NextPage))
}
if apiResponse.LastPage > 0 {
links = append(links, fmt.Sprintf(`<%s?page=%d>; rel="last"`, baseURL, apiResponse.LastPage))
}
if len(links) > 0 {
w.Header().Add("Link", fmt.Sprintf("%s", joinLinks(links)))
}
}
func (r restApi) respond(w http.ResponseWriter, status int, data interface{}) {
jsonData, err := json.Marshal(data)
if err != nil {
http.Error(w, "Failed to marshal response", http.StatusInternalServerError)
r.logger.Error("Failed to marshal response", zap.Error(err))
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
if data != nil {
_, _ = w.Write(jsonData)
}
}
func (r restApi) getClientOrError(w http.ResponseWriter) *gitea.Client {
client, err := getClient(ClientParams{
Config: r.config,
})
if err != nil {
http.Error(w, "Failed to get Gitea client", http.StatusInternalServerError)
r.logger.Error("Failed to get Gitea client", zap.Error(err))
return nil
}
return client
}
func (r restApi) handlerGetTree(w http.ResponseWriter, request *http.Request) {
vars := mux.Vars(request)
owner := vars["owner"]
repo := vars["repo"]
treeSha := vars["tree_sha"]
recursive := false
if request.URL.Query().Has("recursive") {
recursive = true
}
client := r.getClientOrError(w)
if client == nil {
return
}
tree, r2, err := client.GetTrees(owner, repo, treeSha, recursive)
if err != nil {
http.Error(w, "Failed to get tree", http.StatusInternalServerError)
r.logger.Error("Failed to get tree", zap.Error(err))
return
}
treeResponse := convertGitTree(tree)
r.sendPagingHeaders(w, r2)
r.respond(w, http.StatusOK, treeResponse)
}
func setupRestRoutes(params RouteParams) {
logger := params.Logger
cfg := params.Config
r := params.R
restApi := newRestApi(cfg, logger)
setupRoutes := func(r *mux.Router) {
r.HandleFunc("/repos/{owner}/{repo}/pulls/{pull_number}/files", restApi.handlerGetPullRequestFiles).Methods("GET")
r.HandleFunc("/repos/{owner}/{repo}/git/trees/{tree_sha}", restApi.handlerGetTree).Methods("GET")
}
restRouter := r.PathPrefix("/api").Subrouter()
restRouter.Use(githubRestVerifyMiddleware(params.Db))
restRouter.Use(githubRestRequireAuthMiddleware(params.Config))
setupRoutes(restRouter)
setupRoutes(restRouter.PathPrefix("/v3").Subrouter())
}