Gitfed
bastien-mrq/gitfed / internal / store / repos.go
package store

import (
	"fmt"
	"time"

	bolt "go.etcd.io/bbolt"
)

// Repo is a bare git repository hosted on this instance.
type Repo struct {
	Name      string    `json:"name"`  // e.g. "alice/mon-projet"
	Owner     string    `json:"owner"` // principal, e.g. "alice@instancea.example"
	Path      string    `json:"path"`  // absolute path to the bare repo on disk
	CreatedAt time.Time `json:"created_at"`

	// Public repos are readable (never writable) by any principal that can
	// authenticate to this instance, without needing an explicit ACL entry.
	// This does not grant anonymous/unauthenticated access — the reader
	// still needs a valid local account or a certificate from a domain
	// this instance already trusts (§5.2); it only skips the per-repo
	// collaborator check for reads.
	Public      bool     `json:"public"`
	Topics      []string `json:"topics,omitempty"`
	Description string   `json:"description,omitempty"`
}

func (s *Store) CreateRepo(r Repo) error {
	if r.Name == "" || r.Owner == "" || r.Path == "" {
		return fmt.Errorf("store: repo name, owner and path are required")
	}
	r.CreatedAt = time.Now().UTC()
	return s.db.Update(func(tx *bolt.Tx) error {
		if tx.Bucket(bucketRepos).Get([]byte(r.Name)) != nil {
			return fmt.Errorf("store: repo %q already exists", r.Name)
		}
		return putJSON(tx, bucketRepos, r.Name, r)
	})
}

func (s *Store) GetRepo(name string) (Repo, error) {
	var r Repo
	err := s.db.View(func(tx *bolt.Tx) error {
		return getJSON(tx, bucketRepos, name, &r)
	})
	return r, err
}

func (s *Store) ListRepos() ([]Repo, error) {
	var repos []Repo
	err := s.db.View(func(tx *bolt.Tx) error {
		var err error
		repos, err = listJSON[Repo](tx, bucketRepos)
		return err
	})
	return repos, err
}

func (s *Store) DeleteRepo(name string) error {
	return s.db.Update(func(tx *bolt.Tx) error {
		return deleteKey(tx, bucketRepos, name)
	})
}

func (s *Store) SetRepoPublic(name string, public bool) error {
	return s.db.Update(func(tx *bolt.Tx) error {
		var r Repo
		if err := getJSON(tx, bucketRepos, name, &r); err != nil {
			return err
		}
		r.Public = public
		return putJSON(tx, bucketRepos, name, r)
	})
}

func (s *Store) SetRepoTopics(name string, topics []string) error {
	return s.db.Update(func(tx *bolt.Tx) error {
		var r Repo
		if err := getJSON(tx, bucketRepos, name, &r); err != nil {
			return err
		}
		r.Topics = topics
		return putJSON(tx, bucketRepos, name, r)
	})
}

func (s *Store) SetRepoDescription(name, description string) error {
	return s.db.Update(func(tx *bolt.Tx) error {
		var r Repo
		if err := getJSON(tx, bucketRepos, name, &r); err != nil {
			return err
		}
		r.Description = description
		return putJSON(tx, bucketRepos, name, r)
	})
}