op_edit_comment.go

  1package bug
  2
  3import (
  4	"encoding/json"
  5	"fmt"
  6
  7	"github.com/pkg/errors"
  8
  9	"github.com/MichaelMure/git-bug/entity"
 10	"github.com/MichaelMure/git-bug/identity"
 11	"github.com/MichaelMure/git-bug/util/timestamp"
 12
 13	"github.com/MichaelMure/git-bug/util/git"
 14	"github.com/MichaelMure/git-bug/util/text"
 15)
 16
 17var _ Operation = &EditCommentOperation{}
 18
 19// EditCommentOperation will change a comment in the bug
 20type EditCommentOperation struct {
 21	OpBase
 22	Target  entity.Id  `json:"target"`
 23	Message string     `json:"message"`
 24	Files   []git.Hash `json:"files"`
 25}
 26
 27func (op *EditCommentOperation) base() *OpBase {
 28	return &op.OpBase
 29}
 30
 31func (op *EditCommentOperation) Id() entity.Id {
 32	return idOperation(op)
 33}
 34
 35func (op *EditCommentOperation) Apply(snapshot *Snapshot) {
 36	// Todo: currently any message can be edited, even by a different author
 37	// crypto signature are needed.
 38
 39	snapshot.addActor(op.Author)
 40
 41	var target TimelineItem
 42
 43	for i, item := range snapshot.Timeline {
 44		if item.Id() == op.Target {
 45			target = snapshot.Timeline[i]
 46			break
 47		}
 48	}
 49
 50	if target == nil {
 51		// Target not found, edit is a no-op
 52		return
 53	}
 54
 55	comment := Comment{
 56		id:       op.Target,
 57		Message:  op.Message,
 58		Files:    op.Files,
 59		UnixTime: timestamp.Timestamp(op.UnixTime),
 60	}
 61
 62	switch target := target.(type) {
 63	case *CreateTimelineItem:
 64		target.Append(comment)
 65	case *AddCommentTimelineItem:
 66		target.Append(comment)
 67	}
 68
 69	// Updating the corresponding comment
 70
 71	for i := range snapshot.Comments {
 72		if snapshot.Comments[i].Id() == op.Target {
 73			snapshot.Comments[i].Message = op.Message
 74			snapshot.Comments[i].Files = op.Files
 75			break
 76		}
 77	}
 78}
 79
 80func (op *EditCommentOperation) GetFiles() []git.Hash {
 81	return op.Files
 82}
 83
 84func (op *EditCommentOperation) Validate() error {
 85	if err := opBaseValidate(op, EditCommentOp); err != nil {
 86		return err
 87	}
 88
 89	if err := op.Target.Validate(); err != nil {
 90		return errors.Wrap(err, "target hash is invalid")
 91	}
 92
 93	if !text.Safe(op.Message) {
 94		return fmt.Errorf("message is not fully printable")
 95	}
 96
 97	return nil
 98}
 99
100// UnmarshalJSON is a two step JSON unmarshaling
101// This workaround is necessary to avoid the inner OpBase.MarshalJSON
102// overriding the outer op's MarshalJSON
103func (op *EditCommentOperation) UnmarshalJSON(data []byte) error {
104	// Unmarshal OpBase and the op separately
105
106	base := OpBase{}
107	err := json.Unmarshal(data, &base)
108	if err != nil {
109		return err
110	}
111
112	aux := struct {
113		Target  entity.Id  `json:"target"`
114		Message string     `json:"message"`
115		Files   []git.Hash `json:"files"`
116	}{}
117
118	err = json.Unmarshal(data, &aux)
119	if err != nil {
120		return err
121	}
122
123	op.OpBase = base
124	op.Target = aux.Target
125	op.Message = aux.Message
126	op.Files = aux.Files
127
128	return nil
129}
130
131// Sign post method for gqlgen
132func (op *EditCommentOperation) IsAuthored() {}
133
134func NewEditCommentOp(author identity.Interface, unixTime int64, target entity.Id, message string, files []git.Hash) *EditCommentOperation {
135	return &EditCommentOperation{
136		OpBase:  newOpBase(EditCommentOp, author, unixTime),
137		Target:  target,
138		Message: message,
139		Files:   files,
140	}
141}
142
143// Convenience function to apply the operation
144func EditComment(b Interface, author identity.Interface, unixTime int64, target entity.Id, message string) (*EditCommentOperation, error) {
145	return EditCommentWithFiles(b, author, unixTime, target, message, nil)
146}
147
148func EditCommentWithFiles(b Interface, author identity.Interface, unixTime int64, target entity.Id, message string, files []git.Hash) (*EditCommentOperation, error) {
149	editCommentOp := NewEditCommentOp(author, unixTime, target, message, files)
150	if err := editCommentOp.Validate(); err != nil {
151		return nil, err
152	}
153	b.Append(editCommentOp)
154	return editCommentOp, nil
155}