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