op_edit_comment.go

  1package bug
  2
  3import (
  4	"fmt"
  5
  6	"github.com/pkg/errors"
  7
  8	"github.com/git-bug/git-bug/entities/identity"
  9	"github.com/git-bug/git-bug/entity"
 10	"github.com/git-bug/git-bug/entity/dag"
 11	"github.com/git-bug/git-bug/repository"
 12	"github.com/git-bug/git-bug/util/timestamp"
 13
 14	"github.com/git-bug/git-bug/util/text"
 15)
 16
 17var _ Operation = &EditCommentOperation{}
 18var _ dag.OperationWithFiles = &EditCommentOperation{}
 19
 20// EditCommentOperation will change a comment in the bug
 21type EditCommentOperation struct {
 22	dag.OpBase
 23	Target  entity.Id         `json:"target"`
 24	Message string            `json:"message"`
 25	Files   []repository.Hash `json:"files"`
 26}
 27
 28func (op *EditCommentOperation) Id() entity.Id {
 29	return dag.IdOperation(op, &op.OpBase)
 30}
 31
 32func (op *EditCommentOperation) Apply(snapshot *Snapshot) {
 33	// Todo: currently any message can be edited, even by a different author
 34	// crypto signature are needed.
 35
 36	// Recreate the combined Id to match on
 37	combinedId := entity.CombineIds(snapshot.Id(), op.Target)
 38
 39	var target TimelineItem
 40	for i, item := range snapshot.Timeline {
 41		if item.CombinedId() == combinedId {
 42			target = snapshot.Timeline[i]
 43			break
 44		}
 45	}
 46
 47	if target == nil {
 48		// Target not found, edit is a no-op
 49		return
 50	}
 51
 52	comment := Comment{
 53		combinedId: combinedId,
 54		targetId:   op.Target,
 55		Message:    op.Message,
 56		Files:      op.Files,
 57		unixTime:   timestamp.Timestamp(op.UnixTime),
 58	}
 59
 60	switch target := target.(type) {
 61	case *CreateTimelineItem:
 62		target.Append(comment)
 63	case *AddCommentTimelineItem:
 64		target.Append(comment)
 65	default:
 66		// somehow, the target matched on something that is not a comment
 67		// we make the op a no-op
 68		return
 69	}
 70
 71	snapshot.addActor(op.Author())
 72
 73	// Updating the corresponding comment
 74
 75	for i := range snapshot.Comments {
 76		if snapshot.Comments[i].CombinedId() == combinedId {
 77			snapshot.Comments[i].Message = op.Message
 78			snapshot.Comments[i].Files = op.Files
 79			break
 80		}
 81	}
 82}
 83
 84func (op *EditCommentOperation) GetFiles() []repository.Hash {
 85	return op.Files
 86}
 87
 88func (op *EditCommentOperation) Validate() error {
 89	if err := op.OpBase.Validate(op, EditCommentOp); err != nil {
 90		return err
 91	}
 92
 93	if err := op.Target.Validate(); err != nil {
 94		return errors.Wrap(err, "target hash is invalid")
 95	}
 96
 97	if !text.Safe(op.Message) {
 98		return fmt.Errorf("message is not fully printable")
 99	}
100
101	for _, file := range op.Files {
102		if !file.IsValid() {
103			return fmt.Errorf("invalid file hash")
104		}
105	}
106
107	return nil
108}
109
110func NewEditCommentOp(author identity.Interface, unixTime int64, target entity.Id, message string, files []repository.Hash) *EditCommentOperation {
111	return &EditCommentOperation{
112		OpBase:  dag.NewOpBase(EditCommentOp, author, unixTime),
113		Target:  target,
114		Message: message,
115		Files:   files,
116	}
117}
118
119// EditComment is a convenience function to apply the operation
120func EditComment(b Interface, author identity.Interface, unixTime int64, target entity.Id, message string, files []repository.Hash, metadata map[string]string) (entity.CombinedId, *EditCommentOperation, error) {
121	op := NewEditCommentOp(author, unixTime, target, message, files)
122	for key, val := range metadata {
123		op.SetMetadata(key, val)
124	}
125	if err := op.Validate(); err != nil {
126		return entity.UnsetCombinedId, nil, err
127	}
128	b.Append(op)
129	return entity.CombineIds(b.Id(), target), op, nil
130}
131
132// EditCreateComment is a convenience function to edit the body of a bug (the first comment)
133func EditCreateComment(b Interface, author identity.Interface, unixTime int64, message string, files []repository.Hash, metadata map[string]string) (entity.CombinedId, *EditCommentOperation, error) {
134	createOp := b.FirstOp().(*CreateOperation)
135	return EditComment(b, author, unixTime, createOp.Id(), message, files, metadata)
136}