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