1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-09 12:06:24 -07:00
gochan/pkg/gcsql/tables.go
Eggbertx 40c1f48186 Fix json tag, Printf usage, add initial gochan-migration stuff
TODO: make gochan-migration actually useful
2020-06-12 11:01:28 -07:00

427 lines
12 KiB
Go

package gcsql
import (
"fmt"
"html"
"html/template"
"path"
"strconv"
"strings"
"time"
"github.com/gochan-org/gochan/pkg/config"
)
const (
_ = iota
threadBan
imageBan
fullBan
)
var (
// AllSections is a cached list of all of the board sections
AllSections []BoardSection
// AllBoards is a cached list of all of the boards
AllBoards []Board
// TempPosts is a cached list of all of the posts in the temporary posts table
TempPosts []Post
)
type Announcement struct {
ID uint `json:"no"`
Subject string `json:"sub"`
Message string `json:"com"`
Poster string `json:"name"`
Timestamp time.Time
}
type BanAppeal struct {
ID int
Ban int
Message string
Denied bool
StaffResponse string
}
type BanInfo struct {
ID uint
IP string
Name string
NameIsRegex bool
Boards string
Staff string
Timestamp time.Time
Expires time.Time
Permaban bool
Reason string
Type int
StaffNote string
AppealAt time.Time
CanAppeal bool
}
// BannedForever returns true if the ban is an unappealable permaban
func (ban *BanInfo) BannedForever() bool {
return ban.Permaban && !ban.CanAppeal && ban.Type == fullBan && ban.Boards == ""
}
// IsActive returns true if the ban is still active (unexpired or a permaban)
func (ban *BanInfo) IsActive(board string) bool {
if ban.Boards == "" && (ban.Expires.After(time.Now()) || ban.Permaban) {
return true
}
boardsArr := strings.Split(ban.Boards, ",")
for _, b := range boardsArr {
if b == board && (ban.Expires.After(time.Now()) || ban.Permaban) {
return true
}
}
return false
}
// IsBanned checks to see if the ban applies to the given board
func (ban *BanInfo) IsBanned(board string) bool {
if ban.Boards == "" && (ban.Expires.After(time.Now()) || ban.Permaban) {
return true
}
boardsArr := strings.Split(ban.Boards, ",")
for _, b := range boardsArr {
if b == board && (ban.Expires.After(time.Now()) || ban.Permaban) {
return true
}
}
return false
}
type BannedHash struct {
ID uint
Checksum string
Description string
}
type Board struct {
ID int `json:"-"`
CurrentPage int `json:"-"`
NumPages int `json:"pages"`
ListOrder int `json:"-"`
Dir string `json:"board"`
Type int `json:"-"`
UploadType int `json:"-"`
Title string `json:"title"`
Subtitle string `json:"meta_description"`
Description string `json:"-"`
Section int `json:"-"`
MaxFilesize int `json:"max_filesize"`
MaxPages int `json:"max_pages"`
DefaultStyle string `json:"-"`
Locked bool `json:"is_archived"`
CreatedOn time.Time `json:"-"`
Anonymous string `json:"-"`
ForcedAnon bool `json:"-"`
MaxAge int `json:"-"`
AutosageAfter int `json:"bump_limit"`
NoImagesAfter int `json:"image_limit"`
MaxMessageLength int `json:"max_comment_chars"`
EmbedsAllowed bool `json:"-"`
RedirectToThread bool `json:"-"`
ShowID bool `json:"-"`
RequireFile bool `json:"-"`
EnableCatalog bool `json:"-"`
EnableSpoileredImages bool `json:"-"`
EnableSpoileredThreads bool `json:"-"`
Worksafe bool `json:"ws_board"`
ThreadPage int `json:"-"`
Cooldowns BoardCooldowns `json:"cooldowns"`
ThreadsPerPage int `json:"per_page"`
}
// AbsolutePath returns the full filepath of the board directory
func (board *Board) AbsolutePath(subpath ...string) string {
return path.Join(config.Config.DocumentRoot, board.Dir, path.Join(subpath...))
}
// WebPath returns a string that represents the file's path as accessible by a browser
// fileType should be "boardPage", "threadPage", "upload", or "thumb"
func (board *Board) WebPath(fileName string, fileType string) string {
var filePath string
switch fileType {
case "":
fallthrough
case "boardPage":
filePath = path.Join(config.Config.SiteWebfolder, board.Dir, fileName)
case "threadPage":
filePath = path.Join(config.Config.SiteWebfolder, board.Dir, "res", fileName)
case "upload":
filePath = path.Join(config.Config.SiteWebfolder, board.Dir, "src", fileName)
case "thumb":
filePath = path.Join(config.Config.SiteWebfolder, board.Dir, "thumb", fileName)
}
return filePath
}
func (board *Board) PagePath(pageNum interface{}) string {
var page string
pageNumStr := fmt.Sprintf("%v", pageNum)
if pageNumStr == "prev" {
if board.CurrentPage < 2 {
page = "1"
} else {
page = strconv.Itoa(board.CurrentPage - 1)
}
} else if pageNumStr == "next" {
if board.CurrentPage >= board.NumPages {
page = strconv.Itoa(board.NumPages)
} else {
page = strconv.Itoa(board.CurrentPage + 1)
}
} else {
page = pageNumStr
}
return board.WebPath(page+".html", "boardPage")
}
func (board *Board) SetDefaults() {
board.ListOrder = 0
board.Section = 1
board.MaxFilesize = 4096
board.MaxPages = 11
board.DefaultStyle = config.Config.DefaultStyle
board.Locked = false
board.Anonymous = "Anonymous"
board.ForcedAnon = false
board.MaxAge = 0
board.AutosageAfter = 200
board.NoImagesAfter = 0
board.MaxMessageLength = 8192
board.EmbedsAllowed = true
board.RedirectToThread = false
board.ShowID = false
board.RequireFile = false
board.EnableCatalog = true
board.EnableSpoileredImages = true
board.EnableSpoileredThreads = true
board.Worksafe = true
board.ThreadsPerPage = 10
}
type BoardSection struct {
ID int
ListOrder int
Hidden bool
Name string
Abbreviation string
}
// Post represents each post in the database
// Deprecated. Struct was made for use with old database, deprecated since refactor of april 2020.
// Please refactor all code that uses this struct to use a struct that alligns with the new database structure and functions.
type Post struct {
ID int `json:"no"`
ParentID int `json:"resto"`
CurrentPage int `json:"-"`
BoardID int `json:"-"`
Name string `json:"name"`
Tripcode string `json:"trip"`
Email string `json:"email"`
Subject string `json:"sub"`
MessageHTML template.HTML `json:"com"`
MessageText string `json:"-"`
Password string `json:"-"`
Filename string `json:"tim"`
FilenameOriginal string `json:"filename"`
FileChecksum string `json:"md5"`
FileExt string `json:"extension"`
Filesize int `json:"fsize"`
ImageW int `json:"w"`
ImageH int `json:"h"`
ThumbW int `json:"tn_w"`
ThumbH int `json:"tn_h"`
IP string `json:"-"`
Capcode string `json:"capcode"`
Timestamp time.Time `json:"time"`
Autosage bool `json:"-"`
Bumped time.Time `json:"last_modified"`
Stickied bool `json:"-"`
Locked bool `json:"-"`
Reviewed bool `json:"-"`
}
func (p *Post) GetURL(includeDomain bool) string {
postURL := ""
if includeDomain {
postURL += config.Config.SiteDomain
}
var board Board
if err := board.PopulateData(p.BoardID); err != nil {
return postURL
}
idStr := strconv.Itoa(p.ID)
postURL += config.Config.SiteWebfolder + board.Dir + "/res/"
if p.ParentID == 0 {
postURL += idStr + ".html#" + idStr
} else {
postURL += strconv.Itoa(p.ParentID) + ".html#" + idStr
}
return postURL
}
// Sanitize escapes HTML strings in a post. This should be run immediately before
// the post is inserted into the database
func (p *Post) Sanitize() {
p.Name = html.EscapeString(p.Name)
p.Email = html.EscapeString(p.Email)
p.Subject = html.EscapeString(p.Subject)
p.Password = html.EscapeString(p.Password)
}
type Report struct {
ID uint
Board string
PostID uint
Timestamp time.Time
IP string
Reason string
Cleared bool
IsTemp bool
}
type LoginSession struct {
ID uint
Name string
Data string
Expires string
}
// Staff represents a single staff member's info stored in the database
type Staff struct {
ID int
Username string
PasswordChecksum string
Rank int
AddedOn time.Time
LastActive time.Time
}
type BoardCooldowns struct {
NewThread int `json:"threads"`
Reply int `json:"replies"`
ImageReply int `json:"images"`
}
type MessagePostContainer struct {
ID int
MessageRaw string
Message template.HTML
}
// Deprecated. Struct was made for use with old database, deprecated since refactor of april 2020.
// Please refactor all code that uses this struct to use a struct that alligns with the new database structure and functions.
type RecentPost struct {
BoardName string
BoardID int
PostID int
ParentID int
Name string
Tripcode string
Message template.HTML
Filename string
ThumbW int
ThumbH int
IP string
Timestamp time.Time
}
// GetURL returns the full URL of the recent post, or the full path if includeDomain is false
func (p *RecentPost) GetURL(includeDomain bool) string {
postURL := ""
if includeDomain {
postURL += config.Config.SiteDomain
}
idStr := strconv.Itoa(p.PostID)
postURL += config.Config.SiteWebfolder + p.BoardName + "/res/"
if p.ParentID == 0 {
postURL += idStr + ".html#" + idStr
} else {
postURL += strconv.Itoa(p.ParentID) + ".html#" + idStr
}
return postURL
}
type Thread struct {
OP Post `json:"-"`
NumReplies int `json:"replies"`
NumImages int `json:"images"`
OmittedPosts int `json:"omitted_posts"`
OmittedImages int `json:"omitted_images"`
BoardReplies []Post `json:"-"`
Sticky int `json:"sticky"`
Locked int `json:"locked"`
ThreadPage int `json:"-"`
}
//FileBan contains the information associated with a specific file ban
type FileBan struct {
ID int `json:"id"`
BoardID *int `json:"board"`
StaffID int `json:"staff_id"`
StaffNote string `json:"staff_note"`
IssuedAt time.Time `json:"issued_at"`
Checksum string `json:"checksum"`
}
//FilenameBan contains the information associated with a specific filename ban
type FilenameBan struct {
ID int `json:"id"`
BoardID *int `json:"board"`
StaffID int `json:"staff_id"`
StaffNote string `json:"staff_note"`
IssuedAt time.Time `json:"issued_at"`
Filename string `json:"filename"`
IsRegex bool `json:"is_regex"`
}
//UsernameBan contains the information associated with a specific username ban
type UsernameBan struct {
ID int `json:"id"`
BoardID *int `json:"board"`
StaffID int `json:"staff_id"`
StaffNote string `json:"staff_note"`
IssuedAt time.Time `json:"issued_at"`
Username string `json:"username"`
IsRegex bool `json:"is_regex"`
}
//WordFilter contains the information associated with a specific wordfilter
type WordFilter struct {
ID int `json:"id"`
BoardID *int `json:"board"`
StaffID int `json:"staff_id"`
StaffNote string `json:"staff_note"`
IssuedAt time.Time `json:"issued_at"`
Search string `json:"search"`
IsRegex bool `json:"is_regex"`
ChangeTo string `json:"change_to"`
}
//IPBan contains the information association with a specific ip ban
type IPBan struct {
ID int `json:"id"`
BoardID *int `json:"board"`
StaffID int `json:"staff_id"`
BannedForPostID *int `json:"banned_for_post_id"`
CopyPostText template.HTML `json:"copy_post_text"`
IsThreadBan bool `json:"is_thread_ban"`
IsActive bool `json:"is_active"`
IP string `json:"ip"`
IssuedAt time.Time `json:"issued_at"`
AppealAt time.Time `json:"appeal_at"`
ExpiresAt time.Time `json:"expires_at"`
Permanent bool `json:"permanent"`
StaffNote string `json:"staff_note"`
Message string `json:"message"`
CanAppeal bool `json:"can_appeal"`
}