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