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