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