1package bug
2
3import (
4 "strings"
5
6 "github.com/dustin/go-humanize"
7
8 "github.com/MichaelMure/git-bug/entity"
9 "github.com/MichaelMure/git-bug/identity"
10 "github.com/MichaelMure/git-bug/repository"
11 "github.com/MichaelMure/git-bug/util/timestamp"
12)
13
14// Comment represent a comment in a Bug
15type Comment struct {
16 id entity.Id
17 Author identity.Interface
18 Message string
19 Files []repository.Hash
20
21 // Creation time of the comment.
22 // Should be used only for human display, never for ordering as we can't rely on it in a distributed system.
23 UnixTime timestamp.Timestamp
24}
25
26// Id return the Comment identifier
27func (c Comment) Id() entity.Id {
28 if c.id == "" {
29 // simply panic as it would be a coding error
30 // (using an id of an identity not stored yet)
31 panic("no id yet")
32 }
33 return c.id
34}
35
36const compiledCommentIdFormat = "BCBCBCBBBCBBBBCBBBBCBBBBCBBBBCBBBBCBBBBC"
37
38// DeriveCommentId compute a merged Id for a comment holding information from
39// both the Bug's Id and the Comment's Id. This allow to later find efficiently
40// a Comment because we can access the bug directly instead of searching for a
41// Bug that has a Comment matching the Id.
42//
43// To allow the use of an arbitrary length prefix of this merged Id, Ids from Bug
44// and Comment are interleaved with this irregular pattern to give the best chance
45// to find the Comment even with a 7 character prefix.
46//
47// A complete merged Id hold 30 characters for the Bug and 10 for the Comment,
48// which give a key space of 36^30 for the Bug (~5 * 10^46) and 36^10 for the
49// Comment (~3 * 10^15). This asymmetry assume a reasonable number of Comment
50// within a Bug, while still allowing for a vast key space for Bug (that is, a
51// globally merged bug database) with a low risk of collision.
52func DeriveCommentId(bugId entity.Id, commentId entity.Id) entity.Id {
53 var id strings.Builder
54 for _, char := range compiledCommentIdFormat {
55 if char == 'B' {
56 id.WriteByte(bugId[0])
57 bugId = bugId[1:]
58 } else {
59 id.WriteByte(commentId[0])
60 commentId = commentId[1:]
61 }
62 }
63 return entity.Id(id.String())
64}
65
66func SplitCommentId(prefix string) (bugPrefix string, commentPrefix string) {
67 var bugIdPrefix strings.Builder
68 var commentIdPrefix strings.Builder
69
70 for i, char := range prefix {
71 if compiledCommentIdFormat[i] == 'B' {
72 bugIdPrefix.WriteRune(char)
73 } else {
74 commentIdPrefix.WriteRune(char)
75 }
76 }
77 return bugIdPrefix.String(), commentIdPrefix.String()
78}
79
80// FormatTimeRel format the UnixTime of the comment for human consumption
81func (c Comment) FormatTimeRel() string {
82 return humanize.Time(c.UnixTime.Time())
83}
84
85func (c Comment) FormatTime() string {
86 return c.UnixTime.Time().Format("Mon Jan 2 15:04:05 2006 +0200")
87}
88
89// Sign post method for gqlgen
90func (c Comment) IsAuthored() {}