1package bug
2
3import (
4 "encoding/json"
5 "fmt"
6
7 "github.com/MichaelMure/git-bug/entity"
8 "github.com/MichaelMure/git-bug/entity/dag"
9 "github.com/MichaelMure/git-bug/identity"
10 "github.com/MichaelMure/git-bug/repository"
11 "github.com/MichaelMure/git-bug/util/text"
12 "github.com/MichaelMure/git-bug/util/timestamp"
13)
14
15var _ Operation = &AddCommentOperation{}
16var _ dag.OperationWithFiles = &AddCommentOperation{}
17
18// AddCommentOperation will add a new comment in the bug
19type AddCommentOperation struct {
20 OpBase
21 Message string `json:"message"`
22 // TODO: change for a map[string]util.hash to store the filename ?
23 Files []repository.Hash `json:"files"`
24}
25
26func (op *AddCommentOperation) Id() entity.Id {
27 return idOperation(op, &op.OpBase)
28}
29
30func (op *AddCommentOperation) Apply(snapshot *Snapshot) {
31 snapshot.addActor(op.Author_)
32 snapshot.addParticipant(op.Author_)
33
34 commentId := entity.CombineIds(snapshot.Id(), op.Id())
35 comment := Comment{
36 id: commentId,
37 Message: op.Message,
38 Author: op.Author_,
39 Files: op.Files,
40 UnixTime: timestamp.Timestamp(op.UnixTime),
41 }
42
43 snapshot.Comments = append(snapshot.Comments, comment)
44
45 item := &AddCommentTimelineItem{
46 CommentTimelineItem: NewCommentTimelineItem(commentId, comment),
47 }
48
49 snapshot.Timeline = append(snapshot.Timeline, item)
50}
51
52func (op *AddCommentOperation) GetFiles() []repository.Hash {
53 return op.Files
54}
55
56func (op *AddCommentOperation) Validate() error {
57 if err := op.OpBase.Validate(op, AddCommentOp); err != nil {
58 return err
59 }
60
61 if !text.Safe(op.Message) {
62 return fmt.Errorf("message is not fully printable")
63 }
64
65 return nil
66}
67
68// UnmarshalJSON is a two step JSON unmarshalling
69// This workaround is necessary to avoid the inner OpBase.MarshalJSON
70// overriding the outer op's MarshalJSON
71func (op *AddCommentOperation) UnmarshalJSON(data []byte) error {
72 // Unmarshal OpBase and the op separately
73
74 base := OpBase{}
75 err := json.Unmarshal(data, &base)
76 if err != nil {
77 return err
78 }
79
80 aux := struct {
81 Message string `json:"message"`
82 Files []repository.Hash `json:"files"`
83 }{}
84
85 err = json.Unmarshal(data, &aux)
86 if err != nil {
87 return err
88 }
89
90 op.OpBase = base
91 op.Message = aux.Message
92 op.Files = aux.Files
93
94 return nil
95}
96
97// Sign post method for gqlgen
98func (op *AddCommentOperation) IsAuthored() {}
99
100func NewAddCommentOp(author identity.Interface, unixTime int64, message string, files []repository.Hash) *AddCommentOperation {
101 return &AddCommentOperation{
102 OpBase: newOpBase(AddCommentOp, author, unixTime),
103 Message: message,
104 Files: files,
105 }
106}
107
108// CreateTimelineItem replace a AddComment operation in the Timeline and hold its edition history
109type AddCommentTimelineItem struct {
110 CommentTimelineItem
111}
112
113// Sign post method for gqlgen
114func (a *AddCommentTimelineItem) IsAuthored() {}
115
116// Convenience function to apply the operation
117func AddComment(b Interface, author identity.Interface, unixTime int64, message string) (*AddCommentOperation, error) {
118 return AddCommentWithFiles(b, author, unixTime, message, nil)
119}
120
121func AddCommentWithFiles(b Interface, author identity.Interface, unixTime int64, message string, files []repository.Hash) (*AddCommentOperation, error) {
122 addCommentOp := NewAddCommentOp(author, unixTime, message, files)
123 if err := addCommentOp.Validate(); err != nil {
124 return nil, err
125 }
126 b.Append(addCommentOp)
127 return addCommentOp, nil
128}