op_create.go

  1package bug
  2
  3import (
  4	"encoding/json"
  5	"fmt"
  6	"strings"
  7
  8	"github.com/MichaelMure/git-bug/identity"
  9	"github.com/MichaelMure/git-bug/util/git"
 10	"github.com/MichaelMure/git-bug/util/text"
 11	"github.com/MichaelMure/git-bug/util/timestamp"
 12)
 13
 14var _ Operation = &CreateOperation{}
 15
 16// CreateOperation define the initial creation of a bug
 17type CreateOperation struct {
 18	OpBase
 19	Title   string
 20	Message string
 21	Files   []git.Hash
 22}
 23
 24func (op *CreateOperation) base() *OpBase {
 25	return &op.OpBase
 26}
 27
 28func (op *CreateOperation) Hash() (git.Hash, error) {
 29	return hashOperation(op)
 30}
 31
 32func (op *CreateOperation) Apply(snapshot *Snapshot) {
 33	snapshot.addActor(op.Author)
 34	snapshot.addParticipant(op.Author)
 35
 36	hash, err := op.Hash()
 37	if err != nil {
 38		// Should never error unless a programming error happened
 39		// (covered in OpBase.Validate())
 40		panic(err)
 41	}
 42
 43	snapshot.Title = op.Title
 44
 45	comment := Comment{
 46		id:       string(hash),
 47		Message:  op.Message,
 48		Author:   op.Author,
 49		UnixTime: timestamp.Timestamp(op.UnixTime),
 50	}
 51
 52	snapshot.Comments = []Comment{comment}
 53	snapshot.Author = op.Author
 54	snapshot.CreatedAt = op.Time()
 55
 56	snapshot.Timeline = []TimelineItem{
 57		&CreateTimelineItem{
 58			CommentTimelineItem: NewCommentTimelineItem(hash, comment),
 59		},
 60	}
 61}
 62
 63func (op *CreateOperation) GetFiles() []git.Hash {
 64	return op.Files
 65}
 66
 67func (op *CreateOperation) Validate() error {
 68	if err := opBaseValidate(op, CreateOp); err != nil {
 69		return err
 70	}
 71
 72	if text.Empty(op.Title) {
 73		return fmt.Errorf("title is empty")
 74	}
 75
 76	if strings.Contains(op.Title, "\n") {
 77		return fmt.Errorf("title should be a single line")
 78	}
 79
 80	if !text.Safe(op.Title) {
 81		return fmt.Errorf("title is not fully printable")
 82	}
 83
 84	if !text.Safe(op.Message) {
 85		return fmt.Errorf("message is not fully printable")
 86	}
 87
 88	return nil
 89}
 90
 91// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
 92// MarshalJSON
 93func (op *CreateOperation) MarshalJSON() ([]byte, error) {
 94	base, err := json.Marshal(op.OpBase)
 95	if err != nil {
 96		return nil, err
 97	}
 98
 99	// revert back to a flat map to be able to add our own fields
100	var data map[string]interface{}
101	if err := json.Unmarshal(base, &data); err != nil {
102		return nil, err
103	}
104
105	data["title"] = op.Title
106	data["message"] = op.Message
107	data["files"] = op.Files
108
109	return json.Marshal(data)
110}
111
112// Workaround to avoid the inner OpBase.MarshalJSON overriding the outer op
113// MarshalJSON
114func (op *CreateOperation) UnmarshalJSON(data []byte) error {
115	// Unmarshal OpBase and the op separately
116
117	base := OpBase{}
118	err := json.Unmarshal(data, &base)
119	if err != nil {
120		return err
121	}
122
123	aux := struct {
124		Title   string     `json:"title"`
125		Message string     `json:"message"`
126		Files   []git.Hash `json:"files"`
127	}{}
128
129	err = json.Unmarshal(data, &aux)
130	if err != nil {
131		return err
132	}
133
134	op.OpBase = base
135	op.Title = aux.Title
136	op.Message = aux.Message
137	op.Files = aux.Files
138
139	return nil
140}
141
142// Sign post method for gqlgen
143func (op *CreateOperation) IsAuthored() {}
144
145func NewCreateOp(author identity.Interface, unixTime int64, title, message string, files []git.Hash) *CreateOperation {
146	return &CreateOperation{
147		OpBase:  newOpBase(CreateOp, author, unixTime),
148		Title:   title,
149		Message: message,
150		Files:   files,
151	}
152}
153
154// CreateTimelineItem replace a Create operation in the Timeline and hold its edition history
155type CreateTimelineItem struct {
156	CommentTimelineItem
157}
158
159// Sign post method for gqlgen
160func (c *CreateTimelineItem) IsAuthored() {}
161
162// Convenience function to apply the operation
163func Create(author identity.Interface, unixTime int64, title, message string) (*Bug, *CreateOperation, error) {
164	return CreateWithFiles(author, unixTime, title, message, nil)
165}
166
167func CreateWithFiles(author identity.Interface, unixTime int64, title, message string, files []git.Hash) (*Bug, *CreateOperation, error) {
168	newBug := NewBug()
169	createOp := NewCreateOp(author, unixTime, title, message, files)
170
171	if err := createOp.Validate(); err != nil {
172		return nil, createOp, err
173	}
174
175	newBug.Append(createOp)
176
177	return newBug, createOp, nil
178}