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