identity_subcache.go

  1package cache
  2
  3import (
  4	"github.com/git-bug/git-bug/entities/identity"
  5	"github.com/git-bug/git-bug/entity"
  6	"github.com/git-bug/git-bug/repository"
  7)
  8
  9type RepoCacheIdentity struct {
 10	*SubCache[*identity.Identity, *IdentityExcerpt, *IdentityCache]
 11}
 12
 13func NewRepoCacheIdentity(repo repository.ClockedRepo,
 14	resolvers func() entity.Resolvers,
 15	getUserIdentity getUserIdentityFunc) *RepoCacheIdentity {
 16
 17	makeCached := func(i *identity.Identity, entityUpdated func(id entity.Id) error) *IdentityCache {
 18		return NewIdentityCache(i, repo, entityUpdated)
 19	}
 20
 21	makeIndex := func(i *IdentityCache) []string {
 22		// no indexing
 23		return nil
 24	}
 25
 26	// TODO: this is terribly ugly, but we are currently stuck with the fact that identities are NOT using the fancy dag framework.
 27	//   This lead to various complication here and there to handle entities generically, and avoid large code duplication.
 28	//   TL;DR: something has to give, and this is the less ugly solution I found. This "normalize" identities as just another "dag framework"
 29	//   entity. Ideally identities would be converted to the dag framework, but right now that could lead to potential attack: if an old
 30	//   private key is leaked, it would be possible to craft a legal identity update that take over the most recent version. While this is
 31	//   meaningless in the case of a normal entity, it's really an issues for identities.
 32
 33	actions := Actions[*identity.Identity]{
 34		ReadWithResolver: func(repo repository.ClockedRepo, resolvers entity.Resolvers, id entity.Id) (*identity.Identity, error) {
 35			return identity.ReadLocal(repo, id)
 36		},
 37		ReadAllWithResolver: func(repo repository.ClockedRepo, resolvers entity.Resolvers) <-chan entity.StreamedEntity[*identity.Identity] {
 38			return identity.ReadAllLocal(repo)
 39		},
 40		Remove:    identity.Remove,
 41		RemoveAll: identity.RemoveAll,
 42		MergeAll: func(repo repository.ClockedRepo, resolvers entity.Resolvers, remote string, mergeAuthor identity.Interface) <-chan entity.MergeResult {
 43			return identity.MergeAll(repo, remote)
 44		},
 45	}
 46
 47	sc := NewSubCache[*identity.Identity, *IdentityExcerpt, *IdentityCache](
 48		repo, resolvers, getUserIdentity,
 49		makeCached, NewIdentityExcerpt, makeIndex, actions,
 50		identity.Typename, identity.Namespace,
 51		formatVersion, defaultMaxLoadedBugs,
 52	)
 53
 54	return &RepoCacheIdentity{SubCache: sc}
 55}
 56
 57// ResolveIdentityImmutableMetadata retrieve an Identity that has the exact given metadata on
 58// one of its version. If multiple version have the same key, the first defined take precedence.
 59func (c *RepoCacheIdentity) ResolveIdentityImmutableMetadata(key string, value string) (*IdentityCache, error) {
 60	return c.ResolveMatcher(func(excerpt *IdentityExcerpt) bool {
 61		return excerpt.ImmutableMetadata[key] == value
 62	})
 63}
 64
 65// New create a new identity
 66// The new identity is written in the repository (commit)
 67func (c *RepoCacheIdentity) New(name string, email string) (*IdentityCache, error) {
 68	return c.NewRaw(name, email, "", "", nil, nil)
 69}
 70
 71// NewFull create a new identity
 72// The new identity is written in the repository (commit)
 73func (c *RepoCacheIdentity) NewFull(name string, email string, login string, avatarUrl string, keys []*identity.Key) (*IdentityCache, error) {
 74	return c.NewRaw(name, email, login, avatarUrl, keys, nil)
 75}
 76
 77func (c *RepoCacheIdentity) NewRaw(name string, email string, login string, avatarUrl string, keys []*identity.Key, metadata map[string]string) (*IdentityCache, error) {
 78	i, err := identity.NewIdentityFull(c.repo, name, email, login, avatarUrl, keys)
 79	if err != nil {
 80		return nil, err
 81	}
 82	return c.finishIdentity(i, metadata)
 83}
 84
 85func (c *RepoCacheIdentity) NewFromGitUser() (*IdentityCache, error) {
 86	return c.NewFromGitUserRaw(nil)
 87}
 88
 89func (c *RepoCacheIdentity) NewFromGitUserRaw(metadata map[string]string) (*IdentityCache, error) {
 90	i, err := identity.NewFromGitUser(c.repo)
 91	if err != nil {
 92		return nil, err
 93	}
 94	return c.finishIdentity(i, metadata)
 95}
 96
 97func (c *RepoCacheIdentity) finishIdentity(i *identity.Identity, metadata map[string]string) (*IdentityCache, error) {
 98	for key, value := range metadata {
 99		i.SetMetadata(key, value)
100	}
101
102	err := i.Commit(c.repo)
103	if err != nil {
104		return nil, err
105	}
106
107	cached, err := c.add(i)
108	if err != nil {
109		return nil, err
110	}
111
112	return cached, nil
113}