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	"github.com/MichaelMure/git-bug/util/timestamp"
 11)
 12
 13var _ Operation = &SetStatusOperation{}
 14
 15// SetStatusOperation will change the status of a bug
 16type SetStatusOperation struct {
 17	OpBase
 18	Status Status `json:"status"`
 19}
 20
 21// Sign-post method for gqlgen
 22func (op *SetStatusOperation) IsOperation() {}
 23
 24func (op *SetStatusOperation) base() *OpBase {
 25	return &op.OpBase
 26}
 27
 28func (op *SetStatusOperation) Id() entity.Id {
 29	return idOperation(op)
 30}
 31
 32func (op *SetStatusOperation) Apply(snapshot *Snapshot) {
 33	snapshot.Status = op.Status
 34	snapshot.addActor(op.Author)
 35
 36	item := &SetStatusTimelineItem{
 37		id:       op.Id(),
 38		Author:   op.Author,
 39		UnixTime: timestamp.Timestamp(op.UnixTime),
 40		Status:   op.Status,
 41	}
 42
 43	snapshot.Timeline = append(snapshot.Timeline, item)
 44}
 45
 46func (op *SetStatusOperation) Validate() error {
 47	if err := opBaseValidate(op, SetStatusOp); err != nil {
 48		return err
 49	}
 50
 51	if err := op.Status.Validate(); err != nil {
 52		return errors.Wrap(err, "status")
 53	}
 54
 55	return nil
 56}
 57
 58// UnmarshalJSON is a two step JSON unmarshaling
 59// This workaround is necessary to avoid the inner OpBase.MarshalJSON
 60// overriding the outer op's MarshalJSON
 61func (op *SetStatusOperation) UnmarshalJSON(data []byte) error {
 62	// Unmarshal OpBase and the op separately
 63
 64	base := OpBase{}
 65	err := json.Unmarshal(data, &base)
 66	if err != nil {
 67		return err
 68	}
 69
 70	aux := struct {
 71		Status Status `json:"status"`
 72	}{}
 73
 74	err = json.Unmarshal(data, &aux)
 75	if err != nil {
 76		return err
 77	}
 78
 79	op.OpBase = base
 80	op.Status = aux.Status
 81
 82	return nil
 83}
 84
 85// Sign post method for gqlgen
 86func (op *SetStatusOperation) IsAuthored() {}
 87
 88func NewSetStatusOp(author identity.Interface, unixTime int64, status Status) *SetStatusOperation {
 89	return &SetStatusOperation{
 90		OpBase: newOpBase(SetStatusOp, author, unixTime),
 91		Status: status,
 92	}
 93}
 94
 95type SetStatusTimelineItem struct {
 96	id       entity.Id
 97	Author   identity.Interface
 98	UnixTime timestamp.Timestamp
 99	Status   Status
100}
101
102func (s SetStatusTimelineItem) Id() entity.Id {
103	return s.id
104}
105
106// Sign post method for gqlgen
107func (s *SetStatusTimelineItem) IsAuthored() {}
108
109// Convenience function to apply the operation
110func Open(b Interface, author identity.Interface, unixTime int64) (*SetStatusOperation, error) {
111	op := NewSetStatusOp(author, unixTime, OpenStatus)
112	if err := op.Validate(); err != nil {
113		return nil, err
114	}
115	b.Append(op)
116	return op, nil
117}
118
119// Convenience function to apply the operation
120func Close(b Interface, author identity.Interface, unixTime int64) (*SetStatusOperation, error) {
121	op := NewSetStatusOp(author, unixTime, ClosedStatus)
122	if err := op.Validate(); err != nil {
123		return nil, err
124	}
125	b.Append(op)
126	return op, nil
127}