1
2 package util
3
4 import (
5 "fmt"
6 "html/template"
7 "math"
8 "net/http"
9 "net/mail"
10 "regexp"
11 "sort"
12 "strconv"
13 "strings"
14 "time"
15
16 "golang.org/x/exp/constraints"
17 )
18
19 const NewDirPermission = 0755
20 const NewFilePermission = 0644
21
22 var (
23 AlphaNumericAndSymbols = regexp.MustCompile(`^[0-9A-Za-z_\-]+$`)
24 FileNamePattern = regexp.MustCompile(`^[0-9A-Za-z_\-.]+$`)
25 FilePathPattern = regexp.MustCompile(`^[0-9A-Za-z_\-/.]+$`)
26
27 QuotePattern = regexp.MustCompile(`^>(.*)$`)
28
29 RefLinkPattern = regexp.MustCompile(`>>([0-9]+)`)
30 BoardLinkPattern = regexp.MustCompile(`>>>\/([0-9A-Za-z_-]+)?\/?`)
31
32 URLPattern = regexp.MustCompile(`(?i)(((f|ht)tp(s)?:\/\/)[-a-zA-Zа-яА-Я()0-9@%\!_+.,~#?&;:|\'\/=]+)`)
33 FixURLPattern1 = regexp.MustCompile(`(?i)\(\<a href\=\"(.*)\)"\ target\=\"\_blank\">(.*)\)\<\/a>`)
34 FixURLPattern2 = regexp.MustCompile(`(?i)\<a href\=\"(.*)\."\ target\=\"\_blank\">(.*)\.\<\/a>`)
35 FixURLPattern3 = regexp.MustCompile(`(?i)\<a href\=\"(.*)\,"\ target\=\"\_blank\">(.*)\,\<\/a>`)
36 )
37
38 func ParseInt(v string) int {
39 i, err := strconv.Atoi(v)
40 if err == nil && i > 0 {
41 return i
42 }
43 return 0
44 }
45
46 func ParseInt64(v string) int64 {
47 i, err := strconv.ParseInt(v, 10, 64)
48 if err == nil && i > 0 {
49 return i
50 }
51 return 0
52 }
53
54 func ParseFloat(v string) float64 {
55 i, err := strconv.ParseFloat(v, 64)
56 if err == nil && i > 0 {
57 return i
58 }
59 return 0
60 }
61
62 func FormString(r *http.Request, key string) string {
63 return strings.TrimSpace(r.FormValue(key))
64 }
65
66 func FormMultiString(r *http.Request, key string) []string {
67 formKeys := make([]string, len(r.Form))
68 var i int
69 for key := range r.Form {
70 formKeys[i] = key
71 i++
72 }
73 sort.Slice(formKeys, func(i, j int) bool {
74 return formKeys[i] < formKeys[j]
75 })
76 var values []string
77 for _, formKey := range formKeys {
78 formValues := r.Form[formKey]
79 if strings.HasPrefix(formKey, key+"_") {
80 for _, v := range formValues {
81 if strings.TrimSpace(v) == "" {
82 continue
83 }
84 values = append(values, v)
85 }
86 }
87 }
88 return values
89 }
90
91 func FormInt(r *http.Request, key string) int {
92 v, err := strconv.Atoi(FormString(r, key))
93 if err == nil && v >= 0 {
94 return v
95 }
96 return 0
97 }
98
99 func FormInt64(r *http.Request, key string) int64 {
100 v, err := strconv.ParseInt(FormString(r, key), 10, 64)
101 if err == nil && v >= 0 {
102 return v
103 }
104 return 0
105 }
106
107 func FormNegInt(r *http.Request, key string) int {
108 v, err := strconv.Atoi(FormString(r, key))
109 if err == nil {
110 return v
111 }
112 return 0
113 }
114
115 func FormBool(r *http.Request, key string) bool {
116 return FormInt(r, key) == 1
117 }
118
119 func FormRange[T constraints.Integer](r *http.Request, key string, min T, max T) T {
120 v := FormNegInt(r, key)
121 if v >= int(min) && v <= int(max) {
122 return T(v)
123 }
124 return min
125 }
126
127 func PathInt(r *http.Request, prefix string) int {
128 pathValue := PathString(r, prefix)
129 if pathValue != "" {
130 v, err := strconv.Atoi(pathValue)
131 if err == nil && v > 0 {
132 return v
133 }
134 }
135 return 0
136 }
137
138 func PathString(r *http.Request, prefix string) string {
139 if !strings.HasPrefix(r.URL.Path, prefix) {
140 return ""
141 }
142 return strings.TrimPrefix(r.URL.Path, prefix)
143 }
144
145 func ParseEmail(address string) string {
146 a, err := mail.ParseAddress(address)
147 if err != nil {
148 return ""
149 }
150 return a.Address
151 }
152
153 func MIMEToExt(mimeType string) string {
154 switch mimeType {
155 case "image/jpeg", "image/pjpeg":
156 return "jpg"
157 case "image/gif":
158 return "gif"
159 case "image/png":
160 return "png"
161 default:
162 return ""
163 }
164 }
165
166 func FormatTimestamp(timestamp int64) template.HTML {
167 return template.HTML(time.Unix(timestamp, 0).Format("2006/01/02<wbr>(Mon)<wbr>15:04:05"))
168 }
169
170 func FormatRawTimestamp(timestamp int64) string {
171 return time.Unix(timestamp, 0).Format("2006/01/02(Mon)15:04:05")
172 }
173
174 func FormatFileSize(size int64) string {
175 v := float64(size)
176 for _, unit := range []string{"", "K", "M", "G", "T", "P", "E", "Z"} {
177 if math.Abs(v) < 1024.0 {
178 return fmt.Sprintf("%.0f%sB", v, unit)
179 }
180 v /= 1024.0
181 }
182 return fmt.Sprintf("%.0fYB", v)
183 }
184
185 func FormatDuration(d time.Duration) string {
186 var out string
187 if d.Hours() >= 24*365 {
188 out += fmt.Sprintf("%.0fy ", d.Hours()/(24*365))
189 d %= 24 * time.Hour * 365
190 }
191 if d.Hours() >= 24 {
192 out += fmt.Sprintf("%.0fd ", d.Hours()/24)
193 d %= 24 * time.Hour
194 }
195 return out + fmt.Sprintf("%s", d.Truncate(time.Second))
196 }
197
View as plain text