1package bug
2
3import (
4 "encoding/json"
5
6 "github.com/MichaelMure/git-bug/identity"
7 "github.com/MichaelMure/git-bug/util/git"
8 "github.com/pkg/errors"
9)
10
11var _ Operation = &SetStatusOperation{}
12
13// SetStatusOperation will change the status of a bug
14type SetStatusOperation struct {
15 OpBase
16 Status Status
17}
18
19func (op *SetStatusOperation) base() *OpBase {
20 return &op.OpBase
21}
22
23func (op *SetStatusOperation) Hash() (git.Hash, error) {
24 return hashOperation(op)
25}
26
27func (op *SetStatusOperation) Apply(snapshot *Snapshot) {
28 snapshot.Status = op.Status
29
30 hash, err := op.Hash()
31 if err != nil {
32 // Should never error unless a programming error happened
33 // (covered in OpBase.Validate())
34 panic(err)
35 }
36
37 item := &SetStatusTimelineItem{
38 hash: hash,
39 Author: op.Author,
40 UnixTime: Timestamp(op.UnixTime),
41 Status: op.Status,
42 }
43
44 snapshot.Timeline = append(snapshot.Timeline, item)
45}
46
47func (op *SetStatusOperation) Validate() error {
48 if err := opBaseValidate(op, SetStatusOp); err != nil {
49 return err
50 }
51
52 if err := op.Status.Validate(); err != nil {
53 return errors.Wrap(err, "status")
54 }
55
56 return nil
57}
58
59// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
60// MarshalJSON
61func (op *SetStatusOperation) MarshalJSON() ([]byte, error) {
62 base, err := json.Marshal(op.OpBase)
63 if err != nil {
64 return nil, err
65 }
66
67 // revert back to a flat map to be able to add our own fields
68 var data map[string]interface{}
69 if err := json.Unmarshal(base, &data); err != nil {
70 return nil, err
71 }
72
73 data["status"] = op.Status
74
75 return json.Marshal(data)
76}
77
78// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
79// MarshalJSON
80func (op *SetStatusOperation) 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 Status Status `json:"status"`
91 }{}
92
93 err = json.Unmarshal(data, &aux)
94 if err != nil {
95 return err
96 }
97
98 op.OpBase = base
99 op.Status = aux.Status
100
101 return nil
102}
103
104// Sign post method for gqlgen
105func (op *SetStatusOperation) IsAuthored() {}
106
107func NewSetStatusOp(author identity.Interface, unixTime int64, status Status) *SetStatusOperation {
108 return &SetStatusOperation{
109 OpBase: newOpBase(SetStatusOp, author, unixTime),
110 Status: status,
111 }
112}
113
114type SetStatusTimelineItem struct {
115 hash git.Hash
116 Author identity.Interface
117 UnixTime Timestamp
118 Status Status
119}
120
121func (s SetStatusTimelineItem) Hash() git.Hash {
122 return s.hash
123}
124
125// Convenience function to apply the operation
126func Open(b Interface, author identity.Interface, unixTime int64) (*SetStatusOperation, error) {
127 op := NewSetStatusOp(author, unixTime, OpenStatus)
128 if err := op.Validate(); err != nil {
129 return nil, err
130 }
131 b.Append(op)
132 return op, nil
133}
134
135// Convenience function to apply the operation
136func Close(b Interface, author identity.Interface, unixTime int64) (*SetStatusOperation, error) {
137 op := NewSetStatusOp(author, unixTime, ClosedStatus)
138 if err := op.Validate(); err != nil {
139 return nil, err
140 }
141 b.Append(op)
142 return op, nil
143}