op_add_comment.go

  1package bug
  2
  3import (
  4	"encoding/json"
  5	"fmt"
  6
  7	"github.com/MichaelMure/git-bug/identity"
  8	"github.com/MichaelMure/git-bug/util/git"
  9	"github.com/MichaelMure/git-bug/util/text"
 10	"github.com/MichaelMure/git-bug/util/timestamp"
 11)
 12
 13var _ Operation = &AddCommentOperation{}
 14
 15// AddCommentOperation will add a new comment in the bug
 16type AddCommentOperation struct {
 17	OpBase
 18	Message string
 19	// TODO: change for a map[string]util.hash to store the filename ?
 20	Files []git.Hash
 21}
 22
 23func (op *AddCommentOperation) base() *OpBase {
 24	return &op.OpBase
 25}
 26
 27func (op *AddCommentOperation) Hash() (git.Hash, error) {
 28	return hashOperation(op)
 29}
 30
 31func (op *AddCommentOperation) Apply(snapshot *Snapshot) {
 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	comment := Comment{
 40		id:       string(hash),
 41		Message:  op.Message,
 42		Author:   op.Author,
 43		Files:    op.Files,
 44		UnixTime: timestamp.Timestamp(op.UnixTime),
 45	}
 46
 47	snapshot.Comments = append(snapshot.Comments, comment)
 48
 49	item := &AddCommentTimelineItem{
 50		CommentTimelineItem: NewCommentTimelineItem(hash, comment),
 51	}
 52
 53	snapshot.Timeline = append(snapshot.Timeline, item)
 54}
 55
 56func (op *AddCommentOperation) GetFiles() []git.Hash {
 57	return op.Files
 58}
 59
 60func (op *AddCommentOperation) Validate() error {
 61	if err := opBaseValidate(op, AddCommentOp); err != nil {
 62		return err
 63	}
 64
 65	if !text.Safe(op.Message) {
 66		return fmt.Errorf("message is not fully printable")
 67	}
 68
 69	return nil
 70}
 71
 72// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
 73// MarshalJSON
 74func (op *AddCommentOperation) MarshalJSON() ([]byte, error) {
 75	base, err := json.Marshal(op.OpBase)
 76	if err != nil {
 77		return nil, err
 78	}
 79
 80	// revert back to a flat map to be able to add our own fields
 81	var data map[string]interface{}
 82	if err := json.Unmarshal(base, &data); err != nil {
 83		return nil, err
 84	}
 85
 86	data["message"] = op.Message
 87	data["files"] = op.Files
 88
 89	return json.Marshal(data)
 90}
 91
 92// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
 93// MarshalJSON
 94func (op *AddCommentOperation) UnmarshalJSON(data []byte) error {
 95	// Unmarshal OpBase and the op separately
 96
 97	base := OpBase{}
 98	err := json.Unmarshal(data, &base)
 99	if err != nil {
100		return err
101	}
102
103	aux := struct {
104		Message string     `json:"message"`
105		Files   []git.Hash `json:"files"`
106	}{}
107
108	err = json.Unmarshal(data, &aux)
109	if err != nil {
110		return err
111	}
112
113	op.OpBase = base
114	op.Message = aux.Message
115	op.Files = aux.Files
116
117	return nil
118}
119
120// Sign post method for gqlgen
121func (op *AddCommentOperation) IsAuthored() {}
122
123func NewAddCommentOp(author identity.Interface, unixTime int64, message string, files []git.Hash) *AddCommentOperation {
124	return &AddCommentOperation{
125		OpBase:  newOpBase(AddCommentOp, author, unixTime),
126		Message: message,
127		Files:   files,
128	}
129}
130
131// CreateTimelineItem replace a AddComment operation in the Timeline and hold its edition history
132type AddCommentTimelineItem struct {
133	CommentTimelineItem
134}
135
136// Convenience function to apply the operation
137func AddComment(b Interface, author identity.Interface, unixTime int64, message string) (*AddCommentOperation, error) {
138	return AddCommentWithFiles(b, author, unixTime, message, nil)
139}
140
141func AddCommentWithFiles(b Interface, author identity.Interface, unixTime int64, message string, files []git.Hash) (*AddCommentOperation, error) {
142	addCommentOp := NewAddCommentOp(author, unixTime, message, files)
143	if err := addCommentOp.Validate(); err != nil {
144		return nil, err
145	}
146	b.Append(addCommentOp)
147	return addCommentOp, nil
148}