1package bug
2
3import (
4 "fmt"
5 "strings"
6
7 "github.com/MichaelMure/git-bug/identity"
8
9 "github.com/MichaelMure/git-bug/util/git"
10 "github.com/MichaelMure/git-bug/util/text"
11)
12
13var _ Operation = &SetTitleOperation{}
14
15// SetTitleOperation will change the title of a bug
16type SetTitleOperation struct {
17 OpBase
18 Title string `json:"title"`
19 Was string `json:"was"`
20}
21
22func (op *SetTitleOperation) base() *OpBase {
23 return &op.OpBase
24}
25
26func (op *SetTitleOperation) Hash() (git.Hash, error) {
27 return hashOperation(op)
28}
29
30func (op *SetTitleOperation) Apply(snapshot *Snapshot) {
31 snapshot.Title = op.Title
32
33 hash, err := op.Hash()
34 if err != nil {
35 // Should never error unless a programming error happened
36 // (covered in OpBase.Validate())
37 panic(err)
38 }
39
40 item := &SetTitleTimelineItem{
41 hash: hash,
42 Author: op.Author,
43 UnixTime: Timestamp(op.UnixTime),
44 Title: op.Title,
45 Was: op.Was,
46 }
47
48 snapshot.Timeline = append(snapshot.Timeline, item)
49}
50
51func (op *SetTitleOperation) Validate() error {
52 if err := opBaseValidate(op, SetTitleOp); err != nil {
53 return err
54 }
55
56 if text.Empty(op.Title) {
57 return fmt.Errorf("title is empty")
58 }
59
60 if strings.Contains(op.Title, "\n") {
61 return fmt.Errorf("title should be a single line")
62 }
63
64 if !text.Safe(op.Title) {
65 return fmt.Errorf("title should be fully printable")
66 }
67
68 if strings.Contains(op.Was, "\n") {
69 return fmt.Errorf("previous title should be a single line")
70 }
71
72 if !text.Safe(op.Was) {
73 return fmt.Errorf("previous title should be fully printable")
74 }
75
76 return nil
77}
78
79// Sign post method for gqlgen
80func (op *SetTitleOperation) IsAuthored() {}
81
82func NewSetTitleOp(author identity.Interface, unixTime int64, title string, was string) *SetTitleOperation {
83 return &SetTitleOperation{
84 OpBase: newOpBase(SetTitleOp, author, unixTime),
85 Title: title,
86 Was: was,
87 }
88}
89
90type SetTitleTimelineItem struct {
91 hash git.Hash
92 Author identity.Interface
93 UnixTime Timestamp
94 Title string
95 Was string
96}
97
98func (s SetTitleTimelineItem) Hash() git.Hash {
99 return s.hash
100}
101
102// Convenience function to apply the operation
103func SetTitle(b Interface, author identity.Interface, unixTime int64, title string) (*SetTitleOperation, error) {
104 it := NewOperationIterator(b)
105
106 var lastTitleOp Operation
107 for it.Next() {
108 op := it.Value()
109 if op.base().OperationType == SetTitleOp {
110 lastTitleOp = op
111 }
112 }
113
114 var was string
115 if lastTitleOp != nil {
116 was = lastTitleOp.(*SetTitleOperation).Title
117 } else {
118 was = b.FirstOp().(*CreateOperation).Title
119 }
120
121 setTitleOp := NewSetTitleOp(author, unixTime, title, was)
122
123 if err := setTitleOp.Validate(); err != nil {
124 return nil, err
125 }
126
127 b.Append(setTitleOp)
128 return setTitleOp, nil
129}