Files
anonymous_github/backend/internal/server/provider_github_documents.go
T

118 lines
4.3 KiB
Go

package server
import (
"context"
"encoding/base64"
"fmt"
"github.com/tdurieux/anonymous_github/backend/internal/provider"
)
func (g *githubProvider) Document(ctx context.Context, q provider.DocumentRequest) (map[string]any, error) {
r := providerRecord(q.Access)
r["source"] = M{"gistId": q.ID, "repositoryFullName": q.Access.Ref.Name, "pullRequestId": q.Number}
return g.server.githubDocument(ctx, q.Kind, r)
}
func (g *githubProvider) DocumentURL(q provider.DocumentRequest) string {
if q.Kind == "gist" {
return "https://gist.github.com/" + segment(q.ID)
}
if !safeRepositoryName(q.Access.Ref.Name) {
return ""
}
return fmt.Sprintf("https://github.com/%s/pull/%d", q.Access.Ref.Name, q.Number)
}
func (s *Server) githubDocument(ctx context.Context, kind string, r M) (M, error) {
source := obj(r["source"])
var payload M
var token string
var err error
if kind == "gist" {
provider := "github"
if s.Config.AppEnabled {
grant, e := s.Store.one(ctx, "credentials", M{"ownerId": r["owner"], "provider": "github-app-user"})
if e != nil {
return nil, e
}
if grant != nil {
provider = "github-app-user"
}
}
token, err = s.credential(ctx, r["owner"], provider)
} else {
token, err = s.boundToken(ctx, r["owner"], obj(r["githubAccess"]), str(source["repositoryFullName"]))
}
if err != nil {
return nil, err
}
var endpoint string
if kind == "gist" {
endpoint = "/gists/" + segment(str(source["gistId"]))
} else {
endpoint = fmt.Sprintf("/repos/%s/pulls/%d", str(source["repositoryFullName"]), number(source["pullRequestId"]))
}
upstream, err := s.githubObject(ctx, "GET", endpoint, token, nil)
if err != nil {
return nil, err
}
if kind == "gist" {
files := []M{}
for _, value := range obj(upstream["files"]) {
f := obj(value)
if str(f["encoding"]) == "base64" {
decoded, e := base64.StdEncoding.DecodeString(str(f["content"]))
if e != nil {
return nil, fail("github_invalid_response", 502)
}
f["content"] = string(decoded)
}
if boolean(f["truncated"]) {
value, e := s.githubText(ctx, str(f["raw_url"]), token, "text/plain", 8*1024*1024)
if e != nil {
return nil, e
}
f["content"] = value
}
files = append(files, selectFields(f, "filename", "content", "language", "size", "type"))
}
payload = M{"description": upstream["description"], "isPublic": upstream["public"], "creationDate": date(upstream["created_at"]), "updatedDate": date(upstream["updated_at"]), "ownerLogin": obj(upstream["owner"])["login"], "files": files}
} else {
diff, e := s.githubText(ctx, "https://api.github.com"+endpoint, token, "application/vnd.github.diff", 8*1024*1024)
if e != nil {
return nil, e
}
payload = M{"title": upstream["title"], "body": upstream["body"], "creationDate": date(upstream["created_at"]), "updatedDate": date(upstream["updated_at"]), "draft": upstream["draft"], "merged": upstream["merged"], "mergedDate": date(upstream["merged_at"]), "state": upstream["state"], "baseRepositoryFullName": obj(obj(upstream["base"])["repo"])["full_name"], "headRepositoryFullName": obj(obj(upstream["head"])["repo"])["full_name"], "diff": diff}
}
comments := []M{}
commentsPath := endpoint + "/comments"
if kind == "pr" {
commentsPath = fmt.Sprintf("/repos/%s/issues/%d/comments", str(source["repositoryFullName"]), number(source["pullRequestId"]))
}
err = s.githubPages(ctx, commentsPath, token, "", func(c M) bool {
comments = append(comments, M{"body": c["body"], "author": obj(c["user"])["login"], "creationDate": date(c["created_at"]), "updatedDate": date(c["updated_at"])})
return false
})
if err != nil {
return nil, err
}
payload["comments"] = comments
return payload, nil
}
func (g *githubProvider) ConnectDocument(ctx context.Context, q provider.DocumentRequest, connection string) (provider.Access, error) {
if q.Kind == "gist" {
if q.ID == "" {
return q.Access, fail("gist_not_found", 400)
}
return q.Access, nil
}
if q.Kind != "pr" || !safeRepositoryName(q.Access.Ref.Name) || q.Number <= 0 {
return q.Access, fail("pull_request_not_found", 400)
}
if len(q.Access.Binding) > 0 {
return q.Access, g.Authorize(ctx, q.Access)
}
c, e := g.Connect(ctx, provider.ConnectRequest{OwnerID: q.Access.OwnerID, Name: q.Access.Ref.Name, Connection: connection})
q.Access.Binding = c.Binding
return q.Access, e
}