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