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