op_set_metadata.go

  1package bug
  2
  3import (
  4	"encoding/json"
  5	"fmt"
  6
  7	"github.com/MichaelMure/git-bug/identity"
  8)
  9
 10var _ Operation = &SetMetadataOperation{}
 11
 12type SetMetadataOperation struct {
 13	OpBase
 14	Target      string
 15	NewMetadata map[string]string
 16}
 17
 18func (op *SetMetadataOperation) base() *OpBase {
 19	return &op.OpBase
 20}
 21
 22func (op *SetMetadataOperation) ID() string {
 23	return idOperation(op)
 24}
 25
 26func (op *SetMetadataOperation) Apply(snapshot *Snapshot) {
 27	for _, target := range snapshot.Operations {
 28		if target.ID() == op.Target {
 29			base := target.base()
 30
 31			if base.extraMetadata == nil {
 32				base.extraMetadata = make(map[string]string)
 33			}
 34
 35			for key, val := range op.NewMetadata {
 36				if _, exist := base.extraMetadata[key]; !exist {
 37					base.extraMetadata[key] = val
 38				}
 39			}
 40
 41			return
 42		}
 43	}
 44}
 45
 46func (op *SetMetadataOperation) Validate() error {
 47	if err := opBaseValidate(op, SetMetadataOp); err != nil {
 48		return err
 49	}
 50
 51	if !IDIsValid(op.Target) {
 52		return fmt.Errorf("target hash is invalid")
 53	}
 54
 55	return nil
 56}
 57
 58// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
 59// MarshalJSON
 60func (op *SetMetadataOperation) MarshalJSON() ([]byte, error) {
 61	base, err := json.Marshal(op.OpBase)
 62	if err != nil {
 63		return nil, err
 64	}
 65
 66	// revert back to a flat map to be able to add our own fields
 67	var data map[string]interface{}
 68	if err := json.Unmarshal(base, &data); err != nil {
 69		return nil, err
 70	}
 71
 72	data["target"] = op.Target
 73	data["new_metadata"] = op.NewMetadata
 74
 75	return json.Marshal(data)
 76}
 77
 78// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
 79// MarshalJSON
 80func (op *SetMetadataOperation) UnmarshalJSON(data []byte) error {
 81	// Unmarshal OpBase and the op separately
 82
 83	base := OpBase{}
 84	err := json.Unmarshal(data, &base)
 85	if err != nil {
 86		return err
 87	}
 88
 89	aux := struct {
 90		Target      string            `json:"target"`
 91		NewMetadata map[string]string `json:"new_metadata"`
 92	}{}
 93
 94	err = json.Unmarshal(data, &aux)
 95	if err != nil {
 96		return err
 97	}
 98
 99	op.OpBase = base
100	op.Target = aux.Target
101	op.NewMetadata = aux.NewMetadata
102
103	return nil
104}
105
106// Sign post method for gqlgen
107func (op *SetMetadataOperation) IsAuthored() {}
108
109func NewSetMetadataOp(author identity.Interface, unixTime int64, target string, newMetadata map[string]string) *SetMetadataOperation {
110	return &SetMetadataOperation{
111		OpBase:      newOpBase(SetMetadataOp, author, unixTime),
112		Target:      target,
113		NewMetadata: newMetadata,
114	}
115}
116
117// Convenience function to apply the operation
118func SetMetadata(b Interface, author identity.Interface, unixTime int64, target string, newMetadata map[string]string) (*SetMetadataOperation, error) {
119	SetMetadataOp := NewSetMetadataOp(author, unixTime, target, newMetadata)
120	if err := SetMetadataOp.Validate(); err != nil {
121		return nil, err
122	}
123	b.Append(SetMetadataOp)
124	return SetMetadataOp, nil
125}