diff options
Diffstat (limited to 'entities/bug/op_edit_comment.go')
-rw-r--r-- | entities/bug/op_edit_comment.go | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/entities/bug/op_edit_comment.go b/entities/bug/op_edit_comment.go new file mode 100644 index 00000000..b0897b0a --- /dev/null +++ b/entities/bug/op_edit_comment.go @@ -0,0 +1,130 @@ +package bug + +import ( + "fmt" + + "github.com/pkg/errors" + + "github.com/MichaelMure/git-bug/entities/identity" + "github.com/MichaelMure/git-bug/entity" + "github.com/MichaelMure/git-bug/entity/dag" + "github.com/MichaelMure/git-bug/repository" + "github.com/MichaelMure/git-bug/util/timestamp" + + "github.com/MichaelMure/git-bug/util/text" +) + +var _ Operation = &EditCommentOperation{} +var _ dag.OperationWithFiles = &EditCommentOperation{} + +// EditCommentOperation will change a comment in the bug +type EditCommentOperation struct { + dag.OpBase + Target entity.Id `json:"target"` + Message string `json:"message"` + Files []repository.Hash `json:"files"` +} + +func (op *EditCommentOperation) Id() entity.Id { + return dag.IdOperation(op, &op.OpBase) +} + +func (op *EditCommentOperation) Apply(snapshot *Snapshot) { + // Todo: currently any message can be edited, even by a different author + // crypto signature are needed. + + // Recreate the combined Id to match on + combinedId := entity.CombineIds(snapshot.Id(), op.Target) + + var target TimelineItem + for i, item := range snapshot.Timeline { + if item.CombinedId() == combinedId { + target = snapshot.Timeline[i] + break + } + } + + if target == nil { + // Target not found, edit is a no-op + return + } + + comment := Comment{ + combinedId: combinedId, + targetId: op.Target, + Message: op.Message, + Files: op.Files, + unixTime: timestamp.Timestamp(op.UnixTime), + } + + switch target := target.(type) { + case *CreateTimelineItem: + target.Append(comment) + case *AddCommentTimelineItem: + target.Append(comment) + default: + // somehow, the target matched on something that is not a comment + // we make the op a no-op + return + } + + snapshot.addActor(op.Author()) + + // Updating the corresponding comment + + for i := range snapshot.Comments { + if snapshot.Comments[i].CombinedId() == combinedId { + snapshot.Comments[i].Message = op.Message + snapshot.Comments[i].Files = op.Files + break + } + } +} + +func (op *EditCommentOperation) GetFiles() []repository.Hash { + return op.Files +} + +func (op *EditCommentOperation) Validate() error { + if err := op.OpBase.Validate(op, EditCommentOp); err != nil { + return err + } + + if err := op.Target.Validate(); err != nil { + return errors.Wrap(err, "target hash is invalid") + } + + if !text.Safe(op.Message) { + return fmt.Errorf("message is not fully printable") + } + + return nil +} + +func NewEditCommentOp(author identity.Interface, unixTime int64, target entity.Id, message string, files []repository.Hash) *EditCommentOperation { + return &EditCommentOperation{ + OpBase: dag.NewOpBase(EditCommentOp, author, unixTime), + Target: target, + Message: message, + Files: files, + } +} + +// EditComment is a convenience function to apply the operation +func EditComment(b Interface, author identity.Interface, unixTime int64, target entity.Id, message string, files []repository.Hash, metadata map[string]string) (*EditCommentOperation, error) { + op := NewEditCommentOp(author, unixTime, target, message, files) + for key, val := range metadata { + op.SetMetadata(key, val) + } + if err := op.Validate(); err != nil { + return nil, err + } + b.Append(op) + return op, nil +} + +// EditCreateComment is a convenience function to edit the body of a bug (the first comment) +func EditCreateComment(b Interface, author identity.Interface, unixTime int64, message string, files []repository.Hash, metadata map[string]string) (*EditCommentOperation, error) { + createOp := b.FirstOp().(*CreateOperation) + return EditComment(b, author, unixTime, createOp.Id(), message, files, metadata) +} |