321 lines
5.5 KiB
Go
321 lines
5.5 KiB
Go
|
//
|
||
|
// model.go
|
||
|
// template model interfaces
|
||
|
//
|
||
|
package srnd
|
||
|
|
||
|
import (
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
// base model type
|
||
|
type BaseModel interface {
|
||
|
|
||
|
// site url prefix
|
||
|
Prefix() string
|
||
|
|
||
|
// impelements json.Marshaller
|
||
|
MarshalJSON() ([]byte, error)
|
||
|
|
||
|
// to json string
|
||
|
JSON() string
|
||
|
}
|
||
|
|
||
|
type ThumbInfo struct {
|
||
|
Width int
|
||
|
Height int
|
||
|
}
|
||
|
|
||
|
// for attachments
|
||
|
type AttachmentModel interface {
|
||
|
BaseModel
|
||
|
|
||
|
Thumbnail() string
|
||
|
Source() string
|
||
|
Filename() string
|
||
|
Hash() string
|
||
|
ThumbInfo() ThumbInfo
|
||
|
}
|
||
|
|
||
|
// for individual posts
|
||
|
type PostModel interface {
|
||
|
BaseModel
|
||
|
|
||
|
CSSClass() string
|
||
|
|
||
|
MessageID() string
|
||
|
PostHash() string
|
||
|
ShortHash() string
|
||
|
PostURL() string
|
||
|
Frontend() string
|
||
|
Subject() string
|
||
|
Name() string
|
||
|
Date() string
|
||
|
OP() bool
|
||
|
Attachments() []AttachmentModel
|
||
|
NumAttachments() int
|
||
|
Board() string
|
||
|
Sage() bool
|
||
|
Pubkey() string
|
||
|
Reference() string
|
||
|
ReferenceHash() string
|
||
|
|
||
|
RenderBody() string
|
||
|
RenderPost() string
|
||
|
RenderBodyPre() string
|
||
|
|
||
|
// replaces Truncate().RenderBody()
|
||
|
RenderTruncatedBody() string
|
||
|
|
||
|
// replaces Truncate().RenderPost()
|
||
|
RenderTruncatedPost() string
|
||
|
|
||
|
// returns true if this post was truncated
|
||
|
IsTruncated() bool
|
||
|
|
||
|
IsI2P() bool
|
||
|
IsTor() bool
|
||
|
IsClearnet() bool
|
||
|
|
||
|
// deprecated
|
||
|
// truncate body to a certain size
|
||
|
// return copy
|
||
|
Truncate() PostModel
|
||
|
|
||
|
// what is our position in this thread?
|
||
|
// 0 for OP, nonzero for reply
|
||
|
Index() int
|
||
|
// set post index
|
||
|
SetIndex(idx int)
|
||
|
|
||
|
// nntp id number
|
||
|
NNTPID() int
|
||
|
}
|
||
|
|
||
|
// interface for models that have a navbar
|
||
|
type NavbarModel interface {
|
||
|
Navbar() string
|
||
|
}
|
||
|
|
||
|
// for threads
|
||
|
type ThreadModel interface {
|
||
|
BaseModel
|
||
|
NavbarModel
|
||
|
|
||
|
SetAllowFiles(allow bool)
|
||
|
AllowFiles() bool
|
||
|
OP() PostModel
|
||
|
Replies() []PostModel
|
||
|
Board() string
|
||
|
BoardURL() string
|
||
|
// return a short version of the thread
|
||
|
// does not include all replies
|
||
|
Truncate() ThreadModel
|
||
|
|
||
|
// number of posts in this thread
|
||
|
PostCount() int
|
||
|
// number of images in this thread
|
||
|
ImageCount() int
|
||
|
// number of posts excluded during truncation
|
||
|
// returns 0 if not truncated
|
||
|
MissingPostCount() int
|
||
|
// number of images excluded during truncation
|
||
|
// returns 0 if not truncated
|
||
|
MissingImageCount() int
|
||
|
// returns true if this thread has truncated replies
|
||
|
HasOmittedReplies() bool
|
||
|
// returns true if this thread has truncated images
|
||
|
HasOmittedImages() bool
|
||
|
|
||
|
// update the thread's replies
|
||
|
Update(db Database)
|
||
|
// is this thread dirty and needing updating?
|
||
|
IsDirty() bool
|
||
|
// mark thread as dirty
|
||
|
MarkDirty()
|
||
|
}
|
||
|
|
||
|
// board interface
|
||
|
// for 1 page on a board
|
||
|
type BoardModel interface {
|
||
|
BaseModel
|
||
|
NavbarModel
|
||
|
|
||
|
Frontend() string
|
||
|
Name() string
|
||
|
Threads() []ThreadModel
|
||
|
|
||
|
AllowFiles() bool
|
||
|
SetAllowFiles(files bool)
|
||
|
|
||
|
// JUST update this thread
|
||
|
// if we don't have it already loaded do nothing
|
||
|
UpdateThread(message_id string, db Database)
|
||
|
|
||
|
// get a thread model with this id
|
||
|
// returns nil if we don't have it
|
||
|
GetThread(message_id string) ThreadModel
|
||
|
|
||
|
// put a thread back after updating externally
|
||
|
PutThread(th ThreadModel)
|
||
|
|
||
|
// deprecated, use GetThread
|
||
|
HasThread(message_id string) bool
|
||
|
|
||
|
// update the board's contents
|
||
|
Update(db Database)
|
||
|
}
|
||
|
|
||
|
type CatalogModel interface {
|
||
|
BaseModel
|
||
|
NavbarModel
|
||
|
|
||
|
Frontend() string
|
||
|
Name() string
|
||
|
Threads() []CatalogItemModel
|
||
|
}
|
||
|
|
||
|
type CatalogItemModel interface {
|
||
|
OP() PostModel
|
||
|
ReplyCount() string
|
||
|
Page() string
|
||
|
}
|
||
|
|
||
|
type LinkModel interface {
|
||
|
Text() string
|
||
|
LinkURL() string
|
||
|
}
|
||
|
|
||
|
// newsgroup model
|
||
|
// every page on a newsgroup
|
||
|
type GroupModel []BoardModel
|
||
|
|
||
|
// TODO: optimize using 1 query?
|
||
|
// update every page
|
||
|
func (self *GroupModel) UpdateAll(db Database) {
|
||
|
m := *self
|
||
|
for _, page := range m {
|
||
|
page.Update(db)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// update a certain page
|
||
|
// does nothing if out of bounds
|
||
|
func (self *GroupModel) Update(page int, db Database) {
|
||
|
m := *self
|
||
|
if len(m) > page {
|
||
|
m[page].Update(db)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type boardPageRow struct {
|
||
|
Board string
|
||
|
Hour int64
|
||
|
Day int64
|
||
|
All int64
|
||
|
}
|
||
|
|
||
|
type boardPageRows []boardPageRow
|
||
|
|
||
|
func (self boardPageRows) Len() int {
|
||
|
return len(self)
|
||
|
}
|
||
|
|
||
|
func (self boardPageRows) Less(i, j int) bool {
|
||
|
i_val := self[i]
|
||
|
j_val := self[j]
|
||
|
return (i_val.Day + i_val.Hour*24) > (j_val.Day + j_val.Hour*24)
|
||
|
}
|
||
|
|
||
|
func (self boardPageRows) Swap(i, j int) {
|
||
|
self[i], self[j] = self[j], self[i]
|
||
|
}
|
||
|
|
||
|
type postsGraphRow struct {
|
||
|
day time.Time
|
||
|
Num int64
|
||
|
mag int64
|
||
|
}
|
||
|
|
||
|
func (p *postsGraphRow) GraphRune(r string) (s string) {
|
||
|
var num int64
|
||
|
if p.mag > 0 {
|
||
|
num = p.Num / p.mag
|
||
|
} else {
|
||
|
num = p.Num
|
||
|
}
|
||
|
for num > 0 {
|
||
|
s += r
|
||
|
num--
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func (p postsGraphRow) Date() (s string) {
|
||
|
return p.day.Format(i18nProvider.Format("month_date_format"))
|
||
|
}
|
||
|
|
||
|
func (p postsGraphRow) Day() (s string) {
|
||
|
return p.day.Format(i18nProvider.Format("day_date_format"))
|
||
|
}
|
||
|
|
||
|
func (p postsGraphRow) RegularGraph() (s string) {
|
||
|
return p.GraphRune("=")
|
||
|
}
|
||
|
|
||
|
// :0========3 overcock :3 graph of data
|
||
|
func (p postsGraphRow) OvercockGraph() (s string) {
|
||
|
var num int64
|
||
|
if p.mag > 0 {
|
||
|
num = p.Num / p.mag
|
||
|
} else {
|
||
|
num = p.Num
|
||
|
}
|
||
|
if num > 0 {
|
||
|
s = ":0"
|
||
|
num -= 1
|
||
|
for num > 0 {
|
||
|
s += "="
|
||
|
num--
|
||
|
}
|
||
|
s += "3"
|
||
|
} else {
|
||
|
s = ":3"
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
type postsGraph []postsGraphRow
|
||
|
|
||
|
func (self postsGraph) Len() int {
|
||
|
return len(self)
|
||
|
}
|
||
|
|
||
|
func (self postsGraph) Less(i, j int) bool {
|
||
|
i_val := self[i]
|
||
|
j_val := self[j]
|
||
|
return i_val.day.Unix() > j_val.day.Unix()
|
||
|
}
|
||
|
|
||
|
func (self postsGraph) Swap(i, j int) {
|
||
|
self[i], self[j] = self[j], self[i]
|
||
|
}
|
||
|
|
||
|
func (self postsGraph) Scale() (graph postsGraph) {
|
||
|
// find max
|
||
|
max := int64(0)
|
||
|
for _, p := range self {
|
||
|
if p.Num > max {
|
||
|
max = p.Num
|
||
|
}
|
||
|
}
|
||
|
mag := max / 25
|
||
|
for _, p := range self {
|
||
|
p.mag = mag
|
||
|
graph = append(graph, p)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
type overviewModel []PostModel
|