...
1 package model
2
3 import (
4 "fmt"
5 "strings"
6
7 . "codeberg.org/tslocum/sriracha/util"
8 )
9
10 type BoardType int
11
12
13 const (
14 TypeImageboard BoardType = 0
15 TypeForum BoardType = 1
16 )
17
18 func FormatBoardType(t BoardType) string {
19 switch t {
20 case TypeImageboard:
21 return "Imageboard"
22 case TypeForum:
23 return "Forum"
24 default:
25 return "Unknown"
26 }
27 }
28
29 type BoardHide int
30
31 const (
32 HideNowhere BoardHide = 0
33 HideIndex BoardHide = 1
34 HideOverboard BoardHide = 2
35 HideEverywhere BoardHide = 3
36 )
37
38 func FormatBoardHide(a BoardHide) string {
39 switch a {
40 case HideNowhere:
41 return "Show everywhere"
42 case HideIndex:
43 return "Hide from index"
44 case HideOverboard:
45 return "Hide from overboard"
46 case HideEverywhere:
47 return "Hide everywhere"
48 default:
49 return "Unknown"
50 }
51 }
52
53 type BoardLock int
54
55
56 const (
57 LockNone BoardLock = 0
58 LockThread BoardLock = 1
59 LockPost BoardLock = 2
60 LockStaff BoardLock = 3
61 )
62
63 func FormatBoardLock(l BoardLock) string {
64 switch l {
65 case LockNone:
66 return "Allow all"
67 case LockThread:
68 return "No visitor threads"
69 case LockPost:
70 return "No visitor posts"
71 case LockStaff:
72 return "No posts"
73 default:
74 return "Unknown"
75 }
76 }
77
78 type BoardApproval int
79
80 const (
81 ApprovalNone BoardApproval = 0
82 ApprovalFile BoardApproval = 1
83 ApprovalAll BoardApproval = 2
84 )
85
86 func FormatBoardApproval(a BoardApproval) string {
87 switch a {
88 case ApprovalNone:
89 return "None"
90 case ApprovalFile:
91 return "File"
92 case ApprovalAll:
93 return "All"
94 default:
95 return "Unknown"
96 }
97 }
98
99 type BoardIdentifiers int
100
101 const (
102 IdentifiersDisable BoardIdentifiers = 0
103 IdentifiersBoard BoardIdentifiers = 1
104 IdentifiersGlobal BoardIdentifiers = 2
105 )
106
107 func FormatBoardIdentifiers(i BoardIdentifiers) string {
108 switch i {
109 case IdentifiersDisable:
110 return "Disable"
111 case IdentifiersBoard:
112 return "Board"
113 case IdentifiersGlobal:
114 return "Global"
115 default:
116 return "Unknown"
117 }
118 }
119
120 type Board struct {
121 ID int
122 Dir string
123 Name string
124 Description string
125 Type BoardType
126 Hide BoardHide
127 Lock BoardLock
128 Approval BoardApproval
129 Reports bool
130 Style string
131 Locale string
132 Delay int
133 MinName int
134 MaxName int
135 MinEmail int
136 MaxEmail int
137 MinSubject int
138 MaxSubject int
139 MinMessage int
140 MaxMessage int
141 MinSizeThread int64
142 MaxSizeThread int64
143 MinSizeReply int64
144 MaxSizeReply int64
145 ThumbWidth int
146 ThumbHeight int
147 DefaultName string
148 WordBreak int
149 Truncate int
150 Threads int
151 Replies int
152 MaxThreads int
153 MaxReplies int
154 Oekaki bool
155 Backlinks bool
156 Files int
157 Instances int
158 Identifiers BoardIdentifiers
159 Gallery bool
160
161
162 Uploads []string
163 Embeds []string
164 Rules []string
165 Unique int `diff:"-"`
166 }
167
168 const (
169 DefaultBoardThreads = 10
170 DefaultBoardReplies = 3
171 DefaultBoardMaxName = 75
172 DefaultBoardMaxEmail = 75
173 DefaultBoardMaxSubject = 75
174 DefaultBoardMaxMessage = 8000
175 DefaultBoardWordBreak = 200
176 DefaultBoardDefaultName = "Anonymous"
177 DefaultBoardTruncate = 15
178 DefaultBoardMaxSize = 2097152
179 DefaultBoardThumbWidth = 250
180 DefaultBoardThumbHeight = 250
181 DefaultBoardFiles = 1
182 DefaultBoardInstances = 1
183 )
184
185 func NewBoard() *Board {
186 return &Board{
187 Threads: DefaultBoardThreads,
188 Replies: DefaultBoardReplies,
189 MaxName: DefaultBoardMaxName,
190 MaxEmail: DefaultBoardMaxEmail,
191 MaxSubject: DefaultBoardMaxSubject,
192 MaxMessage: DefaultBoardMaxMessage,
193 DefaultName: DefaultBoardDefaultName,
194 WordBreak: DefaultBoardWordBreak,
195 Truncate: DefaultBoardTruncate,
196 MaxSizeThread: DefaultBoardMaxSize,
197 MaxSizeReply: DefaultBoardMaxSize,
198 ThumbWidth: DefaultBoardThumbWidth,
199 ThumbHeight: DefaultBoardThumbHeight,
200 Files: DefaultBoardFiles,
201 Instances: DefaultBoardInstances,
202 }
203 }
204
205 func (b *Board) Validate() error {
206 switch {
207 case b.Dir != "" && !AlphaNumericAndSymbols.MatchString(b.Dir):
208 return fmt.Errorf("dir must only consist of letters, numbers, hyphens and underscores")
209 case strings.TrimSpace(b.Name) == "":
210 return fmt.Errorf("name must be set")
211 case b.MinName > b.MaxName:
212 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "name length")
213 case b.MinEmail > b.MaxEmail:
214 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "email length")
215 case b.MinSubject > b.MaxSubject:
216 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "subject length")
217 case b.MinMessage > b.MaxMessage:
218 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "message length")
219 case b.MinSizeThread > b.MaxSizeThread:
220 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "thread file size")
221 case b.MinSizeReply > b.MaxSizeReply:
222 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "reply file size")
223 }
224 reservedDirs := []string{"captcha", "static", "sriracha", "sriracha_all"}
225 for _, reserved := range reservedDirs {
226 if strings.EqualFold(b.Dir, reserved) {
227 return fmt.Errorf("%s is a reserved name", reserved)
228 }
229 }
230 return nil
231 }
232
233 func (b *Board) Path() string {
234 if b.Dir == "" {
235 return "/"
236 }
237 return "/" + b.Dir + "/"
238 }
239
240 func (b *Board) MaxSizeLabel(thread bool) string {
241 if thread {
242 return FormatFileSize(b.MaxSizeThread)
243 }
244 return FormatFileSize(b.MaxSizeReply)
245 }
246
247 func (b *Board) HasUpload(mimeType string) bool {
248 if len(b.Uploads) == 0 {
249 return false
250 }
251 for _, upload := range b.Uploads {
252 if upload == mimeType {
253 return true
254 }
255 }
256 return false
257 }
258
259 func (b *Board) HasEmbed(name string) bool {
260 if len(b.Embeds) == 0 {
261 return false
262 }
263 for _, embed := range b.Embeds {
264 if embed == name {
265 return true
266 }
267 }
268 return false
269 }
270
271 func (b *Board) UploadTypesLabel(uploadTypes []*UploadType) string {
272 if len(b.Uploads) == 0 {
273 return ""
274 }
275 var types []string
276 found := make(map[string]bool)
277 for _, u := range uploadTypes {
278 if b.HasUpload(u.MIME) && !found[u.Ext] {
279 found[u.Ext] = true
280 types = append(types, strings.ToUpper(u.Ext))
281 }
282 }
283 buf := &strings.Builder{}
284 for i, t := range types {
285 if i > 0 {
286 if i == len(types)-1 {
287 buf.WriteString(" and ")
288 } else {
289 buf.WriteString(", ")
290 }
291 }
292 buf.WriteString(t)
293 }
294 return buf.String()
295 }
296
View as plain text