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