~w1ke/hut

392faeb83f2bd64b077cca9806383de979b0120e — w1ke 11 months ago 9eba50f
added hut git access
2 files changed, 129 insertions(+), 5 deletions(-)

M api/git/git.go
M cmd/hut/git.go
M api/git/git.go => api/git/git.go +102 -3
@@ 4,9 4,13 @@ import (
	"context"
	"errors"
	"fmt"
	"io"
	"log"
	"net/http"
	"regexp"
	"strings"

	"git.sr.ht/~w1ke/hut/api/meta"
	"github.com/shurcooL/graphql"
	"golang.org/x/oauth2"
)


@@ 16,11 20,28 @@ type Client struct {
	graphql *graphql.Client
}

type rt struct{ r http.RoundTripper }

func (r rt) RoundTrip(req *http.Request) (*http.Response, error) {
	body, err := req.GetBody()
	if err != nil {
		log.Println(err)
	}
	bodyContent, err := io.ReadAll(body)
	if err != nil {
		log.Println(err)
	}
	fmt.Println(string(bodyContent))
	body.Close()
	return r.r.RoundTrip(req)
}

func NewClient(token string) *Client {
	src := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: token},
	)
	httpClient := oauth2.NewClient(context.Background(), src)
	httpClient.Transport = rt{httpClient.Transport}

	client := graphql.NewClient("https://git.sr.ht/query", httpClient)



@@ 42,9 63,17 @@ type Repository struct {
	Owner struct {
		CanonicalName string
	}
	Name        string
	Description *string
	Visibility  Visibility
	Name              string
	Description       *string
	Visibility        Visibility
	AccessControlList struct {
		Results []struct {
			Id     int
			Entity struct {
				CanonicalName string
			}
		}
	}
}

func (c *Client) Create(name, description string, visibility Visibility) error {


@@ 195,6 224,19 @@ func repoInfo(r *Repository) {
	fmt.Println()
}

type User struct {
	Id graphql.Int
}

func (c *Client) getUser(identificator string) (*meta.UserInfo, error) {
	if userRegex.MatchString(identificator) {
		metaClient := meta.NewClient(c.token)
		user, err := metaClient.User(identificator)
		return user, err
	}
	return nil, errors.New("illegal identificator")
}

func (c *Client) getRepo(identificator string) (*Repository, error) {
	if userRepoRegex.MatchString(identificator) {
		slice := strings.Split(identificator, "/")


@@ 281,3 323,60 @@ func (c *Client) Delete(identificator string) error {

	return c.graphql.Mutate(context.Background(), &mutation, variables)
}

type AccessMode string

const (
	RW    AccessMode = "RW"
	RO    AccessMode = "RO"
	RESET AccessMode = ""
)

func (c *Client) Access(repoIdentificator, userIdentificator string, mode AccessMode) error {
	if mode == "" {
		repo, err := c.getRepo(repoIdentificator)
		if err != nil {
			return err
		}
		for _, r := range repo.AccessControlList.Results {
			if r.Entity.CanonicalName == userIdentificator {
				var mutation struct {
					DeleteACL struct {
						Id graphql.Int
					} `graphql:"deleteACL(id: $id)"`
				}

				variables := map[string]interface{}{
					"id": graphql.Int(r.Id),
				}

				return c.graphql.Mutate(context.Background(), &mutation, variables)
			}
		}
		return errors.New("that entity is not in the acl list")
	} else {
		repo, err := c.getRepo(repoIdentificator)
		if err != nil {
			return err
		}

		user, err := c.getUser(userIdentificator)
		if err != nil {
			return err
		}

		var mutation struct {
			UpdateACL struct{ Id graphql.Int } `graphql:"updateACL(repoId: $repoId, mode: $mode, entity: $id)"`
		}

		type ID string

		variables := map[string]interface{}{
			"repoId": graphql.Int(repo.Id),
			"mode":   mode,
			"id":     ID(user.CanonicalName),
		}

		return c.graphql.Mutate(context.Background(), &mutation, variables)
	}
}

M cmd/hut/git.go => cmd/hut/git.go +27 -2
@@ 119,8 119,33 @@ func gitRoot(args []string) {
		if err != nil {
			log.Fatal(err)
		}
	case "permit":
	case "deny":
	case "access":
		// hut git access <repo> <user> reset|read|both
		args = args[1:]
		if len(args) != 3 {
			gitUsage()
		}
		repoIdentificator := args[0]
		userIdentificator := args[1]
		access := args[2]
		if access == "reset" {
			err := client.Access(repoIdentificator, userIdentificator, git.RESET)
			if err != nil {
				log.Fatal(err)
			}
		} else if access == "read" {
			err := client.Access(repoIdentificator, userIdentificator, git.RO)
			if err != nil {
				log.Fatal(err)
			}
		} else if access == "both" {
			err := client.Access(repoIdentificator, userIdentificator, git.RW)
			if err != nil {
				log.Fatal(err)
			}
		} else {
			gitUsage()
		}
	default:
		gitUsage()
	}