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