1package bug
2
3import (
4 "encoding/json"
5
6 "github.com/pkg/errors"
7
8 "github.com/MichaelMure/git-bug/entity"
9 "github.com/MichaelMure/git-bug/identity"
10)
11
12var _ Operation = &SetMetadataOperation{}
13
14type SetMetadataOperation struct {
15 OpBase
16 Target entity.Id `json:"target"`
17 NewMetadata map[string]string `json:"new_metadata"`
18}
19
20func (op *SetMetadataOperation) base() *OpBase {
21 return &op.OpBase
22}
23
24func (op *SetMetadataOperation) Id() entity.Id {
25 return idOperation(op)
26}
27
28func (op *SetMetadataOperation) Apply(snapshot *Snapshot) {
29 for _, target := range snapshot.Operations {
30 if target.Id() == op.Target {
31 base := target.base()
32
33 if base.extraMetadata == nil {
34 base.extraMetadata = make(map[string]string)
35 }
36
37 // Apply the metadata in an immutable way: if a metadata already
38 // exist, it's not possible to override it.
39 for key, val := range op.NewMetadata {
40 if _, exist := base.extraMetadata[key]; !exist {
41 base.extraMetadata[key] = val
42 }
43 }
44
45 return
46 }
47 }
48}
49
50func (op *SetMetadataOperation) Validate() error {
51 if err := opBaseValidate(op, SetMetadataOp); err != nil {
52 return err
53 }
54
55 if err := op.Target.Validate(); err != nil {
56 return errors.Wrap(err, "target invalid")
57 }
58
59 return nil
60}
61
62// UnmarshalJSON is a two step JSON unmarshaling
63// This workaround is necessary to avoid the inner OpBase.MarshalJSON
64// overriding the outer op's MarshalJSON
65func (op *SetMetadataOperation) UnmarshalJSON(data []byte) error {
66 // Unmarshal OpBase and the op separately
67
68 base := OpBase{}
69 err := json.Unmarshal(data, &base)
70 if err != nil {
71 return err
72 }
73
74 aux := struct {
75 Target entity.Id `json:"target"`
76 NewMetadata map[string]string `json:"new_metadata"`
77 }{}
78
79 err = json.Unmarshal(data, &aux)
80 if err != nil {
81 return err
82 }
83
84 op.OpBase = base
85 op.Target = aux.Target
86 op.NewMetadata = aux.NewMetadata
87
88 return nil
89}
90
91// Sign post method for gqlgen
92func (op *SetMetadataOperation) IsAuthored() {}
93
94func NewSetMetadataOp(author identity.Interface, unixTime int64, target entity.Id, newMetadata map[string]string) *SetMetadataOperation {
95 return &SetMetadataOperation{
96 OpBase: newOpBase(SetMetadataOp, author, unixTime),
97 Target: target,
98 NewMetadata: newMetadata,
99 }
100}
101
102// Convenience function to apply the operation
103func SetMetadata(b Interface, author identity.Interface, unixTime int64, target entity.Id, newMetadata map[string]string) (*SetMetadataOperation, error) {
104 SetMetadataOp := NewSetMetadataOp(author, unixTime, target, newMetadata)
105 if err := SetMetadataOp.Validate(); err != nil {
106 return nil, err
107 }
108 b.Append(SetMetadataOp)
109 return SetMetadataOp, nil
110}