...
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 DefaultBoardGallery = true
184 )
185
186 func NewBoard() *Board {
187 return &Board{
188 Threads: DefaultBoardThreads,
189 Replies: DefaultBoardReplies,
190 MaxName: DefaultBoardMaxName,
191 MaxEmail: DefaultBoardMaxEmail,
192 MaxSubject: DefaultBoardMaxSubject,
193 MaxMessage: DefaultBoardMaxMessage,
194 DefaultName: DefaultBoardDefaultName,
195 WordBreak: DefaultBoardWordBreak,
196 Truncate: DefaultBoardTruncate,
197 MaxSizeThread: DefaultBoardMaxSize,
198 MaxSizeReply: DefaultBoardMaxSize,
199 ThumbWidth: DefaultBoardThumbWidth,
200 ThumbHeight: DefaultBoardThumbHeight,
201 Files: DefaultBoardFiles,
202 Instances: DefaultBoardInstances,
203 Gallery: DefaultBoardGallery,
204 }
205 }
206
207 func (b *Board) Validate() error {
208 switch {
209 case b.Dir != "" && !AlphaNumericAndSymbols.MatchString(b.Dir):
210 return fmt.Errorf("dir must only consist of letters, numbers, hyphens and underscores")
211 case strings.TrimSpace(b.Name) == "":
212 return fmt.Errorf("name must be set")
213 case b.MinName > b.MaxName:
214 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "name length")
215 case b.MinEmail > b.MaxEmail:
216 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "email length")
217 case b.MinSubject > b.MaxSubject:
218 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "subject length")
219 case b.MinMessage > b.MaxMessage:
220 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "message length")
221 case b.MinSizeThread > b.MaxSizeThread:
222 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "thread file size")
223 case b.MinSizeReply > b.MaxSizeReply:
224 return fmt.Errorf("minimum %[1]s must be less than or equal to maximum %[1]s", "reply file size")
225 }
226 reservedDirs := []string{"captcha", "static", "sriracha", "sriracha_all"}
227 for _, reserved := range reservedDirs {
228 if strings.EqualFold(b.Dir, reserved) {
229 return fmt.Errorf("%s is a reserved name", reserved)
230 }
231 }
232 return nil
233 }
234
235 func (b *Board) Path() string {
236 if b.Dir == "" {
237 return "/"
238 }
239 return "/" + b.Dir + "/"
240 }
241
242 func (b *Board) MaxSizeLabel(thread bool) string {
243 if thread {
244 return FormatFileSize(b.MaxSizeThread)
245 }
246 return FormatFileSize(b.MaxSizeReply)
247 }
248
249 func (b *Board) HasUpload(mimeType string) bool {
250 if len(b.Uploads) == 0 {
251 return false
252 }
253 for _, upload := range b.Uploads {
254 if upload == mimeType {
255 return true
256 }
257 }
258 return false
259 }
260
261 func (b *Board) HasEmbed(name string) bool {
262 if len(b.Embeds) == 0 {
263 return false
264 }
265 for _, embed := range b.Embeds {
266 if embed == name {
267 return true
268 }
269 }
270 return false
271 }
272
273 func (b *Board) UploadTypesLabel(uploadTypes []*UploadType) string {
274 if len(b.Uploads) == 0 {
275 return ""
276 }
277 var types []string
278 found := make(map[string]bool)
279 for _, u := range uploadTypes {
280 if b.HasUpload(u.MIME) && !found[u.Ext] {
281 found[u.Ext] = true
282 types = append(types, strings.ToUpper(u.Ext))
283 }
284 }
285 buf := &strings.Builder{}
286 for i, t := range types {
287 if i > 0 {
288 if i == len(types)-1 {
289 buf.WriteString(" and ")
290 } else {
291 buf.WriteString(", ")
292 }
293 }
294 buf.WriteString(t)
295 }
296 return buf.String()
297 }
298
View as plain text