1package board
  2
  3import (
  4	"fmt"
  5
  6	"github.com/git-bug/git-bug/entities/identity"
  7	"github.com/git-bug/git-bug/entity"
  8	"github.com/git-bug/git-bug/entity/dag"
  9	"github.com/git-bug/git-bug/repository"
 10	"github.com/git-bug/git-bug/util/text"
 11	"github.com/git-bug/git-bug/util/timestamp"
 12)
 13
 14var _ Operation = &AddItemDraftOperation{}
 15
 16type AddItemDraftOperation struct {
 17	dag.OpBase
 18	ColumnId entity.Id         `json:"column"`
 19	Title    string            `json:"title"`
 20	Message  string            `json:"message"`
 21	Files    []repository.Hash `json:"files"`
 22}
 23
 24func (op *AddItemDraftOperation) Id() entity.Id {
 25	return dag.IdOperation(op, &op.OpBase)
 26}
 27
 28func (op *AddItemDraftOperation) GetFiles() []repository.Hash {
 29	return op.Files
 30}
 31
 32func (op *AddItemDraftOperation) Validate() error {
 33	if err := op.OpBase.Validate(op, AddItemDraftOp); err != nil {
 34		return err
 35	}
 36
 37	if err := op.ColumnId.Validate(); err != nil {
 38		return err
 39	}
 40
 41	if text.Empty(op.Title) {
 42		return fmt.Errorf("title is empty")
 43	}
 44	if !text.SafeOneLine(op.Title) {
 45		return fmt.Errorf("title has unsafe characters")
 46	}
 47
 48	if !text.Safe(op.Message) {
 49		return fmt.Errorf("message is not fully printable")
 50	}
 51
 52	for _, file := range op.Files {
 53		if !file.IsValid() {
 54			return fmt.Errorf("invalid file hash")
 55		}
 56	}
 57
 58	return nil
 59}
 60
 61func (op *AddItemDraftOperation) Apply(snapshot *Snapshot) {
 62	// Recreate the combined Id to match on
 63	combinedId := entity.CombineIds(snapshot.Id(), op.ColumnId)
 64
 65	// search the column
 66	for _, column := range snapshot.Columns {
 67		if column.CombinedId == combinedId {
 68			column.Items = append(column.Items, &Draft{
 69				combinedId: entity.CombineIds(snapshot.id, op.Id()),
 70				author:     op.Author(),
 71				title:      op.Title,
 72				Message:    op.Message,
 73				unixTime:   timestamp.Timestamp(op.UnixTime),
 74			})
 75
 76			snapshot.addParticipant(op.Author())
 77			return
 78		}
 79	}
 80}
 81
 82func NewAddItemDraftOp(author identity.Interface, unixTime int64, columnId entity.Id, title, message string, files []repository.Hash) *AddItemDraftOperation {
 83	return &AddItemDraftOperation{
 84		OpBase:   dag.NewOpBase(AddItemDraftOp, author, unixTime),
 85		ColumnId: columnId,
 86		Title:    title,
 87		Message:  message,
 88		Files:    files,
 89	}
 90}
 91
 92// AddItemDraft is a convenience function to add a draft item to a Board
 93func AddItemDraft(b ReadWrite, author identity.Interface, unixTime int64, columnId entity.Id, title, message string, files []repository.Hash, metadata map[string]string) (entity.CombinedId, *AddItemDraftOperation, error) {
 94	op := NewAddItemDraftOp(author, unixTime, columnId, title, message, files)
 95	for key, val := range metadata {
 96		op.SetMetadata(key, val)
 97	}
 98	if err := op.Validate(); err != nil {
 99		return entity.UnsetCombinedId, nil, err
100	}
101	b.Append(op)
102	return entity.CombineIds(b.Id(), op.Id()), op, nil
103}