generated from fun-stack/example
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathstory-details.go
151 lines (124 loc) · 3.34 KB
/
story-details.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package main
import (
"database/sql"
"fmt"
"net/url"
"strings"
"time"
"github.com/weppos/publicsuffix-go/publicsuffix"
humanize "github.com/dustin/go-humanize"
)
type Story struct {
ID int
By string
Title string
URL string
SubmissionTime int64
OriginalSubmissionTime int64
AgeApprox int64
Score int
Comments int
CumulativeUpvotes int
CumulativeExpectedUpvotes float64
UpvoteRate float64
TopRank sql.NullInt32
QNRank sql.NullInt32
RawRank sql.NullInt32
Job bool
Flagged bool
Dupe bool
Archived bool
}
type PageFlags struct {
IsHNTopPage bool
IsFairPage bool
IsUpvoteratePage bool
IsBestUpvoteratePage bool
IsStatsPage bool
IsPenaltiesPage bool
IsBoostsPage bool
IsResubmissionsPage bool
IsRawPage bool
}
// StoryTemplateData combines a Story with page context for use in templates
type StoryTemplateData struct {
Story // embed Story instead of having it as a named field
PageFlags
}
// Page-specific methods
func (s PageFlags) IsAlternativeFrontPage() bool {
return s.IsHNTopPage || s.IsRawPage || s.IsPenaltiesPage || s.IsBoostsPage || s.IsResubmissionsPage || s.IsFairPage || s.IsUpvoteratePage || s.IsBestUpvoteratePage
}
func (s Story) AgeString() string {
// return humanize.Time(time.Unix(int64(time.Now().Unix()-s.AgeApprox), 0))
return humanize.Time(time.Unix(int64(time.Now().Unix()-s.AgeApprox), 0))
}
func (s Story) OriginalAgeString() string {
return humanize.Time(time.Unix(s.OriginalSubmissionTime, 0))
}
func (s Story) IsResubmitted() bool {
return s.SubmissionTime != s.OriginalSubmissionTime
}
func (s Story) UpvoteRateString() string {
return fmt.Sprintf("%.2f", s.UpvoteRate)
}
func (s Story) RankDiff() int32 {
if !s.RawRank.Valid {
return 0
}
rawRank := s.RawRank.Int32
topRank := s.TopRank.Int32
if !s.TopRank.Valid {
topRank = 91
}
return rawRank - topRank
}
func abs(a int32) int32 {
if a >= 0 {
return a
}
return -a
}
func (s Story) RankDiffAbs() int32 {
return abs(s.RankDiff())
}
func (s Story) OverRanked() bool {
return s.RankDiff() > 0
}
func (s Story) UnderRanked() bool {
return s.RankDiff() < 0
}
func (s Story) Domain() string {
u, err := url.Parse(s.URL)
if err != nil {
return ""
}
domain, err := publicsuffix.Domain(u.Host)
if err != nil {
return ""
}
// some domains are treated specially:
// twitter.com/x
// github.com/x
// x.substack.com
// x.notion.site
// x.dreamhosters.com
if u.Host == "news.ycombinator.com" {
return ""
}
if domain == "twitter.com" || domain == "github.com" {
// keep first part of path
return domain + "/" + strings.Split(u.Path, "/")[1]
}
if domain == "substack.com" || domain == "notion.site" || domain == "dreamhosters.com" {
// keep subdomain
return strings.Split(u.Host, ".")[0] + "." + domain
}
return domain
}
func (s Story) ISOTimestamp() string {
return time.Unix(s.SubmissionTime, 0).UTC().Format("2006-01-02T15:04:05")
}
func (s Story) OriginalISOTimestamp() string {
return time.Unix(s.OriginalSubmissionTime, 0).UTC().Format("2006-01-02T15:04:05")
}