1package bug
  2
  3import (
  4	"fmt"
  5
  6	"github.com/MichaelMure/git-bug/entity"
  7	"github.com/MichaelMure/git-bug/entity/dag"
  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 = &CreateOperation{}
 15var _ dag.OperationWithFiles = &CreateOperation{}
 16
 17// CreateOperation define the initial creation of a bug
 18type CreateOperation struct {
 19	dag.OpBase
 20	Title   string            `json:"title"`
 21	Message string            `json:"message"`
 22	Files   []repository.Hash `json:"files"`
 23}
 24
 25func (op *CreateOperation) Id() entity.Id {
 26	return dag.IdOperation(op, &op.OpBase)
 27}
 28
 29func (op *CreateOperation) Apply(snapshot *Snapshot) {
 30	// sanity check: will fail when adding a second Create
 31	if snapshot.id != "" && snapshot.id != entity.UnsetId && snapshot.id != op.Id() {
 32		return
 33	}
 34
 35	snapshot.id = op.Id()
 36
 37	snapshot.addActor(op.Author())
 38	snapshot.addParticipant(op.Author())
 39
 40	snapshot.Title = op.Title
 41
 42	comment := Comment{
 43		id:       entity.CombineIds(snapshot.Id(), op.Id()),
 44		Message:  op.Message,
 45		Author:   op.Author(),
 46		UnixTime: timestamp.Timestamp(op.UnixTime),
 47	}
 48
 49	snapshot.Comments = []Comment{comment}
 50	snapshot.Author = op.Author()
 51	snapshot.CreateTime = op.Time()
 52
 53	snapshot.Timeline = []TimelineItem{
 54		&CreateTimelineItem{
 55			CommentTimelineItem: NewCommentTimelineItem(comment),
 56		},
 57	}
 58}
 59
 60func (op *CreateOperation) GetFiles() []repository.Hash {
 61	return op.Files
 62}
 63
 64func (op *CreateOperation) Validate() error {
 65	if err := op.OpBase.Validate(op, CreateOp); err != nil {
 66		return err
 67	}
 68
 69	if text.Empty(op.Title) {
 70		return fmt.Errorf("title is empty")
 71	}
 72	if !text.SafeOneLine(op.Title) {
 73		return fmt.Errorf("title has unsafe characters")
 74	}
 75
 76	if !text.Safe(op.Message) {
 77		return fmt.Errorf("message is not fully printable")
 78	}
 79
 80	return nil
 81}
 82
 83func NewCreateOp(author identity.Interface, unixTime int64, title, message string, files []repository.Hash) *CreateOperation {
 84	return &CreateOperation{
 85		OpBase:  dag.NewOpBase(CreateOp, author, unixTime),
 86		Title:   title,
 87		Message: message,
 88		Files:   files,
 89	}
 90}
 91
 92// CreateTimelineItem replace a Create operation in the Timeline and hold its edition history
 93type CreateTimelineItem struct {
 94	CommentTimelineItem
 95}
 96
 97// IsAuthored is a sign post method for gqlgen
 98func (c *CreateTimelineItem) IsAuthored() {}
 99
100// Convenience function to apply the operation
101func Create(author identity.Interface, unixTime int64, title, message string) (*Bug, *CreateOperation, error) {
102	return CreateWithFiles(author, unixTime, title, message, nil)
103}
104
105func CreateWithFiles(author identity.Interface, unixTime int64, title, message string, files []repository.Hash) (*Bug, *CreateOperation, error) {
106	newBug := NewBug()
107	createOp := NewCreateOp(author, unixTime, title, message, files)
108
109	if err := createOp.Validate(); err != nil {
110		return nil, createOp, err
111	}
112
113	newBug.Append(createOp)
114
115	return newBug, createOp, nil
116}