common

package
v0.0.0-...-553e66b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 29, 2021 License: GPL-3.0 Imports: 64 Imported by: 0

Documentation

Overview

* * Gosora Alerts System * Copyright Azareal 2017 - 2020 *

* * Gosora Authentication Interface * Copyright Azareal 2017 - 2020 *

* * Gosora Common Resources * Copyright Azareal 2018 - 2020 *

* * Gosora Plugin System * Copyright Azareal 2016 - 2021 *

* * Gosora Forum Store * Copyright Azareal 2017 - 2020 *

Under Heavy Construction

* * OttoJS Plugin Module * Copyright Azareal 2016 - 2019 *

* * Reply Resources File * Copyright Azareal 2016 - 2020 *

* * Gosora Task System * Copyright Azareal 2017 - 2020 *

Copyright Azareal 2016 - 2019

* * Gosora Topic File * Copyright Azareal 2017 - 2020 *

* * Gosora Topic Store * Copyright Azareal 2017 - 2020 *

* * Gosora User File * Copyright Azareal 2017 - 2020 *

* * Utility Functions And Stuff * Copyright Azareal 2017 - 2020 *

* * Gosora WebSocket Subsystem * Copyright Azareal 2017 - 2021 *

Copyright Azareal 2017 - 2020

Index

Constants

View Source
const (
	ForumActionDelete = iota
	ForumActionLock
	ForumActionUnlock
	ForumActionMove
)
View Source
const (
	ENone = iota
	ERaw
	ERawExternal
	EImage
	AImage
	AVideo
	AAudio
	AText
	AOther
)
View Source
const (
	ResTypeUnknown = iota
	ResTypeSheet
	ResTypeScript
)
View Source
const (
	LocUnknown = iota
	LocGlobal
	LocFront
	LocPanel
)
View Source
const (
	TopicListDefault = iota
	TopicListMostViewed
	TopicListWeekViews
)
View Source
const AlertsGrowHint = len(`{"msgs":[],"count":,"tc":}`) + 1 + 10
View Source
const AlertsGrowHint2 = len(`{"msg":"","sub":[],"path":"","img":"","id":}`) + 5 + 3 + 1 + 1 + 1
View Source
const Day = Hour * 24
View Source
const Gigabyte = Megabyte * 1024
View Source
const Hour int = 60 * 60

nolint I don't want to write comments for each of these o.o

View Source
const Kilobyte int = 1024
View Source
const Megabyte = Kilobyte * 1024
View Source
const Month = Day * 30
View Source
const Petabyte = Terabyte * 1024
View Source
const ReportForumID = 1

TODO: Make the default report forum ID configurable TODO: Make sure this constant is used everywhere for the report forum ID

View Source
const SaltLength int = 32
View Source
const SessionLength int = 80
View Source
const Terabyte = Gigabyte * 1024
View Source
const Week = Day * 7
View Source
const Year = Day * 365

Variables

View Source
var AllPluginPerms = make(map[string]bool)
View Source
var AllowedFileExts = StringList{
	"png", "jpg", "jpe", "jpeg", "jif", "jfi", "jfif", "svg", "bmp", "gif", "tiff", "tif", "webp", "apng", "avif", "flif", "heif", "heic", "bpg",

	"txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "pcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore",

	"wav", "mp3", "oga", "m4a", "flac", "ac3", "aac", "opus",

	"mp4", "avi", "ogg", "ogv", "ogx", "wmv", "webm", "flv", "f4v", "xvid", "mov", "movie", "qt",

	"otf", "woff2", "woff", "ttf", "eot",

	"bz2", "zip", "zipx", "gz", "7z", "tar", "cab", "rar", "kgb", "pea", "xz", "zz", "tgz", "xpi",

	"docx", "pdf",
}

? - Should we allow users to upload .php or .go files? It could cause security issues. We could store them with a mangled extension to render them inert TODO: Let admins manage this from the Control Panel apng is commented out for now, as we have no way of re-encoding it into a smaller file

View Source
var ArchiveFileExts = StringList{
	"bz2", "zip", "zipx", "gz", "7z", "tar", "cab", "rar", "kgb", "pea", "xz", "zz", "tgz", "xpi",
}
View Source
var BanGroup = 4

TODO: Replace any literals with this

View Source
var ChangeDefaultThemeMutex sync.Mutex
View Source
var CheckPasswordFuncs = map[string]func(string, string, string) error{
	"bcrypt": BcryptCheckPassword,
}

func(realPassword string, password string, salt string) (err error)

View Source
var Chrome, Firefox int // ! Temporary Hack for http push
View Source
var Config = new(config)

Config holds the more technical settings

View Source
var ConnWatch = &ConnWatcher{}
View Source
var Ctemplates []string // TODO: Use this to filter out top level templates we don't need
View Source
var DbConfig = &dbConfig{Host: "localhost"}

DbConfig holds the database configuration

View Source
var DbInits dbInits
View Source
var DefaultHashAlgo = "bcrypt" // Override this in the configuration file, not here
View Source
var DefaultParseSettings = &ParseSettings{}

TODO: Pack multiple bit flags into an integer instead of using a struct?

View Source
var DefaultTemplateFuncMap map[string]interface{}
View Source
var DefaultTemplates = template.New("")
View Source
var DefaultThemeBox atomic.Value
View Source
var Dev = new(devConfig)

Dev holds build flags and other things which should only be modified during developers or to gather additional test data

View Source
var DockToID = map[string]int{
	"leftOfNav":    0,
	"rightOfNav":   1,
	"topMenu":      2,
	"rightSidebar": 3,
	"footer":       4,
}
View Source
var DoubleForwardSlash = []byte("//")
View Source
var EnableWebsockets = true // Put this in caps for consistency with the other constants?

TODO: Disable WebSockets on high load? Add a Control Panel interface for disabling it?

View Source
var ErrAccountExists = errors.New("this username is already in use")
View Source
var ErrAlreadyLiked = errors.New("You already liked this!")
View Source
var ErrAlreadyReported = errors.New("This item has already been reported")
View Source
var ErrBadDefaultTemplate = errors.New("The template you tried to load doesn't exist in the interpreted pool.")
View Source
var ErrBadMFAToken = errors.New("I'm not sure where you got that from, but that's not a valid 2FA token")
View Source
var ErrBadRateLimiter = errors.New("That rate limiter doesn't exist")
View Source
var ErrBadResetToken = errors.New("This reset token has expired.")
View Source
var ErrBlankName = errors.New("The name must not be blank")
View Source
var ErrCacheDesync = errors.New("The cache is out of sync with the database.") // TODO: A cross-server synchronisation mechanism

nolint ErrCacheDesync is thrown whenever a piece of data, for instance, a user is out of sync with the database. Currently unused.

View Source
var ErrCorruptAttachPath = errors.New("corrupt attachment path")
View Source
var ErrDBDown = errors.New("The database is down")
View Source
var ErrEnableEmbedsOutOfBounds = errors.New("enable_embeds must be -1, 0 or 1")
View Source
var ErrExceededRateLimit = errors.New("You're exceeding a rate limit. Please wait a while before trying again.")
View Source
var ErrHashNotExist = errors.New("We don't recognise that hashing algorithm")

nolint

View Source
var ErrInvalidSocket = errors.New("That's not a valid WebSocket Connection")
View Source
var ErrLogWriter = io.MultiWriter(os.Stderr)
View Source
var ErrLogger = log.New(os.Stderr, "", log.LstdFlags)
View Source
var ErrLongTitle = errors.New("The title is too long")
View Source
var ErrLongUsername = errors.New("this username is too long")
View Source
var ErrMFAScratchIndexOutOfBounds = errors.New("That MFA scratch index is out of bounds")
View Source
var ErrMismatchedHashAndPassword = bcrypt.ErrMismatchedHashAndPassword

ErrMismatchedHashAndPassword is thrown whenever a hash doesn't match it's unhashed password

View Source
var ErrNoBody = errors.New("This message is missing a body")
View Source
var ErrNoDefaultTheme = errors.New("The default theme isn't registered in the system")
View Source
var ErrNoDeleteReports = errors.New("You cannot delete the Reports forum")
View Source
var ErrNoMFAToken = errors.New("This user doesn't have 2FA setup")
View Source
var ErrNoRows = sql.ErrNoRows

ErrNoRows is an alias of sql.ErrNoRows, just in case we end up with non-database/sql datastores

View Source
var ErrNoTempGroup = errors.New("We couldn't find a temporary group for this user")
View Source
var ErrNoTitle = errors.New("This message is missing a title")
View Source
var ErrNoUserByName = errors.New("We couldn't find an account with that username.")
View Source
var ErrNoneOnPage = errors.New("This user isn't on that page")
View Source
var ErrPasswordTooLong = errors.New("The password you selected is too long")

ErrPasswordTooLong is silly, but we don't want bcrypt to bork on us

View Source
var ErrPluginNotInstallable = errors.New("This plugin is not installable")
View Source
var ErrProfileCommentsOutOfBounds = errors.New("profile_comments must be an integer between -1 and 4")

var ErrMalformedInteger = errors.New("malformed integer")

View Source
var ErrSecretError = errors.New("There was a glitch in the system. Please contact your local administrator.")
View Source
var ErrSomeUsersNotFound = errors.New("Unable to find some users")
View Source
var ErrStoreCapacityOverflow = errors.New("This datastore has reached it's maximum capacity.") // nolint

ErrStoreCapacityOverflow is thrown whenever a datastore reaches it's maximum hard capacity. I'm not sure if this error is actually used. It might be, we should check

View Source
var ErrTooFewHashParams = errors.New("You haven't provided enough hash parameters")
View Source
var ErrWeakPasswordCommon = errors.New("You may not use a password that is in common use")
View Source
var ErrWeakPasswordContains error
View Source
var ErrWeakPasswordEmailInPass = errors.New("You can't use your email in your password.")
View Source
var ErrWeakPasswordNameInPass = errors.New("You can't use your name in your password.")
View Source
var ErrWeakPasswordNoLower = errors.New("You don't have any lowercase characters in your password")
View Source
var ErrWeakPasswordNoNumbers = errors.New("You don't have any numbers in your password")
View Source
var ErrWeakPasswordNoUpper = errors.New("You don't have any uppercase characters in your password")
View Source
var ErrWeakPasswordNone = errors.New("You didn't put in a password.")
View Source
var ErrWeakPasswordShort = errors.New("Your password needs to be at-least eight characters long")
View Source
var ErrWeakPasswordUniqueChars = errors.New("You don't have enough unique characters in your password")
View Source
var ErrWrongMFAToken = errors.New("That 2FA token isn't correct")
View Source
var ErrWrongPassword = errors.New("That's not the correct password.")
View Source
var ErrorCountSinceStartup int64

var errorBuffer []ErrorItem

View Source
var ExecutableFileExts = StringList{
	"exe", "jar", "phar", "shar", "iso", "apk", "deb",
}
View Source
var ForumUserCheck func(h *Header, w http.ResponseWriter, r *http.Request, u *User, fid int) (err RouteError) = forumUserCheck
View Source
var GeneratePasswordFuncs = map[string]func(string) (string, string, error){
	"bcrypt": BcryptGeneratePassword,
}

func(password string) (hashedPassword string, salt string, err error)

View Source
var GlobalPermList = []string{
	"BanUsers",
	"ActivateUsers",
	"EditUser",
	"EditUserEmail",
	"EditUserPassword",
	"EditUserGroup",
	"EditUserGroupSuperMod",
	"EditUserGroupAdmin",
	"EditGroup",
	"EditGroupLocalPerms",
	"EditGroupGlobalPerms",
	"EditGroupSuperMod",
	"EditGroupAdmin",
	"ManageForums",
	"EditSettings",
	"ManageThemes",
	"ManagePlugins",
	"ViewAdminLogs",
	"ViewIPs",
	"UploadFiles",
	"UploadAvatars",
	"UseConvos",
	"UseConvosOnlyWithMod",
	"CreateProfileReply",
	"AutoEmbed",
	"AutoLink",
}

? - Can we avoid duplicating the items in this list in a bunch of places?

View Source
var GuestUser = User{ID: 0, Name: "Guest", Link: "#", Group: 6, Perms: GuestPerms, CreatedAt: StartTime} // BuildAvatar is done in site.go to make sure it's done after init

TODO: Use something else as the guest avatar, maybe a question mark of some sort? GuestUser is an instance of user which holds guest data to avoid having to initialise a guest every time

View Source
var GzipStartEtag string
View Source
var HashPrefixes = map[string]string{
	"$2a$": "bcrypt",
}

TODO: Redirect 2b to bcrypt too?

View Source
var ImageFileExts = StringList{
	"png", "jpg", "jpe", "jpeg", "jif", "jfi", "jfif", "svg", "bmp", "gif", "tiff", "tif", "webp",
}
View Source
var InvalidForum = []byte("<red>[Invalid Forum]</red>")
View Source
var InvalidProfile = []byte("<red>[Invalid Profile]</red>")
View Source
var InvalidTopic = []byte("<red>[Invalid Topic]</red>")
View Source
var InvalidURL = []byte("<red>[Invalid URL]</red>")
View Source
var IsDBDown int32 = 0 // 0 = false, 1 = true. this is value which should be manipulated with package atomic for representing whether the database is down so we don't spam the log with lots of redundant errors
View Source
var JSTokenBox atomic.Value // TODO: Move this and some of these other globals somewhere else

Anti-spam token with rotated key

View Source
var LastEmbedID = AOther
View Source
var LocalPermList = []string{
	"ViewTopic",
	"LikeItem",
	"CreateTopic",
	"EditTopic",
	"DeleteTopic",
	"CreateReply",
	"EditReply",
	"DeleteReply",
	"PinTopic",
	"CloseTopic",
	"MoveTopic",
}
View Source
var LogWriter = io.MultiWriter(os.Stdout)
View Source
var OldSessionSigningKeyBox atomic.Value // Just in case we've signed with a key that's about to go stale so we don't annoy the user too much
View Source
var PanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*Header, PanelStats, RouteError) = panelUserCheck

TODO: Come up with a better middleware solution nolint We need these types so people can tell what they are without scrolling to the bottom of the file

View Source
var PluginConfig = map[string]string{}
View Source
var PluginsInited = false
View Source
var PreRenderHooks = map[string][]func(http.ResponseWriter, *http.Request, *User, interface{}) bool{
	"pre_render": nil,

	"pre_render_forums":       nil,
	"pre_render_forum":        nil,
	"pre_render_topics":       nil,
	"pre_render_topic":        nil,
	"pre_render_profile":      nil,
	"pre_render_custom_page":  nil,
	"pre_render_tmpl_page":    nil,
	"pre_render_overview":     nil,
	"pre_render_create_topic": nil,

	"pre_render_account_own_edit":           nil,
	"pre_render_account_own_edit_password":  nil,
	"pre_render_account_own_edit_mfa":       nil,
	"pre_render_account_own_edit_mfa_setup": nil,
	"pre_render_account_own_edit_email":     nil,
	"pre_render_level_list":                 nil,
	"pre_render_login":                      nil,
	"pre_render_login_mfa_verify":           nil,
	"pre_render_register":                   nil,
	"pre_render_ban":                        nil,
	"pre_render_ip_search":                  nil,

	"pre_render_panel_dashboard":        nil,
	"pre_render_panel_forums":           nil,
	"pre_render_panel_delete_forum":     nil,
	"pre_render_panel_forum_edit":       nil,
	"pre_render_panel_forum_edit_perms": nil,

	"pre_render_panel_analytics_views":          nil,
	"pre_render_panel_analytics_routes":         nil,
	"pre_render_panel_analytics_agents":         nil,
	"pre_render_panel_analytics_systems":        nil,
	"pre_render_panel_analytics_referrers":      nil,
	"pre_render_panel_analytics_route_views":    nil,
	"pre_render_panel_analytics_agent_views":    nil,
	"pre_render_panel_analytics_system_views":   nil,
	"pre_render_panel_analytics_referrer_views": nil,

	"pre_render_panel_settings":          nil,
	"pre_render_panel_setting":           nil,
	"pre_render_panel_word_filters":      nil,
	"pre_render_panel_word_filters_edit": nil,
	"pre_render_panel_plugins":           nil,
	"pre_render_panel_users":             nil,
	"pre_render_panel_user_edit":         nil,
	"pre_render_panel_groups":            nil,
	"pre_render_panel_group_edit":        nil,
	"pre_render_panel_group_edit_perms":  nil,
	"pre_render_panel_themes":            nil,
	"pre_render_panel_modlogs":           nil,

	"pre_render_error": nil,

	"pre_render_security_error": nil,
}

The hooks which run before the template is rendered for a route

View Source
var PreRoute func(http.ResponseWriter, *http.Request) (User, bool) = preRoute

nolint

View Source
var PrebuildTmplList []func(User, *Header) CTmpl

var Templates = template.New("")

View Source
var RenderTemplateAlias func(tmplName, hookName string, w http.ResponseWriter, r *http.Request, h *Header, pi interface{}) error

Alias of routes.renderTemplate

View Source
var SessionSigningKeyBox atomic.Value // For MFA to avoid hitting the database unneccessarily
View Source
var SettingBox atomic.Value // An atomic value pointing to a SettingBox
View Source
var SimpleBots []int // ! Temporary hack to stop semrush, ahrefs, python bots and other from wasting resources
View Source
var SimpleForumUserCheck func(w http.ResponseWriter, r *http.Request, u *User, fid int) (headerLite *HeaderLite, err RouteError) = simpleForumUserCheck
View Source
var SimplePanelUserCheck func(http.ResponseWriter, *http.Request, *User) (*HeaderLite, RouteError) = simplePanelUserCheck
View Source
var SimpleUserCheck func(w http.ResponseWriter, r *http.Request, u *User) (headerLite *HeaderLite, err RouteError) = simpleUserCheck
View Source
var Site = &site{Name: "Magical Fairy Land", Language: "english"}

Site holds the basic settings which should be tweaked when setting up a site, we might move them to the settings table at some point

View Source
var SoftwareVersion = Version{Major: 0, Minor: 3, Patch: 0, Tag: "dev"}
View Source
var SpaceGap = []byte("          ")

TODO: Use the template system? TODO: Somehow localise these?

View Source
var SpammyDomainBits = []string{"porn", "sex", "acup", "nude", "milf", "tits", "vape", "busty", "kink", "lingerie", "strapon", "problog", "fet", "xblog", "blogin", "blognetwork", "relayblog"}

TODO: Make this more customisable

View Source
var StartEtag string
View Source
var StartTime time.Time
View Source
var StaticFiles = SFileList{"/s/", make(map[string]*SFile), make(map[string]*SFile)}
View Source
var StopServerChan = make(chan []interface{})
View Source
var Template_account_handle = genIntTmpl("account")
View Source
var Template_create_topic_handle = genIntTmpl("create_topic")

nolint

View Source
var Template_error_handle = genIntTmpl("error")
View Source
var Template_forum_guest_handle = Template_forum_handle
View Source
var Template_forum_handle = genIntTmpl("forum")

nolint

View Source
var Template_forum_member_handle = Template_forum_handle
View Source
var Template_forums_guest_handle = Template_forums_handle
View Source
var Template_forums_handle = genIntTmpl("forums")

nolint

View Source
var Template_forums_member_handle = Template_forums_handle
View Source
var Template_ip_search_handle = genIntTmpl("ip_search")
View Source
var Template_login_handle = genIntTmpl("login")
View Source
var Template_profile_guest_handle = Template_profile_handle
View Source
var Template_profile_handle = genIntTmpl("profile")

nolint

View Source
var Template_profile_member_handle = Template_profile_handle
View Source
var Template_register_handle = genIntTmpl("register")
View Source
var Template_topic_alt_guest_handle = Template_topic_alt_handle
View Source
var Template_topic_alt_handle = genIntTmpl("topic")
View Source
var Template_topic_alt_member_handle = Template_topic_alt_handle
View Source
var Template_topic_guest_handle = Template_topic_handle
View Source
var Template_topic_handle = genIntTmpl("topic")

TODO: Refactor the template trees to not need these nolint

View Source
var Template_topic_member_handle = Template_topic_handle
View Source
var Template_topics_guest_handle = Template_topics_handle
View Source
var Template_topics_handle = genIntTmpl("topics")

nolint

View Source
var Template_topics_member_handle = Template_topics_handle
View Source
var TextFileExts = StringList{
	"txt", "xml", "json", "yaml", "toml", "ini", "md", "html", "rtf", "js", "py", "rb", "css", "scss", "less", "eqcss", "pcss", "java", "ts", "cs", "c", "cc", "cpp", "cxx", "C", "c++", "h", "hh", "hpp", "hxx", "h++", "rs", "rlib", "htaccess", "gitignore",
}
View Source
var ThemesSlice []*Theme
View Source
var TmplPtrMap = make(map[string]interface{})
View Source
var URLClose = []byte("</a>")
View Source
var URLOpen = []byte("<a href='")
View Source
var URLOpen2 = []byte("'>")
View Source
var URLOpenUser = []byte("<a rel='ugc'href='")
View Source
var UserCheck func(w http.ResponseWriter, r *http.Request, u *User) (h *Header, err RouteError) = userCheck
View Source
var UserCheckNano func(w http.ResponseWriter, r *http.Request, u *User, nano int64) (h *Header, err RouteError) = userCheck2
View Source
var VideoFileExts = StringList{
	"mp4", "avi", "ogg", "ogv", "ogx", "wmv", "webm", "flv", "f4v", "xvid", "mov", "movie", "qt",
}
View Source
var WebAudioFileExts = StringList{
	"wav", "mp3", "oga", "m4a", "flac",
}
View Source
var WebVideoFileExts = StringList{
	"mp4", "avi", "ogg", "ogv", "webm",
}

Functions

func AddActivityAndNotifyAll

func AddActivityAndNotifyAll(a Alert) error

TODO: Create a notifier structure?

func AddActivityAndNotifyTarget

func AddActivityAndNotifyTarget(a Alert) error

TODO: Create a notifier structure?

func AddHashLinkType

func AddHashLinkType(prefix string, h func(*strings.Builder, string, *int))

! Not concurrency safe

func AnalyticsRowsToViewMap

func AnalyticsRowsToViewMap(rows *sql.Rows, labelList []int64, viewMap map[int64]int64) (map[int64]int64, error)

func AnalyticsTimeRangeToLabelList

func AnalyticsTimeRangeToLabelList(tr *AnalyticsTimeRange) (revLabelList []int64, labelList []int64, viewMap map[int64]int64)

TODO: Clamp it rather than using an offset off the current time to avoid chaotic changes in stats as adjacent sets converge and diverge?

func ArgQToTopicCount

func ArgQToTopicCount(argList []interface{}, qlist string) (topicCount int, err error)

Internal. Don't rely on it. TODO: Check the TopicCount field on the forums instead? Make sure it's in sync first.

func ArgQToWeekViewTopicCount

func ArgQToWeekViewTopicCount(argList []interface{}, qlist string) (topicCount int, err error)

Internal. Don't rely on it.

func BcryptCheckPassword

func BcryptCheckPassword(realPassword, password, salt string) (err error)

func BcryptGeneratePassword

func BcryptGeneratePassword(password string) (hash, salt string, err error)

Note: The salt is in the hash, therefore the salt parameter is blank

func BuildAlert

func BuildAlert(a Alert, user User) (out string, err error)

func BuildAlertSb

func BuildAlertSb(sb *strings.Builder, a *Alert, u *User) (err error)

func BuildAvatar

func BuildAvatar(uid int, avatar string) (normalAvatar, microAvatar string)

? - Make this part of *User? TODO: Write tests for this

func BuildConvoURL

func BuildConvoURL(coid int) string

func BuildForumURL

func BuildForumURL(slug string, fid int) string

func BuildProfileURL

func BuildProfileURL(slug string, uid int) string

TODO: Write unit tests for this

func BuildProfileURLSb

func BuildProfileURLSb(sb *strings.Builder, slug string, uid int)

func BuildSlug

func BuildSlug(slug string, id int) string

func BuildTopicURL

func BuildTopicURL(slug string, tid int) string

func BuildTopicURLSb

func BuildTopicURLSb(sb *strings.Builder, slug string, tid int)

func BuildWidget

func BuildWidget(dock string, h *Header) (sbody string)

func BuildWidget2

func BuildWidget2(dock int, h *Header) (sbody string)

func BuildWidget3

func BuildWidget3(dock int, h *Header)

func CanonEmail

func CanonEmail(email string) string

func CheckPassword

func CheckPassword(realPassword, password, salt string) (err error)

func CoerceIntString

func CoerceIntString(data string) (res, length int)

TODO: Write a test for this

func CompileJSTemplates

func CompileJSTemplates() error

? - Add template hooks?

func CompileTemplates

func CompileTemplates() error

? - Add template hooks?

func CompressBytesBrotli

func CompressBytesBrotli(in []byte) ([]byte, error)

func CompressBytesGzip

func CompressBytesGzip(in []byte) (b []byte, err error)

func ConvActToString

func ConvActToString(a int) string

func ConvStringToAct

func ConvStringToAct(s string) int

func ConvertByteInUnit

func ConvertByteInUnit(bytes float64, unit string) (count float64)

TODO: Write a test for this

func ConvertByteUnit

func ConvertByteUnit(bytes float64) (float64, string)

TODO: Write a test for this

func ConvertFriendlyUnit

func ConvertFriendlyUnit(num int) (int, string)

TODO: Write a test for this TODO: Re-add quadrillion as int64 TODO: Re-add trillion as int64

func ConvertPerfUnit

func ConvertPerfUnit(quan float64) (out float64, unit string)

func ConvertUnit

func ConvertUnit(num int) (int, string)

TODO: Write a test for this TODO: Re-add T as int64

func Count

func Count(stmt *sql.Stmt) (count int)

func Countf

func Countf(stmt *sql.Stmt, args ...interface{}) (count int)

func CreateThemeTemplate

func CreateThemeTemplate(theme, name string)

CreateThemeTemplate creates a theme template on the current default theme

func Createf

func Createf(stmt *sql.Stmt, args ...interface{}) (id int, e error)

func DBTimeout

func DBTimeout() time.Duration

func Dailies

func Dailies() (e error)

func DebugDetail

func DebugDetail(args ...interface{})

func DebugDetailf

func DebugDetailf(str string, args ...interface{})

func DebugLog

func DebugLog(args ...interface{})

func DebugLogf

func DebugLogf(str string, args ...interface{})

func DeleteAttachment

func DeleteAttachment(aid int) error

TODO: Add a table for the files and lock the file row when performing tasks related to the file

func DeregisterPluginPerm

func DeregisterPluginPerm(name string)

func DirSize

func DirSize(path string) (int, error)

func DismissAlert

func DismissAlert(uid, aid int)

func EatPanics

func EatPanics()

func Err

func Err(args ...interface{})

func ForumListToArgQ

func ForumListToArgQ(forums []Forum) (argList []interface{}, qlist string)

Internal. Don't rely on it.

func ForumPermsToGroupForumPreset

func ForumPermsToGroupForumPreset(fp *ForumPerms) string

TODO: Refactor this and write tests for it TODO: We really need to improve the thread safety of this

func FriendlyGAuthSecret

func FriendlyGAuthSecret(secret string) (out string)

TODO: Test this with Google Authenticator proper

func FriendlyUnitToBytes

func FriendlyUnitToBytes(quantity int, unit string) (bytes int, err error)

TODO: Write a test for this TODO: Localise this?

func GenerateGAuthSecret

func GenerateGAuthSecret() (string, error)

func GeneratePassword

func GeneratePassword(password string) (hash, salt string, err error)

func GenerateSafeString

func GenerateSafeString(len int) (string, error)

GenerateSafeString is for generating a cryptographically secure set of random bytes which is base64 encoded and safe for URLs TODO: Write a test for this

func GenerateStd32SafeString

func GenerateStd32SafeString(len int) (string, error)

GenerateStd32SafeString is for generating a cryptographically secure set of random bytes which is base32 encoded ? - Safe for URLs? Mostly likely due to the small range of characters

func GetDefaultThemeName

func GetDefaultThemeName() string

func GetDockList

func GetDockList() []string

func GetForumURLPrefix

func GetForumURLPrefix() string

func GetLevel

func GetLevel(score int) (level int)

TODO: Write a test for this

func GetLevelScore

func GetLevelScore(getLevel int) (score int)

TODO: Write a test for this

func GetLevels

func GetLevels(maxLevel int) []float64

TODO: Write a test for this

func GetPluginFiles

func GetPluginFiles() (pluginList []string, err error)

func GetRidsForTopic

func GetRidsForTopic(tid, offset int) (rids []int, e error)

func HandleExpiredScheduledGroups

func HandleExpiredScheduledGroups() error

TODO: Use AddScheduledSecondTask

func HandleServerSync

func HandleServerSync() error

TODO: Use AddScheduledSecondTask TODO: Be a little more granular with the synchronisation TODO: Synchronise more things TODO: Does this even work?

func HasDock

func HasDock(dock string) bool

func HasSuspiciousEmail

func HasSuspiciousEmail(email string) bool

TODO: Write a test for this

func HasWidgets

func HasWidgets(dock string, h *Header) bool

TODO: Find a more optimimal way of doing this...

func HasWidgets2

func HasWidgets2(dock int, h *Header) bool

TODO: Find a more optimimal way of doing this...

func InitEmoji

func InitEmoji() error

func InitExtend

func InitExtend() error

func InitPluginLangs

func InitPluginLangs() error

func InitPlugins

func InitPlugins()

func InitTemplates

func InitTemplates() error

func InitWeakPasswords

func InitWeakPasswords() error

func InitWidgets

func InitWidgets() (fi error)

TODO: Make a store for this?

func LastPage

func LastPage(count, perPage int) int

TODO: Write tests for this Make sure we reflect changes to this in the JS port in /public/global.js

func LoadConfig

func LoadConfig() error

func LoadSettings

func LoadSettings() error

func Log

func Log(args ...interface{})

func LogError

func LogError(err error, extra ...string)

LogError logs internal handler errors which can't be handled with InternalError() as a wrapper for log.Fatal(), we might do more with it in the future. TODO: Clean-up extra as a way of passing additional context

func LogWarning

func LogWarning(err error, extra ...string)

func Logf

func Logf(str string, args ...interface{})

func NameToSlug

func NameToSlug(name string) (slug string)

TODO: Make slugs optional for certain languages across the entirety of Gosora? TODO: Let plugins replace NameToSlug and the URL building logic with their own

func NotifyWatchers

func NotifyWatchers(asid int) error

TODO: Create a notifier structure?

func OverrideForumPerms

func OverrideForumPerms(p *Perms, status bool)

TODO: We need a better way of overriding forum perms rather than setting them one by one

func OverridePerms

func OverridePerms(p *Perms, status bool)

func PageOffset

func PageOffset(count, page, perPage int) (int, int, int)

TODO: Write tests for this Make sure we reflect changes to this in the JS port in /public/global.js

func Paginate

func Paginate(currentPage, lastPage, maxPages int) (out []int)

TODO: Write tests for this Make sure we reflect changes to this in the JS port in /public/global.js

func ParseMessage

func ParseMessage(msg string, sectionID int, sectionType string, settings *ParseSettings, user *User) string

func ParseMessage2

func ParseMessage2(msg string, sectionID int, sectionType string, settings *ParseSettings, user *User) (string, bool)

TODO: Write a test for this TODO: We need a lot more hooks here. E.g. To add custom media types and handlers. TODO: Use templates to reduce the amount of boilerplate?

func ParseSEOURL

func ParseSEOURL(urlBit string) (slug string, id int, err error)

TODO: Copied from routes package for use in wsPageResponse, find a more elegant solution.

func PartialURLString

func PartialURLString(d string) (url []byte)

TODO: Write a test for this

func PartialURLStringLen

func PartialURLStringLen(d string) (int, bool)

TODO: Write a test for this TODO: Handle the host bits differently from the paths...

func PartialURLStringLen2

func PartialURLStringLen2(d string) int

TODO: Write a test for this TODO: Get this to support IPv6 hosts, this isn't currently done as this is used in the bbcode plugin where it thinks the [ is a IPv6 host

func PermmapToQuery

func PermmapToQuery(permmap map[string]*ForumPerms, fid int) error

func PrepResources

func PrepResources(u *User, h *Header, theme *Theme)

func PreparseMessage

func PreparseMessage(msg string) string

TODO: Preparse Markdown and normalize it into HTML? TODO: Use a string builder

func PresetToLang

func PresetToLang(preset string) string

TODO: Move this into the phrase system?

func PresetToPermmap

func PresetToPermmap(preset string) (out map[string]*ForumPerms)

func PrivacyAllowMessage

func PrivacyAllowMessage(pu, u *User) (canMsg bool)

TODO: Write tests TODO: Implement and use this TODO: Implement friends

func PrivacyCommentsShow

func PrivacyCommentsShow(pu, u *User) (showComments bool)

TODO: Implement friend system

func ProcessConfig

func ProcessConfig() (err error)

func RebuildGroupPermissions

func RebuildGroupPermissions(g *Group) error

TODO: Is this racey? TODO: Test this along with the rest of the perms system

func RebuildHookTable

func RebuildHookTable()

func RegisterPluginPerm

func RegisterPluginPerm(name string)

func RelativeTime

func RelativeTime(t time.Time) string

TODO: Write a test for this

func RelativeTimeFromString

func RelativeTimeFromString(in string) (string, error)

TODO: Write a test for this

func ReplaceForumPermsForGroup

func ReplaceForumPermsForGroup(gid int, presetSet map[int]string, permSets map[int]*ForumPerms) error

TODO: FPStore.Reload?

func ReplaceForumPermsForGroupTx

func ReplaceForumPermsForGroupTx(tx *sql.Tx, gid int, presetSets map[int]string, permSets map[int]*ForumPerms) error

func ReqIsJson

func ReqIsJson(r *http.Request) bool

func ResetTemplateOverrides

func ResetTemplateOverrides()

func RunPreRenderHook

func RunPreRenderHook(name string, w http.ResponseWriter, r *http.Request, u *User, data interface{}) (halt bool)

func RunTaskHook

func RunTaskHook(name string) error

? - Are the following functions racey?

func RunTasks

func RunTasks(tasks []func() error) error

TODO: Name the tasks so we can figure out which one it was when something goes wrong? Or maybe toss it up WithStack down there?

func SanitiseBody

func SanitiseBody(in string) string

TODO: Write a test for this TODO: Add more strange characters TODO: Strip all sub-32s minus \r and \n? SanitiseBody is the same as SanitiseSingleLine, but it doesn't strip newline characters

func SanitiseSingleLine

func SanitiseSingleLine(in string) string

TODO: Write a test for this SanitiseSingleLine is a generic function for escaping html entities and removing silly characters from usernames and topic titles. It also strips newline characters

func SendActivationEmail

func SendActivationEmail(username, email, token string) error

func SendEmail

func SendEmail(email, subject, msg string) (err error)

TODO: Refactor this

func SendValidationEmail

func SendValidationEmail(username, email, token string) error

func SetDefaultThemeName

func SetDefaultThemeName(name string)

func SetPassword

func SetPassword(uid int, password string) error

TODO: Move this to *User

func StartTick

func StartTick() (abort bool)

func StartupTasks

func StartupTasks() (e error)

func StoppedServer

func StoppedServer(msg ...interface{})

TODO: Add a graceful shutdown function

func StripInvalidGroupForumPreset

func StripInvalidGroupForumPreset(preset string) string

func StripInvalidPreset

func StripInvalidPreset(preset string) string

func Stripslashes

func Stripslashes(text string) string

TODO: Write a test for this

func SwitchToTestDB

func SwitchToTestDB()

func ThumbTask

func ThumbTask(thumbChan chan bool)

func TopicCountInForums

func TopicCountInForums(forums []Forum) (topicCount int, err error)

func UpdateDefaultTheme

func UpdateDefaultTheme(t *Theme) error

func VerifyConfig

func VerifyConfig() (err error)

func VerifyGAuthToken

func VerifyGAuthToken(secret, token string) (bool, error)

func WeakPassword

func WeakPassword(password, username, email string) error

func WordCount

func WordCount(input string) (count int)

The word counter might run into problems with some languages where words aren't as obviously demarcated, I would advise turning it off in those cases, or if it becomes annoying in general, really.

func WriteURL

func WriteURL(sb *strings.Builder, url, label string)

Types

type Account

type Account struct {
	*Header
	HTMLID   string
	TmplName string
	Inner    nobreak
}

type AccountBlocksPage

type AccountBlocksPage struct {
	*Header
	Users []*User
	Paginator
}

type AccountDashPage

type AccountDashPage struct {
	*Header
	MFASetup     bool
	CurrentScore int
	NextScore    int
	NextLevel    int
	Percentage   int
}

type AccountLoginsPage

type AccountLoginsPage struct {
	*Header
	ItemList []LoginLogItem
	Paginator
}

type AccountPrivacyPage

type AccountPrivacyPage struct {
	*Header
	ProfileComments int
	ReceiveConvos   int
	EnableEmbeds    bool
}

type ActivityStream

type ActivityStream interface {
	Add(a Alert) (int, error)
	Get(id int) (Alert, error)
	Delete(id int) error
	DeleteByParams(event string, targetID int, targetType string) error
	DeleteByParamsExtra(event string, targetID int, targetType, extra string) error
	AidsByParams(event string, elementID int, elementType string) (aids []int, err error)
	AidsByParamsExtra(event string, elementID int, elementType, extra string) (aids []int, err error)
	Count() (count int)
}
var Activity ActivityStream

type ActivityStreamMatches

type ActivityStreamMatches interface {
	Add(watcher, asid int) error
	Delete(watcher, asid int) error
	DeleteAndCountChanged(watcher, asid int) (int, error)
	CountAsid(asid int) int
}
var ActivityMatches ActivityStreamMatches

type AesConvoPostProcessor

type AesConvoPostProcessor struct {
}

func NewAesConvoPostProcessor

func NewAesConvoPostProcessor() *AesConvoPostProcessor

func (*AesConvoPostProcessor) OnLoad

func (*AesConvoPostProcessor) OnSave

type Alert

type Alert struct {
	ASID         int
	ActorID      int
	TargetUserID int
	Event        string
	ElementType  string
	ElementID    int
	CreatedAt    time.Time
	Extra        string

	Actor *User
}

type AlertStmts

type AlertStmts struct {
	// contains filtered or unexported fields
}

type AnalyticsStore

type AnalyticsStore interface {
	FillViewMap(tbl string, tr *AnalyticsTimeRange, labelList []int64, viewMap map[int64]int64, param string, args ...interface{}) (map[int64]int64, error)
}
var Analytics AnalyticsStore

type AnalyticsTimeRange

type AnalyticsTimeRange struct {
	Quantity   int
	Unit       string
	Slices     int
	SliceWidth int
	Range      string
}

type AreYouSure

type AreYouSure struct {
	URL     string
	Message string
}

type Attachment

type Attachment struct {
	ID           int
	SectionTable string
	SectionID    int
	OriginTable  string
	OriginID     int
	UploadedBy   int
	Path         string
	Extra        string

	Image bool
	Ext   string
}

type AttachmentStore

type AttachmentStore interface {
	GetForRenderRoute(filename string, sid int, sectionTable string) (*Attachment, error)
	FGet(id int) (*Attachment, error)
	Get(id int) (*MiniAttachment, error)
	MiniGetList(originTable string, originID int) (alist []*MiniAttachment, err error)
	BulkMiniGetList(originTable string, ids []int) (amap map[int][]*MiniAttachment, err error)
	Add(sectionID int, sectionTable string, originID int, originTable string, uploadedBy int, path, extra string) (int, error)
	MoveTo(sectionID, originID int, originTable string) error
	MoveToByExtra(sectionID int, originTable, extra string) error
	Count() int
	CountIn(originTable string, oid int) int
	CountInPath(path string) int
	Delete(id int) error

	AddLinked(otable string, oid int) (err error)
	RemoveLinked(otable string, oid int) (err error)
}
var Attachments AttachmentStore

type AuthInt

type AuthInt interface {
	Authenticate(name, password string) (uid int, err error, requiresExtraAuth bool)
	ValidateMFAToken(mfaToken string, uid int) error
	Logout(w http.ResponseWriter, uid int)
	ForceLogout(uid int) error
	SetCookies(w http.ResponseWriter, uid int, session string)
	SetProvisionalCookies(w http.ResponseWriter, uid int, session, signedSession string) // To avoid logging someone in until they've passed the MFA check
	GetCookies(r *http.Request) (uid int, session string, err error)
	SessionCheck(w http.ResponseWriter, r *http.Request) (u *User, halt bool)
	CreateSession(uid int) (session string, err error)
	CreateProvisionalSession(uid int) (provSession, signedSession string, err error) // To avoid logging someone in until they've passed the MFA check
}

AuthInt is the main authentication interface.

var Auth AuthInt

TODO: Write more authentication tests

type BackupItem

type BackupItem struct {
	SQLURL string

	Timestamp time.Time
}

type BasePanelPage

type BasePanelPage struct {
	*Header
	Stats         PanelStats
	Zone          string
	ReportForumID int
	DebugAdmin    bool
}

type BlockStore

type BlockStore interface {
	IsBlockedBy(blocker, blockee int) (bool, error)
	BulkIsBlockedBy(blockers []int, blockee int) (bool, error)
	Add(blocker, blockee int) error
	Remove(blocker, blockee int) error
	BlockedByOffset(blocker, offset, perPage int) ([]int, error)
	BlockedByCount(blocker int) int
}
var UserBlocks BlockStore

type CSSData

type CSSData struct {
	Phrases map[string]string
}

type CTmpl

type CTmpl struct {
	Name       string
	Filename   string
	Path       string
	StructName string
	Data       interface{}
	Imports    []string
}

type CaireThumbnailer

type CaireThumbnailer struct {
}

! Note: CaireThumbnailer can't handle gifs, so we'll have to either cap their sizes or have another resizer deal with them

func NewCaireThumbnailer

func NewCaireThumbnailer() *CaireThumbnailer

func (*CaireThumbnailer) Resize

func (thumb *CaireThumbnailer) Resize(format, inPath, tmpPath, outPath string, width int) error

type ConnWatcher

type ConnWatcher struct {
	// contains filtered or unexported fields
}

func (*ConnWatcher) Count

func (cw *ConnWatcher) Count() int

func (*ConnWatcher) StateChange

func (cw *ConnWatcher) StateChange(conn net.Conn, state http.ConnState)

type Conversation

type Conversation struct {
	ID          int
	Link        string
	CreatedBy   int
	CreatedAt   time.Time
	LastReplyBy int
	LastReplyAt time.Time
}

func (*Conversation) Create

func (co *Conversation) Create() (int, error)

func (*Conversation) Has

func (co *Conversation) Has(uid int) (in bool)

func (*Conversation) Posts

func (co *Conversation) Posts(offset, itemsPerPage int) (posts []*ConversationPost, err error)

func (*Conversation) PostsCount

func (co *Conversation) PostsCount() (count int)

func (*Conversation) Uids

func (co *Conversation) Uids() (ids []int, err error)

func (*Conversation) Update

func (co *Conversation) Update() error

type ConversationExtra

type ConversationExtra struct {
	*Conversation
	Users []*User
}

type ConversationPost

type ConversationPost struct {
	ID        int
	CID       int
	Body      string
	Post      string // aes, ”
	CreatedBy int
}

func (*ConversationPost) Create

func (co *ConversationPost) Create() (int, error)

func (*ConversationPost) Delete

func (co *ConversationPost) Delete() error

func (*ConversationPost) Fetch

func (co *ConversationPost) Fetch() error

TODO: Should we run OnLoad on this? Or maybe add a FetchMeta method to avoid having to decode the message when it's not necessary?

func (*ConversationPost) Update

func (co *ConversationPost) Update() error

type ConversationStore

type ConversationStore interface {
	Get(id int) (*Conversation, error)
	GetUser(uid, offset int) (cos []*Conversation, err error)
	GetUserExtra(uid, offset int) (cos []*ConversationExtra, err error)
	GetUserCount(uid int) (count int)
	Delete(id int) error
	Count() (count int)
	Create(content string, createdBy int, participants []int) (int, error)
}
var Convos ConversationStore

type ConvoCreatePage

type ConvoCreatePage struct {
	*Header
	RecpName string
}

type ConvoListPage

type ConvoListPage struct {
	*Header
	Convos []ConvoListRow
	Paginator
}

type ConvoListRow

type ConvoListRow struct {
	*ConversationExtra
	ShortUsers []*User
	OneOnOne   bool
}

type ConvoPostProcessor

type ConvoPostProcessor interface {
	OnLoad(co *ConversationPost) (*ConversationPost, error)
	OnSave(co *ConversationPost) (*ConversationPost, error)
}

type ConvoStmts

type ConvoStmts struct {
	// contains filtered or unexported fields
}

type ConvoViewPage

type ConvoViewPage struct {
	*Header
	Convo    *Conversation
	Posts    []ConvoViewRow
	Users    []*User
	CanReply bool
	Paginator
}

type ConvoViewRow

type ConvoViewRow struct {
	*ConversationPost
	User         *User
	ClassName    string
	ContentLines int

	CanModify bool
}

type CreateTopicPage

type CreateTopicPage struct {
	*Header
	ItemList []Forum
	FID      int
}

type CustomPage

type CustomPage struct {
	ID            int
	Name          string // TODO: Let admins put pages in "virtual subdirectories"
	Title         string
	Body          string
	AllowedGroups []int
	MenuID        int
}

func BlankCustomPage

func BlankCustomPage() *CustomPage

func (*CustomPage) AddAllowedGroup

func (p *CustomPage) AddAllowedGroup(gid int)

func (*CustomPage) Commit

func (p *CustomPage) Commit() error

func (*CustomPage) Create

func (p *CustomPage) Create() (int, error)

type CustomPagePage

type CustomPagePage struct {
	*Header
	Page *CustomPage
}

type CustomPageStmts

type CustomPageStmts struct {
	// contains filtered or unexported fields
}

type DashGrids

type DashGrids struct {
	Grid1 []GridElement
	Grid2 []GridElement
}

type DataCache

type DataCache interface {
	CacheGet(id int) (interface{}, error)
	CacheGetUnsafe(id int) (interface{}, error)
	CacheSet(item interface{}) error
	CacheAdd(item interface{}) error
	CacheAddUnsafe(item interface{}) error
	CacheRemove(id int) error
	CacheRemoveUnsafe(id int) error
	Reload(id int) error
	Flush()
	Length() int
	SetCapacity(capacity int)
	GetCapacity() int
}

nolint

type DataStore

type DataStore interface {
	DirtyGet(id int) interface{}
	Get(id int) (interface{}, error)
	BypassGet(id int) (interface{}, error)
}

nolint

type DebugPageCache

type DebugPageCache struct {
	Topics  int
	Users   int
	Replies int

	TCap int
	UCap int
	RCap int

	TopicListThaw bool
}

type DebugPageDatabase

type DebugPageDatabase struct {
	Topics         int
	Users          int
	Replies        int
	ProfileReplies int
	ActivityStream int
	Likes          int
	Attachments    int
	Polls          int

	LoginLogs int
	RegLogs   int
	ModLogs   int
	AdminLogs int

	Views          int
	ViewsAgents    int
	ViewsForums    int
	ViewsLangs     int
	ViewsReferrers int
	ViewsSystems   int
	PostChunks     int
	TopicChunks    int
}

type DebugPageDisk

type DebugPageDisk struct {
	Static      int
	Attachments int
	Avatars     int
	Logs        int
	Backups     int
	Git         int
}

type DebugPageTasks

type DebugPageTasks struct {
	HalfSecond    int
	Second        int
	FifteenMinute int
	Hour          int
	Day           int
	Shutdown      int
}

type DefaultActivityStream

type DefaultActivityStream struct {
	// contains filtered or unexported fields
}

func NewDefaultActivityStream

func NewDefaultActivityStream(acc *qgen.Accumulator) (*DefaultActivityStream, error)

func (*DefaultActivityStream) Add

func (s *DefaultActivityStream) Add(a Alert) (int, error)

func (*DefaultActivityStream) AidsByParams

func (s *DefaultActivityStream) AidsByParams(event string, elementID int, elementType string) (aids []int, err error)

func (*DefaultActivityStream) AidsByParamsExtra

func (s *DefaultActivityStream) AidsByParamsExtra(event string, elementID int, elementType, extra string) (aids []int, e error)

func (*DefaultActivityStream) Count

func (s *DefaultActivityStream) Count() (count int)

Count returns the total number of activity stream items

func (*DefaultActivityStream) Delete

func (s *DefaultActivityStream) Delete(id int) error

func (*DefaultActivityStream) DeleteByParams

func (s *DefaultActivityStream) DeleteByParams(event string, elementID int, elementType string) error

func (*DefaultActivityStream) DeleteByParamsExtra

func (s *DefaultActivityStream) DeleteByParamsExtra(event string, elementID int, elementType, extra string) error

func (*DefaultActivityStream) Get

func (s *DefaultActivityStream) Get(id int) (Alert, error)

type DefaultActivityStreamMatches

type DefaultActivityStreamMatches struct {
	// contains filtered or unexported fields
}

func NewDefaultActivityStreamMatches

func NewDefaultActivityStreamMatches(acc *qgen.Accumulator) (*DefaultActivityStreamMatches, error)

func (*DefaultActivityStreamMatches) Add

func (s *DefaultActivityStreamMatches) Add(watcher, asid int) error

func (*DefaultActivityStreamMatches) CountAsid

func (s *DefaultActivityStreamMatches) CountAsid(asid int) int

func (*DefaultActivityStreamMatches) Delete

func (s *DefaultActivityStreamMatches) Delete(watcher, asid int) error

func (*DefaultActivityStreamMatches) DeleteAndCountChanged

func (s *DefaultActivityStreamMatches) DeleteAndCountChanged(watcher, asid int) (int, error)

type DefaultAnalytics

type DefaultAnalytics struct {
}

func NewDefaultAnalytics

func NewDefaultAnalytics() *DefaultAnalytics

func (*DefaultAnalytics) FillViewMap

func (s *DefaultAnalytics) FillViewMap(tbl string, tr *AnalyticsTimeRange, labelList []int64, viewMap map[int64]int64, param string, args ...interface{}) (map[int64]int64, error)

type DefaultAttachmentStore

type DefaultAttachmentStore struct {
	// contains filtered or unexported fields
}

func NewDefaultAttachmentStore

func NewDefaultAttachmentStore(acc *qgen.Accumulator) (*DefaultAttachmentStore, error)

func (*DefaultAttachmentStore) Add

func (s *DefaultAttachmentStore) Add(sectionID int, sectionTable string, originID int, originTable string, uploadedBy int, path, extra string) (int, error)

func (*DefaultAttachmentStore) AddLinked

func (s *DefaultAttachmentStore) AddLinked(otable string, oid int) (err error)

TODO: Split this out of this store

func (*DefaultAttachmentStore) BulkMiniGetList

func (s *DefaultAttachmentStore) BulkMiniGetList(originTable string, ids []int) (amap map[int][]*MiniAttachment, err error)

func (*DefaultAttachmentStore) Count

func (s *DefaultAttachmentStore) Count() (count int)

func (*DefaultAttachmentStore) CountIn

func (s *DefaultAttachmentStore) CountIn(originTable string, oid int) (count int)

func (*DefaultAttachmentStore) CountInPath

func (s *DefaultAttachmentStore) CountInPath(path string) (count int)

func (*DefaultAttachmentStore) Delete

func (s *DefaultAttachmentStore) Delete(id int) error

func (*DefaultAttachmentStore) FGet

func (s *DefaultAttachmentStore) FGet(id int) (*Attachment, error)

func (*DefaultAttachmentStore) Get

func (*DefaultAttachmentStore) GetForRenderRoute

func (s *DefaultAttachmentStore) GetForRenderRoute(filename string, sid int, sectionTable string) (*Attachment, error)

TODO: Revamp this to make it less of a copy-paste from the original code in the route ! Lacks some attachment initialisation code

func (*DefaultAttachmentStore) MiniGetList

func (s *DefaultAttachmentStore) MiniGetList(originTable string, originID int) (alist []*MiniAttachment, err error)

func (*DefaultAttachmentStore) MoveTo

func (s *DefaultAttachmentStore) MoveTo(sectionID, originID int, originTable string) error

func (*DefaultAttachmentStore) MoveToByExtra

func (s *DefaultAttachmentStore) MoveToByExtra(sectionID int, originTable, extra string) error

func (*DefaultAttachmentStore) RemoveLinked

func (s *DefaultAttachmentStore) RemoveLinked(otable string, oid int) (err error)

TODO: Split this out of this store

type DefaultAuth

type DefaultAuth struct {
	// contains filtered or unexported fields
}

DefaultAuth is the default authenticator used by Gosora, may be swapped with an alternate authenticator in some situations. E.g. To support LDAP.

func NewDefaultAuth

func NewDefaultAuth() (*DefaultAuth, error)

NewDefaultAuth is a factory for spitting out DefaultAuths

func (*DefaultAuth) Authenticate

func (auth *DefaultAuth) Authenticate(name, password string) (uid int, err error, requiresExtraAuth bool)

Authenticate checks if a specific username and password is valid and returns the UID for the corresponding user, if so. Otherwise, a user safe error. IF MFA is enabled, then pass it back a flag telling the caller that authentication isn't complete yet TODO: Find a better way of handling errors we don't want to reach the user

func (*DefaultAuth) CreateProvisionalSession

func (auth *DefaultAuth) CreateProvisionalSession(uid int) (provSession, signedSession string, err error)

func (*DefaultAuth) CreateSession

func (auth *DefaultAuth) CreateSession(uid int) (session string, err error)

CreateSession generates a new session to allow a remote client to stay logged in as a specific user

func (*DefaultAuth) ForceLogout

func (auth *DefaultAuth) ForceLogout(uid int) error

ForceLogout logs the user out of every computer, not just the one they logged out of

func (*DefaultAuth) GetCookies

func (auth *DefaultAuth) GetCookies(r *http.Request) (uid int, session string, err error)

GetCookies fetches the current user's session cookies

func (*DefaultAuth) Logout

func (auth *DefaultAuth) Logout(w http.ResponseWriter, _ int)

Logout logs you out of the computer you requested the logout for, but not the other computers you're logged in with

func (*DefaultAuth) SessionCheck

func (auth *DefaultAuth) SessionCheck(w http.ResponseWriter, r *http.Request) (user *User, halt bool)

SessionCheck checks if a user has session cookies and whether they're valid

func (*DefaultAuth) SetCookies

func (auth *DefaultAuth) SetCookies(w http.ResponseWriter, uid int, session string)

TODO: Set the cookie domain SetCookies sets the two cookies required for the current user to be recognised as a specific user in future requests

func (*DefaultAuth) SetProvisionalCookies

func (auth *DefaultAuth) SetProvisionalCookies(w http.ResponseWriter, uid int, provSession, signedSession string)

TODO: Set the cookie domain SetProvisionalCookies sets the two cookies required for guests to be recognised as having passed the initial login but not having passed the additional checks (e.g. multi-factor authentication)

func (*DefaultAuth) ValidateMFAToken

func (auth *DefaultAuth) ValidateMFAToken(mfaToken string, uid int) error

type DefaultBlockStore

type DefaultBlockStore struct {
	// contains filtered or unexported fields
}

func NewDefaultBlockStore

func NewDefaultBlockStore(acc *qgen.Accumulator) (*DefaultBlockStore, error)

func (*DefaultBlockStore) Add

func (s *DefaultBlockStore) Add(blocker, blockee int) error

func (*DefaultBlockStore) BlockedByCount

func (s *DefaultBlockStore) BlockedByCount(blocker int) (count int)

func (*DefaultBlockStore) BlockedByOffset

func (s *DefaultBlockStore) BlockedByOffset(blocker, offset, perPage int) (uids []int, err error)

func (*DefaultBlockStore) BulkIsBlockedBy

func (s *DefaultBlockStore) BulkIsBlockedBy(blockers []int, blockee int) (bool, error)

TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts?

func (*DefaultBlockStore) IsBlockedBy

func (s *DefaultBlockStore) IsBlockedBy(blocker, blockee int) (bool, error)

func (*DefaultBlockStore) Remove

func (s *DefaultBlockStore) Remove(blocker, blockee int) error

type DefaultConversationStore

type DefaultConversationStore struct {
	// contains filtered or unexported fields
}

func NewDefaultConversationStore

func NewDefaultConversationStore(acc *qgen.Accumulator) (*DefaultConversationStore, error)

func (*DefaultConversationStore) Count

func (s *DefaultConversationStore) Count() (count int)

Count returns the total number of topics on these forums

func (*DefaultConversationStore) Create

func (s *DefaultConversationStore) Create(content string, createdBy int, participants []int) (int, error)

func (*DefaultConversationStore) Delete

func (s *DefaultConversationStore) Delete(id int) error

TODO: Use a foreign key or transaction

func (*DefaultConversationStore) Get

func (*DefaultConversationStore) GetUser

func (s *DefaultConversationStore) GetUser(uid, offset int) (cos []*Conversation, err error)

func (*DefaultConversationStore) GetUserCount

func (s *DefaultConversationStore) GetUserCount(uid int) (count int)

func (*DefaultConversationStore) GetUserExtra

func (s *DefaultConversationStore) GetUserExtra(uid, offset int) (cos []*ConversationExtra, err error)

type DefaultConvoPostProcessor

type DefaultConvoPostProcessor struct {
}

func NewDefaultConvoPostProcessor

func NewDefaultConvoPostProcessor() *DefaultConvoPostProcessor

func (*DefaultConvoPostProcessor) OnLoad

func (*DefaultConvoPostProcessor) OnSave

type DefaultEmailStore

type DefaultEmailStore struct {
	// contains filtered or unexported fields
}

func NewDefaultEmailStore

func NewDefaultEmailStore(acc *qgen.Accumulator) (*DefaultEmailStore, error)

func (*DefaultEmailStore) Add

func (s *DefaultEmailStore) Add(uid int, email, token string) error

func (*DefaultEmailStore) Delete

func (s *DefaultEmailStore) Delete(uid int, email string) error

func (*DefaultEmailStore) Get

func (s *DefaultEmailStore) Get(user *User, email string) (Email, error)

func (*DefaultEmailStore) GetEmailsByUser

func (s *DefaultEmailStore) GetEmailsByUser(user *User) (emails []Email, err error)

func (*DefaultEmailStore) VerifyEmail

func (s *DefaultEmailStore) VerifyEmail(email string) error

type DefaultForumActionStore

type DefaultForumActionStore struct {
	// contains filtered or unexported fields
}

func NewDefaultForumActionStore

func NewDefaultForumActionStore(acc *qgen.Accumulator) (*DefaultForumActionStore, error)

func (*DefaultForumActionStore) Add

func (*DefaultForumActionStore) Count

func (s *DefaultForumActionStore) Count() (count int)

func (*DefaultForumActionStore) CountInForum

func (s *DefaultForumActionStore) CountInForum(fid int) (count int)

func (*DefaultForumActionStore) DailyTick

func (s *DefaultForumActionStore) DailyTick() error

func (*DefaultForumActionStore) Delete

func (s *DefaultForumActionStore) Delete(id int) error

func (*DefaultForumActionStore) Exists

func (s *DefaultForumActionStore) Exists(id int) bool

func (*DefaultForumActionStore) Get

func (*DefaultForumActionStore) GetAll

func (s *DefaultForumActionStore) GetAll() (fas []*ForumAction, e error)

func (*DefaultForumActionStore) GetInForum

func (s *DefaultForumActionStore) GetInForum(fid int) (fas []*ForumAction, e error)

func (*DefaultForumActionStore) GetNewTopicActions

func (s *DefaultForumActionStore) GetNewTopicActions(fid int) (fas []*ForumAction, e error)

type DefaultFriendStore

type DefaultFriendStore struct {
	// contains filtered or unexported fields
}

func NewDefaultFriendStore

func NewDefaultFriendStore(acc *qgen.Accumulator) (*DefaultFriendStore, error)

func (*DefaultFriendStore) AddInvite

func (s *DefaultFriendStore) AddInvite(requester, target int) error

func (*DefaultFriendStore) Confirm

func (s *DefaultFriendStore) Confirm(requester, target int) error

func (*DefaultFriendStore) GetOwnRecvInvites

func (s *DefaultFriendStore) GetOwnRecvInvites(uid int) ([]FriendInvite, error)

func (*DefaultFriendStore) GetOwnSentInvites

func (s *DefaultFriendStore) GetOwnSentInvites(uid int) ([]FriendInvite, error)

type DefaultGroupPromotionStore

type DefaultGroupPromotionStore struct {
	// contains filtered or unexported fields
}

func NewDefaultGroupPromotionStore

func NewDefaultGroupPromotionStore(acc *qgen.Accumulator) (*DefaultGroupPromotionStore, error)

func (*DefaultGroupPromotionStore) Create

func (s *DefaultGroupPromotionStore) Create(from, to int, twoWay bool, level, posts, registeredFor int) (int, error)

func (*DefaultGroupPromotionStore) Delete

func (s *DefaultGroupPromotionStore) Delete(id int) error

func (*DefaultGroupPromotionStore) Get

TODO: Cache the group promotions to avoid hitting the database as much

func (*DefaultGroupPromotionStore) GetByGroup

func (s *DefaultGroupPromotionStore) GetByGroup(gid int) (gps []*GroupPromotion, err error)

func (*DefaultGroupPromotionStore) PromoteIfEligible

func (s *DefaultGroupPromotionStore) PromoteIfEligible(u *User, level, posts int, registeredAt time.Time) error

TODO: Optimise this to avoid the query

func (*DefaultGroupPromotionStore) Tick

type DefaultIPSearcher

type DefaultIPSearcher struct {
	// contains filtered or unexported fields
}

func NewDefaultIPSearcher

func NewDefaultIPSearcher() (*DefaultIPSearcher, error)

NewDefaultIPSearcher gives you a new instance of DefaultIPSearcher

func (*DefaultIPSearcher) Lookup

func (s *DefaultIPSearcher) Lookup(ip string) (uids []int, e error)

type DefaultLikeStore

type DefaultLikeStore struct {
	// contains filtered or unexported fields
}

func NewDefaultLikeStore

func NewDefaultLikeStore(acc *qgen.Accumulator) (*DefaultLikeStore, error)

func (*DefaultLikeStore) BulkExists

func (s *DefaultLikeStore) BulkExists(ids []int, sentBy int, targetType string) (eids []int, e error)

TODO: Write a test for this

func (*DefaultLikeStore) BulkExistsFunc

func (s *DefaultLikeStore) BulkExistsFunc(ids []int, sentBy int, targetType string, f func(id int) error) (e error)

TODO: Write a test for this

func (*DefaultLikeStore) Count

func (s *DefaultLikeStore) Count() (count int)

TODO: Write a test for this Count returns the total number of likes globally

func (*DefaultLikeStore) Delete

func (s *DefaultLikeStore) Delete(targetID int, targetType string) error

type DefaultMenuItemStore

type DefaultMenuItemStore struct {
	// contains filtered or unexported fields
}

func NewDefaultMenuItemStore

func NewDefaultMenuItemStore() *DefaultMenuItemStore

func (*DefaultMenuItemStore) Add

func (s *DefaultMenuItemStore) Add(i MenuItem)

func (*DefaultMenuItemStore) Get

func (s *DefaultMenuItemStore) Get(id int) (MenuItem, error)

type DefaultMenuStore

type DefaultMenuStore struct {
	// contains filtered or unexported fields
}
var Menus *DefaultMenuStore

func NewDefaultMenuStore

func NewDefaultMenuStore() *DefaultMenuStore

func (*DefaultMenuStore) Get

func (s *DefaultMenuStore) Get(mid int) (*MenuListHolder, error)

func (*DefaultMenuStore) GetAllMap

func (s *DefaultMenuStore) GetAllMap() (out map[int]*MenuListHolder)

TODO: Add actual support for multiple menus

func (*DefaultMenuStore) ItemStore

func (s *DefaultMenuStore) ItemStore() *DefaultMenuItemStore

func (*DefaultMenuStore) Items

func (s *DefaultMenuStore) Items(mid int) (mlist MenuItemList, err error)

func (*DefaultMenuStore) Load

func (s *DefaultMenuStore) Load(mid int) error

type DefaultPageStore

type DefaultPageStore struct {
	// contains filtered or unexported fields
}

TODO: Add a cache to this to save on the queries

func NewDefaultPageStore

func NewDefaultPageStore(acc *qgen.Accumulator) (*DefaultPageStore, error)

func (*DefaultPageStore) Count

func (s *DefaultPageStore) Count() (count int)

func (*DefaultPageStore) Delete

func (s *DefaultPageStore) Delete(id int) error

func (*DefaultPageStore) Get

func (s *DefaultPageStore) Get(id int) (*CustomPage, error)

func (*DefaultPageStore) GetByName

func (s *DefaultPageStore) GetByName(name string) (*CustomPage, error)

func (*DefaultPageStore) GetOffset

func (s *DefaultPageStore) GetOffset(offset, perPage int) (pages []*CustomPage, err error)

func (*DefaultPageStore) Reload

func (s *DefaultPageStore) Reload(id int) error

Always returns nil as there's currently no cache

type DefaultPasswordResetter

type DefaultPasswordResetter struct {
	// contains filtered or unexported fields
}
var PasswordResetter *DefaultPasswordResetter

func NewDefaultPasswordResetter

func NewDefaultPasswordResetter(acc *qgen.Accumulator) (*DefaultPasswordResetter, error)

func (*DefaultPasswordResetter) Create

func (r *DefaultPasswordResetter) Create(email string, uid int, token string) error

func (*DefaultPasswordResetter) FlushTokens

func (r *DefaultPasswordResetter) FlushTokens(uid int) error

func (*DefaultPasswordResetter) ValidateToken

func (r *DefaultPasswordResetter) ValidateToken(uid int, token string) error

type DefaultPollStore

type DefaultPollStore struct {
	// contains filtered or unexported fields
}

func NewDefaultPollStore

func NewDefaultPollStore(cache PollCache) (*DefaultPollStore, error)

func (*DefaultPollStore) BulkGetMap

func (s *DefaultPollStore) BulkGetMap(ids []int) (list map[int]*Poll, err error)

TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts? TODO: ID of 0 should always error?

func (*DefaultPollStore) ClearIPs

func (s *DefaultPollStore) ClearIPs() error

func (*DefaultPollStore) Count

func (s *DefaultPollStore) Count() int

func (*DefaultPollStore) Create

func (s *DefaultPollStore) Create(parent Pollable, pollType int, pollOptions map[int]string) (id int, e error)

TODO: Use a transaction for this

func (*DefaultPollStore) Exists

func (s *DefaultPollStore) Exists(id int) bool

func (*DefaultPollStore) Get

func (s *DefaultPollStore) Get(id int) (*Poll, error)

func (*DefaultPollStore) GetCache

func (s *DefaultPollStore) GetCache() PollCache

TODO: We're temporarily doing this so that you can do ucache != nil in getTopicUser. Refactor it.

func (*DefaultPollStore) Reload

func (s *DefaultPollStore) Reload(id int) error

func (*DefaultPollStore) SetCache

func (s *DefaultPollStore) SetCache(cache PollCache)

type DefaultRateLimiter

type DefaultRateLimiter struct {
	// contains filtered or unexported fields
}

func NewDefaultRateLimiter

func NewDefaultRateLimiter() *DefaultRateLimiter

func (*DefaultRateLimiter) LimitIP

func (l *DefaultRateLimiter) LimitIP(limit, ip string) error

func (*DefaultRateLimiter) LimitUser

func (l *DefaultRateLimiter) LimitUser(limit string, user int) error

type DefaultRecalc

type DefaultRecalc struct {
	// contains filtered or unexported fields
}

func NewDefaultRecalc

func NewDefaultRecalc(acc *qgen.Accumulator) (*DefaultRecalc, error)

func (*DefaultRecalc) ActivityStream

func (s *DefaultRecalc) ActivityStream() (count int, err error)

func (*DefaultRecalc) Attachments

func (s *DefaultRecalc) Attachments() (count int, err error)

func (*DefaultRecalc) Forums

func (s *DefaultRecalc) Forums() (count int, err error)

func (*DefaultRecalc) Replies

func (s *DefaultRecalc) Replies() (count int, err error)

func (*DefaultRecalc) Subscriptions

func (s *DefaultRecalc) Subscriptions() (count int, err error)

func (*DefaultRecalc) Users

func (s *DefaultRecalc) Users() error

type DefaultReportStore

type DefaultReportStore struct {
	// contains filtered or unexported fields
}

func NewDefaultReportStore

func NewDefaultReportStore(acc *qgen.Accumulator) (*DefaultReportStore, error)

func (*DefaultReportStore) Create

func (s *DefaultReportStore) Create(title, content string, u *User, itemType string, itemID int) (tid int, err error)

! There's a data race in this. If two users report one item at the exact same time, then both reports will go through

type DefaultStatStore

type DefaultStatStore struct {
}

func NewDefaultStatStore

func NewDefaultStatStore() *DefaultStatStore

func (*DefaultStatStore) LookupInt

func (s *DefaultStatStore) LookupInt(name string, duration int, unit string) (int, error)

type DefaultSubscriptionStore

type DefaultSubscriptionStore struct {
	// contains filtered or unexported fields
}

func NewDefaultSubscriptionStore

func NewDefaultSubscriptionStore() (*DefaultSubscriptionStore, error)

func (*DefaultSubscriptionStore) Add

func (s *DefaultSubscriptionStore) Add(uid, elementID int, elementType string) error

func (*DefaultSubscriptionStore) Delete

func (s *DefaultSubscriptionStore) Delete(uid, targetID int, targetType string) error

TODO: Add a primary key to the activity subscriptions table

func (*DefaultSubscriptionStore) DeleteResource

func (s *DefaultSubscriptionStore) DeleteResource(targetID int, targetType string) error

type DefaultTaskSet

type DefaultTaskSet struct {
	Tasks []func() error
}

func (*DefaultTaskSet) Add

func (s *DefaultTaskSet) Add(task func() error)

func (*DefaultTaskSet) Count

func (s *DefaultTaskSet) Count() int

func (*DefaultTaskSet) GetList

func (s *DefaultTaskSet) GetList() []func() error

func (*DefaultTaskSet) Run

func (s *DefaultTaskSet) Run() error

type DefaultThaw

type DefaultThaw struct {
	// contains filtered or unexported fields
}

func NewDefaultThaw

func NewDefaultThaw() *DefaultThaw

func (*DefaultThaw) Thaw

func (t *DefaultThaw) Thaw()

func (*DefaultThaw) Thawed

func (t *DefaultThaw) Thawed() bool

func (*DefaultThaw) Tick

func (t *DefaultThaw) Tick() error

Decrement the thawed counter once a second until it goes cold

type DefaultTopicList

type DefaultTopicList struct {
	// contains filtered or unexported fields
}

func NewDefaultTopicList

func NewDefaultTopicList(acc *qgen.Accumulator) (*DefaultTopicList, error)

We've removed the topic list cache cap as admins really shouldn't be abusing groups like this with plugin_guilds around and it was extremely fiddly. If this becomes a problem later on, then we can revisit this with a fresh perspective, particularly with regards to what people expect a group to really be Also, keep in mind that as-long as the groups don't all have unique sets of forums they can see, then we can optimise a large portion of the work away.

func (*DefaultTopicList) GetList

func (tList *DefaultTopicList) GetList(page, orderby int, filterIDs []int) (topicList []*TopicsRow, forumList []Forum, pagi Paginator, err error)

TODO: Reduce the number of returns

func (*DefaultTopicList) GetListByCanSee

func (tList *DefaultTopicList) GetListByCanSee(canSee []int, page, orderby int, filterIDs []int) (topicList []*TopicsRow, forumList []Forum, pagi Paginator, err error)

func (*DefaultTopicList) GetListByForum

func (tList *DefaultTopicList) GetListByForum(f *Forum, page, orderby int) (topicList []*TopicsRow, pagi Paginator, err error)

TODO: Add Topics() method to *Forum? TODO: Implement orderby

func (*DefaultTopicList) GetListByGroup

func (tList *DefaultTopicList) GetListByGroup(g *Group, page, orderby int, filterIDs []int) (topicList []*TopicsRow, forumList []Forum, pagi Paginator, err error)

func (*DefaultTopicList) RawGetListByForum

func (tList *DefaultTopicList) RawGetListByForum(f *Forum, page, orderby int) (topicList []*TopicsRow, pagi Paginator, err error)

func (*DefaultTopicList) Tick

func (tList *DefaultTopicList) Tick() error

type DefaultTopicStore

type DefaultTopicStore struct {
	// contains filtered or unexported fields
}

func NewDefaultTopicStore

func NewDefaultTopicStore(cache TopicCache) (*DefaultTopicStore, error)

NewDefaultTopicStore gives you a new instance of DefaultTopicStore

func (*DefaultTopicStore) AddLastTopic

func (s *DefaultTopicStore) AddLastTopic(t *Topic, fid int) error

? - What is this? Do we need it? Should it be in the main store interface?

func (*DefaultTopicStore) BulkGetMap

func (s *DefaultTopicStore) BulkGetMap(ids []int) (list map[int]*Topic, e error)

TODO: Avoid duplicating much of this logic from user_store.go

func (*DefaultTopicStore) BypassGet

func (s *DefaultTopicStore) BypassGet(id int) (*Topic, error)

BypassGet will always bypass the cache and pull the topic directly from the database

func (*DefaultTopicStore) ClearIPs

func (s *DefaultTopicStore) ClearIPs() error

func (*DefaultTopicStore) Count

func (s *DefaultTopicStore) Count() (count int)

Count returns the total number of topics on these forums

func (*DefaultTopicStore) CountBigUser

func (s *DefaultTopicStore) CountBigUser(uid int) (count int)

func (*DefaultTopicStore) CountMegaUser

func (s *DefaultTopicStore) CountMegaUser(uid int) (count int)

func (*DefaultTopicStore) CountUser

func (s *DefaultTopicStore) CountUser(uid int) (count int)

func (*DefaultTopicStore) Create

func (s *DefaultTopicStore) Create(fid int, name, content string, uid int, ip string) (tid int, err error)

func (*DefaultTopicStore) DirtyGet

func (s *DefaultTopicStore) DirtyGet(id int) *Topic

func (*DefaultTopicStore) Exists

func (s *DefaultTopicStore) Exists(id int) bool

func (*DefaultTopicStore) Get

func (s *DefaultTopicStore) Get(id int) (t *Topic, e error)

TODO: Log weird cache errors?

func (*DefaultTopicStore) GetCache

func (s *DefaultTopicStore) GetCache() TopicCache

TODO: We're temporarily doing this so that you can do tcache != nil in getTopicUser. Refactor it.

func (*DefaultTopicStore) LockMany

func (s *DefaultTopicStore) LockMany(tids []int) (e error)

func (*DefaultTopicStore) Reload

func (s *DefaultTopicStore) Reload(id int) error

func (*DefaultTopicStore) SetCache

func (s *DefaultTopicStore) SetCache(cache TopicCache)

type DefaultUserStore

type DefaultUserStore struct {
	// contains filtered or unexported fields
}

func NewDefaultUserStore

func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error)

NewDefaultUserStore gives you a new instance of DefaultUserStore

func (*DefaultUserStore) BulkGetByName

func (s *DefaultUserStore) BulkGetByName(names []string) (list []*User, err error)

TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts? ! This bypasses the cache, use frugally

func (*DefaultUserStore) BulkGetMap

func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error)

TODO: Optimise the query to avoid preparing it on the spot? Maybe, use knowledge of the most common IN() parameter counts? TODO: ID of 0 should always error?

func (*DefaultUserStore) BypassGet

func (s *DefaultUserStore) BypassGet(id int) (*User, error)

func (*DefaultUserStore) ClearLastIPs

func (s *DefaultUserStore) ClearLastIPs() error

func (*DefaultUserStore) Count

func (s *DefaultUserStore) Count() (count int)

Count returns the total number of users registered on the forums

func (*DefaultUserStore) CountSearch

func (s *DefaultUserStore) CountSearch(name, email string, gid int) (count int)

func (*DefaultUserStore) Create

func (s *DefaultUserStore) Create(name, password, email string, group int, active bool) (int, error)

TODO: Change active to a bool? TODO: Use unique keys for the usernames

func (*DefaultUserStore) DirtyGet

func (s *DefaultUserStore) DirtyGet(id int) *User

func (*DefaultUserStore) Each

func (s *DefaultUserStore) Each(f func(*User) error) error

func (*DefaultUserStore) Exists

func (s *DefaultUserStore) Exists(id int) bool

func (*DefaultUserStore) Get

func (s *DefaultUserStore) Get(id int) (*User, error)

TODO: Log weird cache errors? Not just here but in every *Cache?

func (*DefaultUserStore) GetByName

func (s *DefaultUserStore) GetByName(name string) (*User, error)

TODO: Log weird cache errors? Not just here but in every *Cache? ! This bypasses the cache, use frugally

func (*DefaultUserStore) GetCache

func (s *DefaultUserStore) GetCache() UserCache

TODO: We're temporarily doing this so that you can do ucache != nil in getTopicUser. Refactor it.

func (*DefaultUserStore) GetOffset

func (s *DefaultUserStore) GetOffset(offset, perPage int) (users []*User, err error)

TODO: Optimise this, so we don't wind up hitting the database every-time for small gaps TODO: Make this a little more consistent with DefaultGroupStore's GetRange method

func (*DefaultUserStore) Getn

func (s *DefaultUserStore) Getn(id int) *User

func (*DefaultUserStore) RawBulkGetByNameForConvo

func (s *DefaultUserStore) RawBulkGetByNameForConvo(f func(int, string, int, bool, int, int) error, names []string) error

Special case function for efficiency

func (*DefaultUserStore) Reload

func (s *DefaultUserStore) Reload(id int) error

func (*DefaultUserStore) SearchOffset

func (s *DefaultUserStore) SearchOffset(name, email string, gid, offset, perPage int) (users []*User, err error)

func (*DefaultUserStore) SetCache

func (s *DefaultUserStore) SetCache(cache UserCache)

type DefaultWidgetStore

type DefaultWidgetStore struct {
	sync.RWMutex
	// contains filtered or unexported fields
}
var Widgets *DefaultWidgetStore

func NewDefaultWidgetStore

func NewDefaultWidgetStore() *DefaultWidgetStore

func (*DefaultWidgetStore) Get

func (s *DefaultWidgetStore) Get(id int) (*Widget, error)

type DefaultWordFilterStore

type DefaultWordFilterStore struct {
	// contains filtered or unexported fields
}

func NewDefaultWordFilterStore

func NewDefaultWordFilterStore(acc *qgen.Accumulator) (*DefaultWordFilterStore, error)

func (*DefaultWordFilterStore) Count

func (s *DefaultWordFilterStore) Count() (count int)

Count gets the total number of word filters directly from the database

func (*DefaultWordFilterStore) Create

func (s *DefaultWordFilterStore) Create(find, replace string) (int, error)

Create adds a new word filter to the database and refreshes the memory cache

func (*DefaultWordFilterStore) Delete

func (s *DefaultWordFilterStore) Delete(id int) error

Delete removes a word filter from the database and refreshes the memory cache

func (*DefaultWordFilterStore) EstCount

func (s *DefaultWordFilterStore) EstCount() int

EstCount provides the same result as Length(), intended for alternate implementations of WordFilterStore, so that Length is the number of items in cache, if only a subset is held there and EstCount is the total count

func (*DefaultWordFilterStore) Get

func (s *DefaultWordFilterStore) Get(id int) (*WordFilter, error)

func (*DefaultWordFilterStore) GetAll

func (s *DefaultWordFilterStore) GetAll() (filters map[int]*WordFilter, err error)

GetAll returns all of the word filters in a map. Do note mutate this map (or maps returned from any store not explicitly noted as copies) as multiple threads may be accessing it at once

func (*DefaultWordFilterStore) Length

func (s *DefaultWordFilterStore) Length() int

Length gets the number of word filters currently in memory, for the DefaultWordFilterStore, this should be all of them

func (*DefaultWordFilterStore) ReloadAll

func (s *DefaultWordFilterStore) ReloadAll() error

ReloadAll drops all the items in the memory cache and replaces them with fresh copies from the database

func (*DefaultWordFilterStore) Update

func (s *DefaultWordFilterStore) Update(id int, find, replace string) error

type ElasticSearchSearcher

type ElasticSearchSearcher struct {
}

TODO: Implement this

func NewElasticSearchSearcher

func NewElasticSearchSearcher() (*ElasticSearchSearcher, error)

func (*ElasticSearchSearcher) Query

func (s *ElasticSearchSearcher) Query(q string, zones []int) ([]int, error)

type Email

type Email struct {
	UserID    int
	Email     string
	Validated bool
	Primary   bool
	Token     string
}

type EmailListPage

type EmailListPage struct {
	*Header
	ItemList []Email
}

type EmailStore

type EmailStore interface {
	// TODO: Add an autoincrement key
	Get(u *User, email string) (Email, error)
	GetEmailsByUser(u *User) (emails []Email, err error)
	Add(uid int, email, token string) error
	Delete(uid int, email string) error
	VerifyEmail(email string) error
}
var Emails EmailStore

type ErrorItem

type ErrorItem struct {
	Stack []byte
	// contains filtered or unexported fields
}

type ErrorPage

type ErrorPage struct {
	*Header
	Message string
}

type Existable

type Existable interface {
	Exists(id int) bool
}

type ExtData

type ExtData struct {
	Items map[string]interface{} // Key: pluginname
	sync.RWMutex
}

TODO: Add a ExtDataHolder interface with methods for manipulating the contents? ? - Could we use a sync.Map instead?

type ExtendStmts

type ExtendStmts struct {
	// contains filtered or unexported fields
}

type Forum

type Forum struct {
	ID         int
	Link       string
	Name       string
	Desc       string
	Tmpl       string
	Active     bool
	Order      int
	Preset     string
	ParentID   int
	ParentType string
	TopicCount int

	LastTopic     *Topic
	LastTopicID   int
	LastReplyer   *User
	LastReplyerID int
	LastTopicTime string // So that we can re-calculate the relative time on the spot in /forums/
	LastPage      int
}

func BlankForum

func BlankForum(fid int, link, name, desc string, active bool, preset string, parentID int, parentType string, topicCount int) *Forum

! Don't use this outside of tests and possibly template_init.go

func (*Forum) Copy

func (f *Forum) Copy() (fcopy Forum)

Copy gives you a non-pointer concurrency safe copy of the forum

func (*Forum) SetPerms

func (f *Forum) SetPerms(fperms *ForumPerms, preset string, gid int) (err error)

TODO: Refactor this

func (*Forum) SetPreset

func (f *Forum) SetPreset(preset string, gid int) error

func (*Forum) Update

func (f *Forum) Update(name, desc string, active bool, preset string) error

TODO: Write tests for this

type ForumAction

type ForumAction struct {
	ID                         int
	Forum                      int
	RunOnTopicCreation         bool
	RunDaysAfterTopicCreation  int
	RunDaysAfterTopicLastReply int
	Action                     int
	Extra                      string
}

func (*ForumAction) Run

func (a *ForumAction) Run() error

func (*ForumAction) TopicCreation

func (a *ForumAction) TopicCreation(tid int) error

type ForumActionAction

type ForumActionAction struct {
	*ForumAction
	ActionName string
}

type ForumActionStmts

type ForumActionStmts struct {
	// contains filtered or unexported fields
}

type ForumActionStoreInt

type ForumActionStoreInt interface {
	Get(faid int) (*ForumAction, error)
	GetInForum(fid int) ([]*ForumAction, error)
	GetAll() ([]*ForumAction, error)
	GetNewTopicActions(fid int) ([]*ForumAction, error)

	Add(fa *ForumAction) (int, error)
	Delete(faid int) error
	Exists(faid int) bool
	Count() int
	CountInForum(fid int) int

	DailyTick() error
}
var ForumActionStore ForumActionStoreInt

type ForumAdmin

type ForumAdmin struct {
	ID         int
	Name       string
	Desc       string
	Active     bool
	Preset     string
	TopicCount int
	PresetLang string
}

TODO: Do we really need this?

type ForumCache

type ForumCache interface {
	CacheGet(id int) (*Forum, error)
	CacheSet(f *Forum) error
	CacheDelete(id int)
	Length() int
}

type ForumPage

type ForumPage struct {
	*Header
	ItemList []TopicsRowMut
	Forum    *Forum
	CanLock  bool
	CanMove  bool
	Paginator
}

type ForumPerms

type ForumPerms struct {
	ViewTopic bool
	//ViewOwnTopic bool
	LikeItem    bool
	CreateTopic bool
	EditTopic   bool
	DeleteTopic bool
	CreateReply bool
	//CreateReplyToOwn bool
	EditReply bool
	//EditOwnReply bool
	DeleteReply bool
	PinTopic    bool
	CloseTopic  bool
	//CloseOwnTopic bool
	MoveTopic bool

	Overrides bool
	ExtData   map[string]bool
}

TODO: Rename this to ForumPermSet?

Inherit from group permissions for ones we don't have

func AllForumPerms

func AllForumPerms() *ForumPerms

AllForumPerms is a set of forum local permissions with everything set to true

func BlankForumPerms

func BlankForumPerms() *ForumPerms

func GroupForumPresetToForumPerms

func GroupForumPresetToForumPerms(preset string) (fperms *ForumPerms, changed bool)

func ReadForumPerms

func ReadForumPerms() *ForumPerms

func ReadReplyForumPerms

func ReadReplyForumPerms() *ForumPerms

func ReadWriteForumPerms

func ReadWriteForumPerms() *ForumPerms

type ForumPermsCache

type ForumPermsCache interface {
}

type ForumPermsStore

type ForumPermsStore interface {
	Init() error
	GetAllMap() (bigMap map[int]map[int]*ForumPerms)
	Get(fid, gid int) (fp *ForumPerms, err error)
	GetCopy(fid, gid int) (fp ForumPerms, err error)
	ReloadAll() error
	Reload(id int) error
}
var FPStore ForumPermsStore

type ForumSimple

type ForumSimple struct {
	ID     int
	Name   string
	Active bool
	Preset string
}

? - What is this for?

type ForumStmts

type ForumStmts struct {
	// contains filtered or unexported fields
}

type ForumStore

type ForumStore interface {
	LoadForums() error
	Each(h func(*Forum) error) error
	DirtyGet(id int) *Forum
	Get(id int) (*Forum, error)
	BypassGet(id int) (*Forum, error)
	BulkGetCopy(ids []int) (forums []Forum, err error)
	Reload(id int) error // ? - Should we move this to ForumCache? It might require us to do some unnecessary casting though
	//Update(Forum) error
	Delete(id int) error
	AddTopic(tid, uid, fid int) error
	RemoveTopic(fid int) error
	RemoveTopics(fid, count int) error
	UpdateLastTopic(tid, uid, fid int) error
	Exists(id int) bool
	GetAll() ([]*Forum, error)
	GetAllIDs() ([]int, error)
	GetAllVisible() ([]*Forum, error)
	GetAllVisibleIDs() ([]int, error)
	//GetChildren(parentID int, parentType string) ([]*Forum,error)
	//GetFirstChild(parentID int, parentType string) (*Forum,error)
	Create(name, desc string, active bool, preset string) (int, error)
	UpdateOrder(updateMap map[int]int) error

	Count() int
}

ForumStore is an interface for accessing the forums and the metadata stored on them

var Forums ForumStore

type ForumTopicListHolder

type ForumTopicListHolder struct {
	List      []*TopicsRow
	Paginator Paginator
}

type ForumsPage

type ForumsPage struct {
	*Header
	ItemList []Forum
}

type FriendInvite

type FriendInvite struct {
	Requester int
	Target    int
}

type FriendStore

type FriendStore interface {
	AddInvite(requester, target int) error
	Confirm(requester, target int) error
	GetOwSentInvites(uid int) ([]FriendInvite, error)
	GetOwnRecvInvites(uid int) ([]FriendInvite, error)
}

type GridElement

type GridElement struct {
	ID         string
	Href       string
	Body       string
	Order      int // For future use
	Class      string
	Background string
	TextColour string
	Note       string
}

type Group

type Group struct {
	ID              int
	Name            string
	IsMod           bool
	IsAdmin         bool
	IsBanned        bool
	Tag             string
	Perms           Perms
	PermissionsText []byte
	PluginPerms     map[string]bool // Custom permissions defined by plugins. What if two plugins declare the same permission, but they handle them in incompatible ways? Very unlikely, we probably don't need to worry about this, the plugin authors should be aware of each other to some extent
	PluginPermsText []byte
	CanSee          []int // The IDs of the forums this group can see
	UserCount       int   // ! Might be temporary as I might want to lean on the database instead for this
}

! Fix the data races in the fperms

func (*Group) ChangeRank

func (g *Group) ChangeRank(isAdmin, isMod, isBanned bool) (err error)

func (*Group) Copy

func (g *Group) Copy() Group

Copy gives you a non-pointer concurrency safe copy of the group

func (*Group) CopyPtr

func (g *Group) CopyPtr() (co *Group)

func (*Group) Update

func (g *Group) Update(name, tag string) (err error)

func (*Group) UpdatePerms

func (g *Group) UpdatePerms(perms map[string]bool) (err error)

Please don't pass arbitrary inputs to this method

type GroupAdmin

type GroupAdmin struct {
	ID        int
	Name      string
	Rank      string
	RankClass string
	CanEdit   bool
	CanDelete bool
}

type GroupCache

type GroupCache interface {
	CacheSet(g *Group) error
	SetCanSee(gid int, canSee []int) error
	CacheAdd(g *Group) error
	Length() int
}

type GroupForumPermPreset

type GroupForumPermPreset struct {
	Group         *Group
	Preset        string
	DefaultPreset bool
}

type GroupPromotion

type GroupPromotion struct {
	ID     int
	From   int
	To     int
	TwoWay bool

	Level         int
	Posts         int
	MinTime       int
	RegisteredFor int
}

type GroupPromotionExtend

type GroupPromotionExtend struct {
	*GroupPromotion
	FromGroup *Group
	ToGroup   *Group
}

type GroupPromotionStore

type GroupPromotionStore interface {
	GetByGroup(gid int) (gps []*GroupPromotion, err error)
	Get(id int) (*GroupPromotion, error)
	PromoteIfEligible(u *User, level, posts int, registeredAt time.Time) error
	Delete(id int) error
	Create(from, to int, twoWay bool, level, posts, registeredFor int) (int, error)
}
var GroupPromotions GroupPromotionStore

type GroupStmts

type GroupStmts struct {
	// contains filtered or unexported fields
}

type GroupStore

type GroupStore interface {
	LoadGroups() error
	DirtyGet(id int) *Group
	Get(id int) (*Group, error)
	GetCopy(id int) (Group, error)
	Exists(id int) bool
	Create(name, tag string, isAdmin, isMod, isBanned bool) (id int, err error)
	GetAll() ([]*Group, error)
	GetRange(lower, higher int) ([]*Group, error)
	Reload(id int) error // ? - Should we move this to GroupCache? It might require us to do some unnecessary casting though
	Count() int
}

? - We could fallback onto the database when an item can't be found in the cache?

var Groups GroupStore

type GuestAvatar

type GuestAvatar struct {
	Normal string
	Micro  string
}

type GzipResponseWriter

type GzipResponseWriter struct {
	io.Writer
	http.ResponseWriter
}

func (GzipResponseWriter) Write

func (w GzipResponseWriter) Write(b []byte) (int, error)

type HScript

type HScript struct {
	Name string
	Hash string
}
type Header struct {
	Title string
	//Title      []byte // Experimenting with []byte for increased efficiency, let's avoid converting too many things to []byte, as it involves a lot of extra boilerplate
	NoticeList      []string
	Scripts         []HScript
	PreScriptsAsync []HScript
	ScriptsAsync    []HScript
	//Preload []string
	Stylesheets []HScript
	Widgets     PageWidgets
	Site        *site
	Settings    SettingMap
	//Themes      map[string]*Theme // TODO: Use a slice containing every theme instead of the main map for speed?
	ThemesSlice []*Theme
	Theme       *Theme
	//TemplateName string // TODO: Use this to move template calls to the router rather than duplicating them over and over and over?
	CurrentUser *User // TODO: Deprecate CurrentUser on the page structs and use a pointer here
	Hooks       *HookTable
	Zone        string
	ZoneID      int
	ZoneData    interface{}
	Path        string
	MetaDesc    string
	//OGImage string
	OGDesc         string
	GoogSiteVerify string
	IsoCode        string
	LooseCSP       bool
	ExternalMedia  bool
	//StartedAt      time.Time
	StartedAt int64
	Elapsed1  string
	Writer    http.ResponseWriter
	ExtData   ExtData
}

TODO: Allow resources in spots other than /s/ and possibly even external domains (e.g. CDNs) TODO: Preload Trumboyg on Cosora on the forum list

func DefaultHeader

func DefaultHeader(w http.ResponseWriter, u *User) *Header

TODO: Write a test for this

func SimpleDefaultHeader

func SimpleDefaultHeader(w http.ResponseWriter) *Header

func (*Header) AddNotice

func (h *Header) AddNotice(name string)

func (*Header) AddPreScriptAsync

func (h *Header) AddPreScriptAsync(name string)

func (*Header) AddScript

func (h *Header) AddScript(name string)

func (*Header) AddScriptAsync

func (h *Header) AddScriptAsync(name string)

func (*Header) AddSheet

func (h *Header) AddSheet(name string)

func (*Header) AddXRes

func (h *Header) AddXRes(names ...string)

! Experimental

type HeaderLite

type HeaderLite struct {
	Site     *site
	Settings SettingMap
	Hooks    *HookTable
	ExtData  ExtData
}

TODO: Add this to routes which don't use templates. E.g. Json APIs.

type HookTable

type HookTable struct {
	//Hooks           map[string][]func(interface{}) interface{}
	HooksNoRet      map[string][]func(interface{})
	HooksSkip       map[string][]func(interface{}) bool
	Vhooks          map[string]func(...interface{}) interface{}
	VhookSkippable_ map[string]func(...interface{}) (bool, RouteError)
	Sshooks         map[string][]func(string) string
	PreRenderHooks  map[string][]func(http.ResponseWriter, *http.Request, *User, interface{}) bool
}

! HookTable is a work in progress, do not use it yet TODO: Test how fast it is to indirect hooks off the hook table as opposed to using them normally or using an interface{} for the hooks TODO: Can we filter the HookTable for each request down to only hooks the request actually uses? TODO: Make the RunXHook functions methods on HookTable TODO: Have plugins update hooks on a mutex guarded map and create a copy of that map in a serial global goroutine which gets thrown in the atomic.Value

func GetHookTable

func GetHookTable() *HookTable

func (*HookTable) HookNoRet

func (t *HookTable) HookNoRet(name string, data interface{})

func (*HookTable) HookSkip

func (t *HookTable) HookSkip(name string, data interface{}) (skip bool)

To cover the case in routes/topic.go's CreateTopic route, we could probably obsolete this use and replace it

func (*HookTable) Sshook

func (t *HookTable) Sshook(name, data string) string

Hooks which take in and spit out a string. This is usually used for parser components Trying to get a teeny bit of type-safety where-ever possible, especially for such a critical set of hooks

func (*HookTable) Vhook

func (t *HookTable) Vhook(name string, data ...interface{}) interface{}

Hooks with a variable number of arguments TODO: Use RunHook semantics to allow multiple lined up plugins / modules their turn?

func (*HookTable) VhookNeedHook

func (t *HookTable) VhookNeedHook(name string, data ...interface{}) (ret interface{}, hasHook bool)

TODO: Find a better way of doing this

func (*HookTable) VhookNoRet

func (t *HookTable) VhookNoRet(name string, data ...interface{})

func (*HookTable) VhookSkippable

func (t *HookTable) VhookSkippable(name string, data ...interface{}) (bool, RouteError)

Hooks with a variable number of arguments and return values for skipping the parent function and propagating an error upwards

type IPSearchPage

type IPSearchPage struct {
	*Header
	ItemList map[int]*User
	IP       string
}

type IPSearcher

type IPSearcher interface {
	Lookup(ip string) (uids []int, e error)
}
var IPSearch IPSearcher

type LevelListItem

type LevelListItem struct {
	Level      int
	Score      int
	Status     string
	Percentage int // 0 to 200 to fit with the CSS logic
}

type LevelListPage

type LevelListPage struct {
	*Header
	Levels []LevelListItem
}

type LikeStore

type LikeStore interface {
	BulkExists(ids []int, sentBy int, targetType string) ([]int, error)
	BulkExistsFunc(ids []int, sentBy int, targetType string, f func(int) error) error
	Delete(targetID int, targetType string) error
	Count() (count int)
}
var Likes LikeStore

type LogItem

type LogItem struct {
	Action      string
	ElementID   int
	ElementType string
	IP          string
	ActorID     int
	DoneAt      string
	Extra       string
}

type LogStore

type LogStore interface {
	Create(action string, elementID int, elementType, ip string, actorID int) (err error)
	CreateExtra(action string, elementID int, elementType, ip string, actorID int, extra string) (err error)
	Count() int
	GetOffset(offset, perPage int) (logs []LogItem, err error)
}
var AdminLogs LogStore
var ModLogs LogStore

type LoginLogItem

type LoginLogItem struct {
	ID      int
	UID     int
	Success bool
	IP      string
	DoneAt  string
}

func (*LoginLogItem) Commit

func (l *LoginLogItem) Commit() error

TODO: Reload this item in the store, probably doesn't matter right now, but it might when we start caching this stuff in memory ! Retroactive updates of date are not permitted for integrity reasons

func (*LoginLogItem) Create

func (l *LoginLogItem) Create() (id int, e error)

type LoginLogStmts

type LoginLogStmts struct {
	// contains filtered or unexported fields
}

type LoginLogStore

type LoginLogStore interface {
	Count() (count int)
	CountUser(uid int) (count int)
	GetOffset(uid, offset, perPage int) (logs []LoginLogItem, err error)
	Purge() error

	DeleteOlderThanDays(days int) error
}
var LoginLogs LoginLogStore

type MFAItem

type MFAItem struct {
	UID     int
	Secret  string
	Scratch []string
}

func (*MFAItem) BurnScratch

func (i *MFAItem) BurnScratch(index int) error

func (*MFAItem) Delete

func (i *MFAItem) Delete() error

type MFAItemStmts

type MFAItemStmts struct {
	// contains filtered or unexported fields
}

type MFAStore

type MFAStore interface {
	Get(id int) (*MFAItem, error)
	Create(secret string, uid int) (err error)
}
var MFAstore MFAStore

type MeUser

type MeUser struct {
	ID         int
	Link       string
	Name       string
	Group      int
	Active     bool
	IsMod      bool
	IsSuperMod bool
	IsAdmin    bool
	IsBanned   bool

	S           string // Session
	Avatar      string
	MicroAvatar string
	Tag         string
	Level       int
	Score       int
	Liked       int
}

For when users need to see their own data, I've omitted some redundancies and less useful items, so we don't wind up sending them on every request

type MediaEmbed

type MediaEmbed struct {
	//Type string //image
	Type int
	URL  string
	FURL string
	Body string

	Trusted bool // samesite urls
}

type MemoryForumPermsStore

type MemoryForumPermsStore struct {
	// contains filtered or unexported fields
}

func NewMemoryForumPermsStore

func NewMemoryForumPermsStore() (*MemoryForumPermsStore, error)

func (*MemoryForumPermsStore) Get

func (s *MemoryForumPermsStore) Get(fid, gid int) (fp *ForumPerms, err error)

TODO: Add a hook here and have plugin_guilds use it TODO: Check if the forum exists? TODO: Fix the races TODO: Return BlankForumPerms() when the forum permission set doesn't exist?

func (*MemoryForumPermsStore) GetAllMap

func (s *MemoryForumPermsStore) GetAllMap() (bigMap map[int]map[int]*ForumPerms)

! Throughput on this might be bad due to the excessive locking

func (*MemoryForumPermsStore) GetCopy

func (s *MemoryForumPermsStore) GetCopy(fid, gid int) (fp ForumPerms, e error)

TODO: Check if the forum exists? TODO: Fix the races

func (*MemoryForumPermsStore) Init

func (s *MemoryForumPermsStore) Init() error

func (*MemoryForumPermsStore) Reload

func (s *MemoryForumPermsStore) Reload(fid int) error

func (*MemoryForumPermsStore) ReloadAll

func (s *MemoryForumPermsStore) ReloadAll() error

TODO: Optimise this?

type MemoryForumStore

type MemoryForumStore struct {
	// contains filtered or unexported fields
}

MemoryForumStore is a struct which holds an arbitrary number of forums in memory, usually all of them, although we might introduce functionality to hold a smaller subset in memory for sites with an extremely large number of forums

func NewMemoryForumStore

func NewMemoryForumStore() (*MemoryForumStore, error)

NewMemoryForumStore gives you a new instance of MemoryForumStore

func (*MemoryForumStore) AddTopic

func (s *MemoryForumStore) AddTopic(tid, uid, fid int) error

func (*MemoryForumStore) BulkGetCopy

func (s *MemoryForumStore) BulkGetCopy(ids []int) (forums []Forum, err error)

TODO: Optimise this

func (*MemoryForumStore) BypassGet

func (s *MemoryForumStore) BypassGet(id int) (*Forum, error)

func (*MemoryForumStore) CacheDelete

func (s *MemoryForumStore) CacheDelete(id int)

TODO: Batch deletions with name blanking? Is this necessary?

func (*MemoryForumStore) CacheGet

func (s *MemoryForumStore) CacheGet(id int) (*Forum, error)

func (*MemoryForumStore) CacheSet

func (s *MemoryForumStore) CacheSet(f *Forum) error

func (*MemoryForumStore) Count

func (s *MemoryForumStore) Count() (count int)

TODO: Get the total count of forums in the forum store rather than doing a heavy query for this? Count returns the total number of forums

func (*MemoryForumStore) Create

func (s *MemoryForumStore) Create(name, desc string, active bool, preset string) (int, error)

func (*MemoryForumStore) Delete

func (s *MemoryForumStore) Delete(id int) error

TODO: Add a hook to allow plugin_guilds to detect when one of it's forums has just been deleted?

func (*MemoryForumStore) DirtyGet

func (s *MemoryForumStore) DirtyGet(id int) *Forum

func (*MemoryForumStore) Each

func (s *MemoryForumStore) Each(h func(*Forum) error) (err error)

func (*MemoryForumStore) Exists

func (s *MemoryForumStore) Exists(id int) bool

TODO: Add a query for this rather than hitting cache

func (*MemoryForumStore) Get

func (s *MemoryForumStore) Get(id int) (*Forum, error)

func (*MemoryForumStore) GetAll

func (s *MemoryForumStore) GetAll() (forumView []*Forum, err error)

! Has a randomised order

func (*MemoryForumStore) GetAllIDs

func (s *MemoryForumStore) GetAllIDs() (ids []int, err error)

? - Can we optimise the sorting?

func (*MemoryForumStore) GetAllVisible

func (s *MemoryForumStore) GetAllVisible() (forumView []*Forum, err error)

func (*MemoryForumStore) GetAllVisibleIDs

func (s *MemoryForumStore) GetAllVisibleIDs() ([]int, error)

func (*MemoryForumStore) Length

func (s *MemoryForumStore) Length() (len int)

! Might be slightly inaccurate, if the sync.Map is constantly shifting and churning, but it'll stabilise eventually. Also, slow. Don't use this on every request x.x Length returns the number of forums in the memory cache

func (*MemoryForumStore) LoadForums

func (s *MemoryForumStore) LoadForums() error

TODO: Rename to ReloadAll? TODO: Add support for subforums

func (*MemoryForumStore) RefreshTopic

func (s *MemoryForumStore) RefreshTopic(fid int) (err error)

func (*MemoryForumStore) Reload

func (s *MemoryForumStore) Reload(id int) error

func (*MemoryForumStore) RemoveTopic

func (s *MemoryForumStore) RemoveTopic(fid int) error

TODO: Make this update more atomic

func (*MemoryForumStore) RemoveTopics

func (s *MemoryForumStore) RemoveTopics(fid, count int) error

func (*MemoryForumStore) UpdateLastTopic

func (s *MemoryForumStore) UpdateLastTopic(tid, uid, fid int) error

DEPRECATED. forum.Update() will be the way to do this in the future, once it's completed TODO: Have a pointer to the last topic rather than storing it on the forum itself

func (*MemoryForumStore) UpdateOrder

func (s *MemoryForumStore) UpdateOrder(updateMap map[int]int) error

TODO: Make this atomic, maybe with a transaction?

type MemoryGroupStore

type MemoryGroupStore struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

func NewMemoryGroupStore

func NewMemoryGroupStore() (*MemoryGroupStore, error)

func (*MemoryGroupStore) CacheAdd

func (s *MemoryGroupStore) CacheAdd(g *Group) error

func (*MemoryGroupStore) CacheSet

func (s *MemoryGroupStore) CacheSet(g *Group) error

func (*MemoryGroupStore) Count

func (s *MemoryGroupStore) Count() (count int)

func (*MemoryGroupStore) Create

func (s *MemoryGroupStore) Create(name, tag string, isAdmin, isMod, isBanned bool) (gid int, err error)

? Allow two groups with the same name? TODO: Refactor this

func (*MemoryGroupStore) DirtyGet

func (s *MemoryGroupStore) DirtyGet(id int) *Group

TODO: Hit the database when the item isn't in memory

func (*MemoryGroupStore) Exists

func (s *MemoryGroupStore) Exists(id int) bool

TODO: Hit the database when the item isn't in memory

func (*MemoryGroupStore) Get

func (s *MemoryGroupStore) Get(id int) (*Group, error)

TODO: Hit the database when the item isn't in memory

func (*MemoryGroupStore) GetAll

func (s *MemoryGroupStore) GetAll() (results []*Group, err error)

func (*MemoryGroupStore) GetAllMap

func (s *MemoryGroupStore) GetAllMap() (map[int]*Group, error)

func (*MemoryGroupStore) GetCopy

func (s *MemoryGroupStore) GetCopy(id int) (Group, error)

TODO: Hit the database when the item isn't in memory

func (*MemoryGroupStore) GetRange

func (s *MemoryGroupStore) GetRange(lower, higher int) (groups []*Group, err error)

? - Set the lower and higher numbers to 0 to remove the bounds TODO: Might be a little slow right now, maybe we can cache the groups in a slice or break the map up into chunks

func (*MemoryGroupStore) Length

func (s *MemoryGroupStore) Length() int

func (*MemoryGroupStore) LoadGroups

func (s *MemoryGroupStore) LoadGroups() error

TODO: Move this query from the global stmt store into this store

func (*MemoryGroupStore) Reload

func (s *MemoryGroupStore) Reload(id int) error

func (*MemoryGroupStore) SetCanSee

func (s *MemoryGroupStore) SetCanSee(gid int, canSee []int) error

type MemoryPollCache

type MemoryPollCache struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

MemoryPollCache stores and pulls polls out of the current process' memory

func NewMemoryPollCache

func NewMemoryPollCache(capacity int) *MemoryPollCache

NewMemoryPollCache gives you a new instance of MemoryPollCache

func (*MemoryPollCache) Add

func (s *MemoryPollCache) Add(item *Poll) error

Add adds a poll to the cache, similar to Set, but it's only intended for new items. This method might be deprecated in the near future, use Set. May return a capacity overflow error. ? Is this redundant if we have Set? Are the efficiency wins worth this? Is this even used?

func (*MemoryPollCache) AddUnsafe

func (s *MemoryPollCache) AddUnsafe(item *Poll) error

AddUnsafe is the unsafe version of Add. May return a capacity overflow error. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryPollCache) BulkGet

func (s *MemoryPollCache) BulkGet(ids []int) (list []*Poll)

BulkGet fetches multiple polls by their IDs. Indices without polls will be set to nil, so make sure you check for those, we might want to change this behaviour to make it less confusing.

func (*MemoryPollCache) Flush

func (s *MemoryPollCache) Flush()

Flush removes all the polls from the cache, useful for tests.

func (*MemoryPollCache) Get

func (s *MemoryPollCache) Get(id int) (*Poll, error)

Get fetches a poll by ID. Returns ErrNoRows if not present.

func (*MemoryPollCache) GetCapacity

func (s *MemoryPollCache) GetCapacity() int

GetCapacity returns the maximum number of polls this cache can hold

func (*MemoryPollCache) GetUnsafe

func (s *MemoryPollCache) GetUnsafe(id int) (*Poll, error)

GetUnsafe fetches a poll by ID. Returns ErrNoRows if not present. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryPollCache) Length

func (s *MemoryPollCache) Length() int

! Is this concurrent? Length returns the number of polls in the memory cache

func (*MemoryPollCache) Remove

func (s *MemoryPollCache) Remove(id int) error

Remove removes a poll from the cache by ID, if they exist. Returns ErrNoRows if no items exist.

func (*MemoryPollCache) RemoveUnsafe

func (s *MemoryPollCache) RemoveUnsafe(id int) error

RemoveUnsafe is the unsafe version of Remove. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryPollCache) Set

func (s *MemoryPollCache) Set(item *Poll) error

Set overwrites the value of a poll in the cache, whether it's present or not. May return a capacity overflow error.

func (*MemoryPollCache) SetCapacity

func (s *MemoryPollCache) SetCapacity(capacity int)

SetCapacity sets the maximum number of polls which this cache can hold

type MemoryReplyCache

type MemoryReplyCache struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

MemoryReplyCache stores and pulls replies out of the current process' memory

func NewMemoryReplyCache

func NewMemoryReplyCache(cap int) *MemoryReplyCache

NewMemoryReplyCache gives you a new instance of MemoryReplyCache

func (*MemoryReplyCache) Add

func (s *MemoryReplyCache) Add(item *Reply) error

Add adds a reply to the cache, similar to Set, but it's only intended for new items. This method might be deprecated in the near future, use Set. May return a capacity overflow error. ? Is this redundant if we have Set? Are the efficiency wins worth this? Is this even used?

func (*MemoryReplyCache) AddUnsafe

func (s *MemoryReplyCache) AddUnsafe(item *Reply) error

AddUnsafe is the unsafe version of Add. May return a capacity overflow error. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryReplyCache) BulkGet

func (s *MemoryReplyCache) BulkGet(ids []int) (list []*Reply)

BulkGet fetches multiple replies by their IDs. Indices without replies will be set to nil, so make sure you check for those, we might want to change this behaviour to make it less confusing.

func (*MemoryReplyCache) Flush

func (s *MemoryReplyCache) Flush()

Flush removes all the replies from the cache, useful for tests.

func (*MemoryReplyCache) Get

func (s *MemoryReplyCache) Get(id int) (*Reply, error)

Get fetches a reply by ID. Returns ErrNoRows if not present.

func (*MemoryReplyCache) GetCapacity

func (s *MemoryReplyCache) GetCapacity() int

GetCapacity returns the maximum number of replies this cache can hold

func (*MemoryReplyCache) GetUnsafe

func (s *MemoryReplyCache) GetUnsafe(id int) (*Reply, error)

GetUnsafe fetches a reply by ID. Returns ErrNoRows if not present. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryReplyCache) Length

func (s *MemoryReplyCache) Length() int

! Is this concurrent? Length returns the number of replies in the memory cache

func (*MemoryReplyCache) Remove

func (s *MemoryReplyCache) Remove(id int) error

Remove removes a reply from the cache by ID, if they exist. Returns ErrNoRows if no items exist.

func (*MemoryReplyCache) RemoveUnsafe

func (s *MemoryReplyCache) RemoveUnsafe(id int) error

RemoveUnsafe is the unsafe version of Remove. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryReplyCache) Set

func (s *MemoryReplyCache) Set(item *Reply) error

Set overwrites the value of a reply in the cache, whether it's present or not. May return a capacity overflow error.

func (*MemoryReplyCache) SetCapacity

func (s *MemoryReplyCache) SetCapacity(cap int)

SetCapacity sets the maximum number of replies which this cache can hold

type MemoryTopicCache

type MemoryTopicCache struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

MemoryTopicCache stores and pulls topics out of the current process' memory

func NewMemoryTopicCache

func NewMemoryTopicCache(cap int) *MemoryTopicCache

NewMemoryTopicCache gives you a new instance of MemoryTopicCache

func (*MemoryTopicCache) Add

func (s *MemoryTopicCache) Add(item *Topic) error

Add adds a topic to the cache, similar to Set, but it's only intended for new items. This method might be deprecated in the near future, use Set. May return a capacity overflow error. ? Is this redundant if we have Set? Are the efficiency wins worth this? Is this even used?

func (*MemoryTopicCache) AddUnsafe

func (s *MemoryTopicCache) AddUnsafe(item *Topic) error

AddUnsafe is the unsafe version of Add. May return a capacity overflow error. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryTopicCache) BulkGet

func (s *MemoryTopicCache) BulkGet(ids []int) (list []*Topic)

BulkGet fetches multiple topics by their IDs. Indices without topics will be set to nil, so make sure you check for those, we might want to change this behaviour to make it less confusing.

func (*MemoryTopicCache) Flush

func (s *MemoryTopicCache) Flush()

Flush removes all the topics from the cache, useful for tests.

func (*MemoryTopicCache) Get

func (s *MemoryTopicCache) Get(id int) (*Topic, error)

Get fetches a topic by ID. Returns ErrNoRows if not present.

func (*MemoryTopicCache) GetCapacity

func (s *MemoryTopicCache) GetCapacity() int

GetCapacity returns the maximum number of topics this cache can hold

func (*MemoryTopicCache) GetUnsafe

func (s *MemoryTopicCache) GetUnsafe(id int) (*Topic, error)

GetUnsafe fetches a topic by ID. Returns ErrNoRows if not present. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryTopicCache) Length

func (s *MemoryTopicCache) Length() int

! Is this concurrent? Length returns the number of topics in the memory cache

func (*MemoryTopicCache) Remove

func (s *MemoryTopicCache) Remove(id int) error

Remove removes a topic from the cache by ID, if they exist. Returns ErrNoRows if no items exist.

func (*MemoryTopicCache) RemoveMany

func (s *MemoryTopicCache) RemoveMany(ids []int) error

func (*MemoryTopicCache) RemoveUnsafe

func (s *MemoryTopicCache) RemoveUnsafe(id int) error

RemoveUnsafe is the unsafe version of Remove. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryTopicCache) Set

func (s *MemoryTopicCache) Set(it *Topic) error

Set overwrites the value of a topic in the cache, whether it's present or not. May return a capacity overflow error.

func (*MemoryTopicCache) SetCapacity

func (s *MemoryTopicCache) SetCapacity(cap int)

SetCapacity sets the maximum number of topics which this cache can hold

type MemoryUserCache

type MemoryUserCache struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

MemoryUserCache stores and pulls users out of the current process' memory

func NewMemoryUserCache

func NewMemoryUserCache(cap int) *MemoryUserCache

NewMemoryUserCache gives you a new instance of MemoryUserCache

func (*MemoryUserCache) Add

func (s *MemoryUserCache) Add(item *User) error

Add adds a user to the cache, similar to Set, but it's only intended for new items. This method might be deprecated in the near future, use Set. May return a capacity overflow error. ? Is this redundant if we have Set? Are the efficiency wins worth this? Is this even used?

func (*MemoryUserCache) AddUnsafe

func (s *MemoryUserCache) AddUnsafe(item *User) error

AddUnsafe is the unsafe version of Add. May return a capacity overflow error. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryUserCache) BulkGet

func (s *MemoryUserCache) BulkGet(ids []int) (list []*User)

BulkGet fetches multiple users by their IDs. Indices without users will be set to nil, so make sure you check for those, we might want to change this behaviour to make it less confusing.

func (*MemoryUserCache) BulkRemove

func (s *MemoryUserCache) BulkRemove(ids []int)

func (*MemoryUserCache) DeallocOverflow

func (s *MemoryUserCache) DeallocOverflow(evictPriority bool) (evicted int)

TODO: Avoid deallocating topic list users

func (*MemoryUserCache) Flush

func (s *MemoryUserCache) Flush()

Flush removes all the users from the cache, useful for tests.

func (*MemoryUserCache) Get

func (s *MemoryUserCache) Get(id int) (*User, error)

Get fetches a user by ID. Returns ErrNoRows if not present.

func (*MemoryUserCache) GetCapacity

func (s *MemoryUserCache) GetCapacity() int

GetCapacity returns the maximum number of users this cache can hold

func (*MemoryUserCache) GetUnsafe

func (s *MemoryUserCache) GetUnsafe(id int) (*User, error)

GetUnsafe fetches a user by ID. Returns ErrNoRows if not present. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryUserCache) Getn

func (s *MemoryUserCache) Getn(id int) *User

func (*MemoryUserCache) Length

func (s *MemoryUserCache) Length() int

! Is this concurrent? Length returns the number of users in the memory cache

func (*MemoryUserCache) Remove

func (s *MemoryUserCache) Remove(id int) error

Remove removes a user from the cache by ID, if they exist. Returns ErrNoRows if no items exist.

func (*MemoryUserCache) RemoveUnsafe

func (s *MemoryUserCache) RemoveUnsafe(id int) error

RemoveUnsafe is the unsafe version of Remove. THIS METHOD IS NOT THREAD-SAFE.

func (*MemoryUserCache) Set

func (s *MemoryUserCache) Set(item *User) error

Set overwrites the value of a user in the cache, whether it's present or not. May return a capacity overflow error.

func (*MemoryUserCache) SetCapacity

func (s *MemoryUserCache) SetCapacity(cap int)

SetCapacity sets the maximum number of users which this cache can hold

type MenuItem struct {
	ID     int
	MenuID int

	Name     string
	HTMLID   string
	CSSClass string
	Position string
	Path     string
	Aria     string
	Tooltip  string
	Order    int
	TmplName string

	GuestOnly    bool
	MemberOnly   bool
	SuperModOnly bool
	AdminOnly    bool
}
func (i MenuItem) Commit() error
func (i MenuItem) Create() (int, error)
func (i MenuItem) Delete() error
type MenuItemList []MenuItem
type MenuItemStmts struct {
	// contains filtered or unexported fields
}

TODO: Move the menu item stuff to it's own file

type MenuListHolder struct {
	MenuID     int
	List       MenuItemList
	Variations map[int]menuTmpl // 0 = Guest Menu, 1 = Member Menu, 2 = Super Mod Menu, 3 = Admin Menu
}
func (h *MenuListHolder) Build(w io.Writer, user *User, pathPrefix string) error

TODO: Pre-render the lang stuff

func (h *MenuListHolder) LoadTmpl(name string) (t MenuTmpl, e error)
func (h *MenuListHolder) LoadTmpls() (tmpls map[string]MenuTmpl, e error)
func (h *MenuListHolder) Parse(name string, tmplData []byte) (menuTmpl MenuTmpl)
func (h *MenuListHolder) Preparse() error

TODO: Run this in main, sync ticks, when the phrase file changes (need to implement the sync for that first), and when the settings are changed

func (h *MenuListHolder) Scan(tmpls map[string]MenuTmpl, showItem func(i MenuItem) bool) (renderBuffer [][]byte, variableIndices []int, pathList []menuPath)
func (h *MenuListHolder) ScanItem(tmpls map[string]MenuTmpl, mitem MenuItem, renderBuffer [][]byte, variableIndices []int) ([][]byte, []int)

Note: This doesn't do a visibility check like hold.Scan() does

func (h *MenuListHolder) UpdateOrder(updateMap map[int]int) error

TODO: Make this atomic, maybe with a transaction or store the order on the menu itself?

type MenuTmpl struct {
	Name           string
	TextBuffer     [][]byte
	VariableBuffer [][]byte
	RenderList     []menuRenderItem
}

type Message

type Message interface {
	ID() int
	Poster() int
	Contents() string
	ParsedContents() string
}

Coming Soon:

type MiniAttachment

type MiniAttachment struct {
	ID         int
	SectionID  int
	OriginID   int
	UploadedBy int
	Path       string
	Extra      string

	Image bool
	Ext   string
}

type NameLangToggle

type NameLangToggle struct {
	Name    string
	LangStr string
	Toggle  bool
}

type NameTextPair

type NameTextPair struct {
	Name string
	Text template.HTML
}

type NullPollCache

type NullPollCache struct {
}

NullPollCache is a poll cache to be used when you don't want a cache and just want queries to passthrough to the database

func NewNullPollCache

func NewNullPollCache() *NullPollCache

NewNullPollCache gives you a new instance of NullPollCache

func (*NullPollCache) Add

func (s *NullPollCache) Add(_ *Poll) error

func (*NullPollCache) AddUnsafe

func (s *NullPollCache) AddUnsafe(_ *Poll) error

func (*NullPollCache) BulkGet

func (s *NullPollCache) BulkGet(ids []int) (list []*Poll)

func (*NullPollCache) Flush

func (s *NullPollCache) Flush()

func (*NullPollCache) Get

func (s *NullPollCache) Get(id int) (*Poll, error)

nolint

func (*NullPollCache) GetCapacity

func (s *NullPollCache) GetCapacity() int

func (*NullPollCache) GetUnsafe

func (s *NullPollCache) GetUnsafe(id int) (*Poll, error)

func (*NullPollCache) Length

func (s *NullPollCache) Length() int

func (*NullPollCache) Remove

func (s *NullPollCache) Remove(id int) error

func (*NullPollCache) RemoveUnsafe

func (s *NullPollCache) RemoveUnsafe(id int) error

func (*NullPollCache) Set

func (s *NullPollCache) Set(_ *Poll) error

func (*NullPollCache) SetCapacity

func (s *NullPollCache) SetCapacity(_ int)

type NullReplyCache

type NullReplyCache struct {
}

NullReplyCache is a reply cache to be used when you don't want a cache and just want queries to passthrough to the database

func NewNullReplyCache

func NewNullReplyCache() *NullReplyCache

NewNullReplyCache gives you a new instance of NullReplyCache

func (*NullReplyCache) Add

func (c *NullReplyCache) Add(_ *Reply) error

func (*NullReplyCache) AddUnsafe

func (c *NullReplyCache) AddUnsafe(_ *Reply) error

func (*NullReplyCache) BulkGet

func (c *NullReplyCache) BulkGet(ids []int) (list []*Reply)

func (*NullReplyCache) Flush

func (c *NullReplyCache) Flush()

func (*NullReplyCache) Get

func (c *NullReplyCache) Get(id int) (*Reply, error)

nolint

func (*NullReplyCache) GetCapacity

func (c *NullReplyCache) GetCapacity() int

func (*NullReplyCache) GetUnsafe

func (c *NullReplyCache) GetUnsafe(id int) (*Reply, error)

func (*NullReplyCache) Length

func (c *NullReplyCache) Length() int

func (*NullReplyCache) Remove

func (c *NullReplyCache) Remove(id int) error

func (*NullReplyCache) RemoveUnsafe

func (c *NullReplyCache) RemoveUnsafe(id int) error

func (*NullReplyCache) Set

func (c *NullReplyCache) Set(_ *Reply) error

func (*NullReplyCache) SetCapacity

func (c *NullReplyCache) SetCapacity(_ int)

type NullTopicCache

type NullTopicCache struct {
}

NullTopicCache is a topic cache to be used when you don't want a cache and just want queries to passthrough to the database

func NewNullTopicCache

func NewNullTopicCache() *NullTopicCache

NewNullTopicCache gives you a new instance of NullTopicCache

func (*NullTopicCache) Add

func (c *NullTopicCache) Add(_ *Topic) error

func (*NullTopicCache) AddUnsafe

func (c *NullTopicCache) AddUnsafe(_ *Topic) error

func (*NullTopicCache) BulkGet

func (c *NullTopicCache) BulkGet(ids []int) (list []*Topic)

func (*NullTopicCache) Flush

func (c *NullTopicCache) Flush()

func (*NullTopicCache) Get

func (c *NullTopicCache) Get(id int) (*Topic, error)

nolint

func (*NullTopicCache) GetCapacity

func (c *NullTopicCache) GetCapacity() int

func (*NullTopicCache) GetUnsafe

func (c *NullTopicCache) GetUnsafe(id int) (*Topic, error)

func (*NullTopicCache) Length

func (c *NullTopicCache) Length() int

func (*NullTopicCache) Remove

func (c *NullTopicCache) Remove(id int) error

func (*NullTopicCache) RemoveMany

func (c *NullTopicCache) RemoveMany(ids []int) error

func (*NullTopicCache) RemoveUnsafe

func (c *NullTopicCache) RemoveUnsafe(id int) error

func (*NullTopicCache) Set

func (c *NullTopicCache) Set(_ *Topic) error

func (*NullTopicCache) SetCapacity

func (c *NullTopicCache) SetCapacity(_ int)

type NullUserCache

type NullUserCache struct {
}

NullUserCache is a user cache to be used when you don't want a cache and just want queries to passthrough to the database

func NewNullUserCache

func NewNullUserCache() *NullUserCache

NewNullUserCache gives you a new instance of NullUserCache

func (*NullUserCache) Add

func (c *NullUserCache) Add(_ *User) error

func (*NullUserCache) AddUnsafe

func (c *NullUserCache) AddUnsafe(_ *User) error

func (*NullUserCache) BulkGet

func (c *NullUserCache) BulkGet(ids []int) (list []*User)

func (*NullUserCache) BulkRemove

func (c *NullUserCache) BulkRemove(ids []int)

func (*NullUserCache) DeallocOverflow

func (c *NullUserCache) DeallocOverflow(evictPriority bool) (evicted int)

nolint

func (*NullUserCache) Flush

func (c *NullUserCache) Flush()

func (*NullUserCache) Get

func (c *NullUserCache) Get(id int) (*User, error)

func (*NullUserCache) GetCapacity

func (c *NullUserCache) GetCapacity() int

func (*NullUserCache) GetUnsafe

func (c *NullUserCache) GetUnsafe(id int) (*User, error)

func (*NullUserCache) Getn

func (c *NullUserCache) Getn(id int) *User

func (*NullUserCache) Length

func (c *NullUserCache) Length() int

func (*NullUserCache) Remove

func (c *NullUserCache) Remove(id int) error

func (*NullUserCache) RemoveUnsafe

func (c *NullUserCache) RemoveUnsafe(id int) error

func (*NullUserCache) Set

func (c *NullUserCache) Set(_ *User) error

func (*NullUserCache) SetCapacity

func (c *NullUserCache) SetCapacity(_ int)

type OptionLabel

type OptionLabel struct {
	Label    string
	Value    int
	Selected bool
}

type OttoPluginLang

type OttoPluginLang struct {
	// contains filtered or unexported fields
}

func (*OttoPluginLang) AddPlugin

func (js *OttoPluginLang) AddPlugin(meta PluginMeta) (plugin *Plugin, err error)

func (*OttoPluginLang) GetExts

func (js *OttoPluginLang) GetExts() []string

func (*OttoPluginLang) GetName

func (js *OttoPluginLang) GetName() string

func (*OttoPluginLang) Init

func (js *OttoPluginLang) Init() (err error)

type Page

type Page struct {
	*Header
	ItemList  []interface{}
	Something interface{}
}

type PageInt

type PageInt interface {
	Title() string
	Header() *Header
	CurrentUser() *User
	GetExtData(name string) interface{}
	SetExtData(name string, contents interface{})
}

While the idea is nice, this might result in too much code duplication, as we have seventy billion page structs, what else could we do to get static typing with these in plugins?

type PageLogItem

type PageLogItem struct {
	Action template.HTML
	IP     string
	DoneAt string
}

type PageRegLogItem

type PageRegLogItem struct {
	RegLogItem
	ParsedReason string
}

type PageSimple

type PageSimple struct {
	Title     string
	Something interface{}
}

type PageStore

type PageStore interface {
	Count() (count int)
	Get(id int) (*CustomPage, error)
	GetByName(name string) (*CustomPage, error)
	GetOffset(offset, perPage int) (pages []*CustomPage, err error)
	Reload(id int) error
	Delete(id int) error
}

Holds the custom pages, but doesn't include the template pages in /pages/ which are a lot more flexible yet harder to use and which are too risky security-wise to make editable in the Control Panel

var Pages PageStore

type PageWidgets

type PageWidgets struct {
	LeftSidebar  template.HTML
	RightSidebar template.HTML
}

type Paginator

type Paginator struct {
	PageList []int
	Page     int
	LastPage int
}

type PaginatorMod

type PaginatorMod struct {
	Params   template.URL
	PageList []int
	Page     int
	LastPage int
}

type Panel

type Panel struct {
	*BasePanelPage
	HTMLID     string
	ClassNames string
	TmplName   string
	Inner      nobreak
}

WIP for dyntmpl

type PanelAnalytics

type PanelAnalytics struct {
	*BasePanelPage
	FormAction string
	TmplName   string
	Inner      nobreak
}

type PanelAnalyticsActiveMemory

type PanelAnalyticsActiveMemory struct {
	Graph     PanelTimeGraph
	ViewItems []PanelAnalyticsItemUnit
	TimeRange string
	Unit      string
	TimeType  string
	MemType   int
}

type PanelAnalyticsAgentPage

type PanelAnalyticsAgentPage struct {
	*BasePanelPage
	Agent         string
	FriendlyAgent string
	Graph         PanelTimeGraph
	TimeRange     string
}

type PanelAnalyticsAgentsItem

type PanelAnalyticsAgentsItem struct {
	Agent         string
	FriendlyAgent string
	Count         int
}

TODO: Rename the fields as this structure is being used in a generic way now

type PanelAnalyticsAgentsPage

type PanelAnalyticsAgentsPage struct {
	*BasePanelPage
	ItemList  []PanelAnalyticsAgentsItem
	TimeRange string
}

type PanelAnalyticsDuoPage

type PanelAnalyticsDuoPage struct {
	*BasePanelPage
	ItemList  []PanelAnalyticsAgentsItem
	Graph     PanelTimeGraph
	TimeRange string
}

type PanelAnalyticsItem

type PanelAnalyticsItem struct {
	Time  int64
	Count int64
}

type PanelAnalyticsItemUnit

type PanelAnalyticsItemUnit struct {
	Time  int64
	Count int64
	Unit  string
}

type PanelAnalyticsPage

type PanelAnalyticsPage struct {
	*BasePanelPage
	Graph     PanelTimeGraph
	ViewItems []PanelAnalyticsItem
	TimeRange string
	Unit      string
	TimeType  string
}

type PanelAnalyticsPerf

type PanelAnalyticsPerf struct {
	Graph     PanelTimeGraph
	ViewItems []PanelAnalyticsItemUnit
	TimeRange string
	Unit      string
	TimeType  string
	PerfType  int
}

type PanelAnalyticsReferrersPage

type PanelAnalyticsReferrersPage struct {
	*BasePanelPage
	ItemList  []PanelAnalyticsAgentsItem
	TimeRange string
	ShowSpam  bool
}

type PanelAnalyticsRoutePage

type PanelAnalyticsRoutePage struct {
	*BasePanelPage
	Route     string
	Graph     PanelTimeGraph
	ViewItems []PanelAnalyticsItem
	TimeRange string
}

type PanelAnalyticsRoutesItem

type PanelAnalyticsRoutesItem struct {
	Route string
	Count int
}

type PanelAnalyticsRoutesPage

type PanelAnalyticsRoutesPage struct {
	*BasePanelPage
	ItemList  []PanelAnalyticsRoutesItem
	Graph     PanelTimeGraph
	TimeRange string
}

type PanelAnalyticsRoutesPerfItem

type PanelAnalyticsRoutesPerfItem struct {
	Route string
	Count int
	Unit  string
}

type PanelAnalyticsRoutesPerfPage

type PanelAnalyticsRoutesPerfPage struct {
	*BasePanelPage
	ItemList  []PanelAnalyticsRoutesPerfItem
	Graph     PanelTimeGraph
	TimeRange string
}

type PanelAnalyticsStd

type PanelAnalyticsStd struct {
	Graph     PanelTimeGraph
	ViewItems []PanelAnalyticsItem
	TimeRange string
	Unit      string
	TimeType  string
}

type PanelAnalyticsStdUnit

type PanelAnalyticsStdUnit struct {
	Graph     PanelTimeGraph
	ViewItems []PanelAnalyticsItemUnit
	TimeRange string
	Unit      string
	TimeType  string
}

type PanelBackupPage

type PanelBackupPage struct {
	*BasePanelPage
	Backups []BackupItem
}

type PanelCustomPageEditPage

type PanelCustomPageEditPage struct {
	*BasePanelPage
	Page *CustomPage
}

type PanelCustomPagesPage

type PanelCustomPagesPage struct {
	*BasePanelPage
	ItemList []*CustomPage
	Paginator
}

type PanelDashboardPage

type PanelDashboardPage struct {
	*BasePanelPage
	Grids DashGrids
}

type PanelDebugPage

type PanelDebugPage struct {
	*BasePanelPage
	GoVersion string
	DBVersion string
	Uptime    string

	DBConns   int
	DBAdapter string

	Goroutines int
	CPUs       int
	HttpConns  int

	Tasks    DebugPageTasks
	MemStats runtime.MemStats
	Cache    DebugPageCache
	Database DebugPageDatabase
	Disk     DebugPageDisk
}

type PanelEditForumGroupPage

type PanelEditForumGroupPage struct {
	*BasePanelPage
	ForumID int
	GroupID int
	Name    string
	Desc    string
	Active  bool
	Preset  string
	Perms   []NameLangToggle
}

type PanelEditForumPage

type PanelEditForumPage struct {
	*BasePanelPage
	ID      int
	Name    string
	Desc    string
	Active  bool
	Preset  string
	Groups  []GroupForumPermPreset
	Actions []*ForumActionAction
}

type PanelEditGroupPage

type PanelEditGroupPage struct {
	*BasePanelPage
	ID          int
	Name        string
	Tag         string
	Rank        string
	DisableRank bool
}

type PanelEditGroupPermsPage

type PanelEditGroupPermsPage struct {
	*BasePanelPage
	ID          int
	Name        string
	LocalPerms  []NameLangToggle
	GlobalPerms []NameLangToggle
	ModPerms    []NameLangToggle
}

type PanelEditGroupPromotionsPage

type PanelEditGroupPromotionsPage struct {
	*BasePanelPage
	ID         int
	Name       string
	Promotions []*GroupPromotionExtend
	Groups     []*Group
}

type PanelGroupPage

type PanelGroupPage struct {
	*BasePanelPage
	ItemList []GroupAdmin
	Paginator
}

type PanelLogsPage

type PanelLogsPage struct {
	*BasePanelPage
	Logs []PageLogItem
	Paginator
}

type PanelMenuItemPage

type PanelMenuItemPage struct {
	*BasePanelPage
	Item MenuItem
}

type PanelMenuListItem

type PanelMenuListItem struct {
	Name      string
	ID        int
	ItemCount int
}

type PanelMenuListPage

type PanelMenuListPage struct {
	*BasePanelPage
	ItemList []PanelMenuListItem
}

type PanelMenuPage

type PanelMenuPage struct {
	*BasePanelPage
	MenuID   int
	ItemList []MenuItem
}

type PanelPage

type PanelPage struct {
	*BasePanelPage
	ItemList  []interface{}
	Something interface{}
}

type PanelRegLogsPage

type PanelRegLogsPage struct {
	*BasePanelPage
	Logs []PageRegLogItem
	Paginator
}

type PanelSetting

type PanelSetting struct {
	*Setting
	FriendlyName string
}

type PanelSettingPage

type PanelSettingPage struct {
	*BasePanelPage
	ItemList []OptionLabel
	Setting  *PanelSetting
}

type PanelStats

type PanelStats struct {
	Users       int
	Groups      int
	Forums      int
	Pages       int
	Settings    int
	WordFilters int
	Themes      int
	Reports     int
}

type PanelTaskPage

type PanelTaskPage struct {
	*BasePanelPage
	Tasks []PanelTaskTask
	Types []PanelTaskType
}

type PanelTaskTask

type PanelTaskTask struct {
	Name string
	Type int // 0 = halfsec, 1 = sec, 2 = fifteenmin, 3 = hour, 4 = shutdown
}

type PanelTaskType

type PanelTaskType struct {
	Name string
	FAvg string
}

type PanelThemesPage

type PanelThemesPage struct {
	*BasePanelPage
	PrimaryThemes []*Theme
	VariantThemes []*Theme
}

type PanelTimeGraph

type PanelTimeGraph struct {
	Series  [][]int64 // The counts on the left
	Labels  []int64   // unixtimes for the bottom, gets converted into 1:00, 2:00, etc. with JS
	Legends []string
}
type PanelTimeGraph struct {
	Series []int64 // The counts on the left
	Labels []int64 // unixtimes for the bottom, gets converted into 1:00, 2:00, etc. with JS
}

type PanelUserEditPage

type PanelUserEditPage struct {
	*BasePanelPage
	Groups    []*Group
	User      *User
	ShowEmail bool
}

type PanelUserPage

type PanelUserPage struct {
	*BasePanelPage
	ItemList []*User
	Groups   []*Group
	Search   PanelUserPageSearch
	PaginatorMod
}

type PanelUserPageSearch

type PanelUserPageSearch struct {
	Name  string
	Email string
	Group int

	Any bool
}

type PanelWidgetListPage

type PanelWidgetListPage struct {
	*BasePanelPage
	Docks       map[string][]WidgetEdit
	BlankWidget WidgetEdit
}

type ParseSettings

type ParseSettings struct {
	NoEmbed bool
}

func (*ParseSettings) CopyPtr

func (ps *ParseSettings) CopyPtr() *ParseSettings

type Perms

type Perms struct {
	// Global Permissions
	BanUsers              bool `json:",omitempty"`
	ActivateUsers         bool `json:",omitempty"`
	EditUser              bool `json:",omitempty"`
	EditUserEmail         bool `json:",omitempty"`
	EditUserPassword      bool `json:",omitempty"`
	EditUserGroup         bool `json:",omitempty"`
	EditUserGroupSuperMod bool `json:",omitempty"`
	EditUserGroupAdmin    bool `json:",omitempty"`
	EditGroup             bool `json:",omitempty"`
	EditGroupLocalPerms   bool `json:",omitempty"`
	EditGroupGlobalPerms  bool `json:",omitempty"`
	EditGroupSuperMod     bool `json:",omitempty"`
	EditGroupAdmin        bool `json:",omitempty"`
	ManageForums          bool `json:",omitempty"` // This could be local, albeit limited for per-forum managers?
	EditSettings          bool `json:",omitempty"`
	ManageThemes          bool `json:",omitempty"`
	ManagePlugins         bool `json:",omitempty"`
	ViewAdminLogs         bool `json:",omitempty"`
	ViewIPs               bool `json:",omitempty"`

	// Global non-staff permissions
	UploadFiles          bool `json:",omitempty"`
	UploadAvatars        bool `json:",omitempty"`
	UseConvos            bool `json:",omitempty"`
	UseConvosOnlyWithMod bool `json:",omitempty"`
	CreateProfileReply   bool `json:",omitempty"`
	AutoEmbed            bool `json:",omitempty"`
	AutoLink             bool `json:",omitempty"`

	// Forum permissions
	ViewTopic bool `json:",omitempty"`
	//ViewOwnTopic bool `json:",omitempty"`
	LikeItem    bool `json:",omitempty"`
	CreateTopic bool `json:",omitempty"`
	EditTopic   bool `json:",omitempty"`
	DeleteTopic bool `json:",omitempty"`
	CreateReply bool `json:",omitempty"`
	//CreateReplyToOwn bool `json:",omitempty"`
	EditReply bool `json:",omitempty"`
	//EditOwnReply bool `json:",omitempty"`
	DeleteReply bool `json:",omitempty"`
	//DeleteOwnReply bool `json:",omitempty"`
	PinTopic   bool `json:",omitempty"`
	CloseTopic bool `json:",omitempty"`
	//CloseOwnTopic bool `json:",omitempty"`
	MoveTopic bool `json:",omitempty"`
}

Permission Structure: ActionComponent[Subcomponent]Flag

var AllPerms Perms

AllPerms is a set of global permissions with everything set to true

var BlankPerms Perms

TODO: Refactor the perms system

var GuestPerms Perms

func InitPerms2

func InitPerms2(group int, superAdmin bool, tempGroup int) (perms *Perms, admin, superMod, banned bool)

TODO: Write unit tests for this

type Plugin

type Plugin struct {
	UName       string
	Name        string
	Author      string
	URL         string
	Settings    string
	Active      bool
	Tag         string
	Type        string
	Installable bool
	Installed   bool

	Init       func(pl *Plugin) error
	Activate   func(pl *Plugin) error
	Deactivate func(pl *Plugin) // TODO: We might want to let this return an error?
	Install    func(pl *Plugin) error
	Uninstall  func(pl *Plugin) error // TODO: I'm not sure uninstall is implemented

	Hooks map[string]int // Active hooks
	Meta  PluginMetaData
	Data  interface{} // Usually used for hosting the VMs / reusable elements of non-native plugins
}

? - Should we make this an interface which plugins implement instead? Plugin is a struct holding the metadata for a plugin, along with a few of it's primary handlers.

func (*Plugin) AddHook

func (pl *Plugin) AddHook(name string, hInt interface{})

? - Is this racey? TODO: Generate the cases in this switch

func (*Plugin) AddToDatabase

func (pl *Plugin) AddToDatabase(active, installed bool) (err error)

func (*Plugin) BypassActive

func (pl *Plugin) BypassActive() (active bool, err error)

func (*Plugin) InDatabase

func (pl *Plugin) InDatabase() (exists bool, err error)

func (*Plugin) RemoveHook

func (pl *Plugin) RemoveHook(name string, hInt interface{})

? - Is this racey? TODO: Generate the cases in this switch

func (*Plugin) SetActive

func (pl *Plugin) SetActive(active bool) (err error)

TODO: Silently add to the database, if it doesn't exist there rather than forcing users to call AddToDatabase instead?

func (*Plugin) SetInstalled

func (pl *Plugin) SetInstalled(installed bool) (err error)

TODO: Silently add to the database, if it doesn't exist there rather than forcing users to call AddToDatabase instead?

type PluginLang

type PluginLang interface {
	GetName() string
	GetExts() []string

	Init() error
	AddPlugin(meta PluginMeta) (*Plugin, error)
}

func ExtToPluginLang

func ExtToPluginLang(ext string) (PluginLang, error)

type PluginList

type PluginList map[string]*Plugin
var Plugins PluginList = make(map[string]*Plugin)

TODO: Have a proper store rather than a map?

func (PluginList) Add

func (l PluginList) Add(pl *Plugin)

func (PluginList) Load

func (l PluginList) Load() error

Load polls the database to see which plugins have been activated and which have been installed

type PluginMeta

type PluginMeta struct {
	UName    string
	Name     string
	Author   string
	URL      string
	Settings string
	Tag      string

	Skip  bool              // Skip this folder?
	Main  string            // The main file
	Hooks map[string]string // Hooks mapped to functions
}

For non-native plugins to bind JSON files to. E.g. JS and Lua

type PluginMetaData

type PluginMetaData struct {
	Hooks []string
}

type Poll

type Poll struct {
	ID          int
	ParentID    int
	ParentTable string
	Type        int  // 0: Single choice, 1: Multiple choice, 2: Multiple choice w/ points
	AntiCheat   bool // Apply various mitigations for cheating

	Options      map[int]string
	Results      map[int]int  // map[optionIndex]points
	QuickOptions []PollOption // TODO: Fix up the template transpiler so we don't need to use this hack anymore
	VoteCount    int
}

func (*Poll) CastVote

func (p *Poll) CastVote(optionIndex, uid int, ip string) error

TODO: Use a transaction for this? TODO: Add a voters table with castAt / IP data and only populate it when poll anti-cheat is on

func (*Poll) Copy

func (p *Poll) Copy() Poll

func (*Poll) Delete

func (p *Poll) Delete() error

func (*Poll) Resultsf

func (p *Poll) Resultsf(f func(votes int) error) error

type PollCache

type PollCache interface {
	Get(id int) (*Poll, error)
	GetUnsafe(id int) (*Poll, error)
	BulkGet(ids []int) (list []*Poll)
	Set(item *Poll) error
	Add(item *Poll) error
	AddUnsafe(item *Poll) error
	Remove(id int) error
	RemoveUnsafe(id int) error
	Flush()
	Length() int
	SetCapacity(capacity int)
	GetCapacity() int
}

PollCache is an interface which spits out polls from a fast cache rather than the database, whether from memory or from an application like Redis. Polls may not be present in the cache but may be in the database

type PollOption

type PollOption struct {
	ID    int
	Value string
}

type PollStmts

type PollStmts struct {
	// contains filtered or unexported fields
}

type PollStore

type PollStore interface {
	Get(id int) (*Poll, error)
	Exists(id int) bool
	ClearIPs() error
	Create(parent Pollable, pollType int, pollOptions map[int]string) (int, error)
	Reload(id int) error
	Count() int

	SetCache(cache PollCache)
	GetCache() PollCache
}
var Polls PollStore

type Pollable

type Pollable interface {
	GetID() int
	GetTable() string
	SetPoll(pollID int) error
}

type ProfilePage

type ProfilePage struct {
	*Header
	ItemList     []*ReplyUser
	ProfileOwner User
	CurrentScore int
	NextScore    int
	Blocked      bool
	CanMessage   bool
	CanComment   bool
	ShowComments bool
}

type ProfileReply

type ProfileReply struct {
	ID           int
	ParentID     int
	Content      string
	CreatedBy    int
	Group        int
	CreatedAt    time.Time
	LastEdit     int
	LastEditBy   int
	ContentLines int
	IP           string
}

func BlankProfileReply

func BlankProfileReply(id int) *ProfileReply

Mostly for tests, so we don't wind up with out-of-date profile reply initialisation logic there

func (*ProfileReply) Creator

func (r *ProfileReply) Creator() (*User, error)

TODO: We can get this from the topic store instead of a query which will always miss the cache...

func (*ProfileReply) Delete

func (r *ProfileReply) Delete() error

TODO: Write tests for this

func (*ProfileReply) SetBody

func (r *ProfileReply) SetBody(content string) error

type ProfileReplyStmts

type ProfileReplyStmts struct {
	// contains filtered or unexported fields
}

type ProfileReplyStore

type ProfileReplyStore interface {
	Get(id int) (*ProfileReply, error)
	Exists(id int) bool
	ClearIPs() error
	Create(profileID int, content string, createdBy int, ip string) (id int, err error)
	Count() (count int)
}
var Prstore ProfileReplyStore

type QuickTools

type QuickTools struct {
	CanDelete bool
	CanLock   bool
	CanMove   bool
}

type RateData

type RateData struct {
	// contains filtered or unexported fields
}

type RateFence

type RateFence struct {
	// contains filtered or unexported fields
}

type RateLimit

type RateLimit struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

TODO: Optimise this by using something other than a string when possible

func NewRateLimit

func NewRateLimit(fences []RateFence) *RateLimit

func (*RateLimit) Limit

func (l *RateLimit) Limit(name string, ltype int) error

type RateLimiter

type RateLimiter interface {
	LimitIP(limit, ip string) error
	LimitUser(limit string, user int) error
}

TODO: Persist rate limits to disk

type RecalcInt

type RecalcInt interface {
	Replies() (count int, err error)
	Forums() (count int, err error)
	Subscriptions() (count int, err error)
	ActivityStream() (count int, err error)
	Users() error
	Attachments() (count int, err error)
}
var Recalc RecalcInt

type RegLogItem

type RegLogItem struct {
	ID            int
	Username      string
	Email         string
	FailureReason string
	Success       bool
	IP            string
	DoneAt        string
}

func (*RegLogItem) Commit

func (l *RegLogItem) Commit() error

TODO: Reload this item in the store, probably doesn't matter right now, but it might when we start caching this stuff in memory ! Retroactive updates of date are not permitted for integrity reasons TODO: Do we even use this anymore or can we just make the logs immutable (except for deletes) for simplicity sake?

func (*RegLogItem) Create

func (l *RegLogItem) Create() (id int, e error)

type RegLogStmts

type RegLogStmts struct {
	// contains filtered or unexported fields
}

type RegLogStore

type RegLogStore interface {
	Count() (count int)
	GetOffset(offset, perPage int) (logs []RegLogItem, err error)
	Purge() error

	DeleteOlderThanDays(days int) error
}
var RegLogs RegLogStore

type RegisterPage

type RegisterPage struct {
	*Header
	RequireEmail bool
	Token        string
	Verify       []RegisterVerify
}

type RegisterVerify

type RegisterVerify struct {
	NoScript bool

	Image *RegisterVerifyImageGrid
}

type RegisterVerifyImageGrid

type RegisterVerifyImageGrid struct {
	Question string
	Items    []RegisterVerifyImageGridImage
}

type RegisterVerifyImageGridImage

type RegisterVerifyImageGridImage struct {
	Src string
}

WIP: Optional anti-bot methods

type Reply

type Reply struct {
	ID        int
	ParentID  int
	Content   string
	CreatedBy int
	//Group        int
	CreatedAt    time.Time
	LastEdit     int
	LastEditBy   int
	ContentLines int
	IP           string
	Liked        bool
	LikeCount    int
	AttachCount  uint16
	ActionType   string
}

func (*Reply) Copy

func (r *Reply) Copy() Reply

Copy gives you a non-pointer concurrency safe copy of the reply

func (*Reply) Delete

func (r *Reply) Delete() error

TODO: Refresh topic list?

func (*Reply) GetID

func (r *Reply) GetID() int

func (*Reply) GetTable

func (r *Reply) GetTable() string

func (*Reply) Like

func (r *Reply) Like(uid int) (err error)

TODO: Write tests for this TODO: Wrap these queries in a transaction to make sure the state is consistent

func (*Reply) SetPoll

func (r *Reply) SetPoll(pollID int) error

TODO: Write tests for this

func (*Reply) SetPost

func (r *Reply) SetPost(content string) error

func (*Reply) Topic

func (r *Reply) Topic() (*Topic, error)

func (*Reply) Unlike

func (r *Reply) Unlike(uid int) error

TODO: Use a transaction

type ReplyCache

type ReplyCache interface {
	Get(id int) (*Reply, error)
	GetUnsafe(id int) (*Reply, error)
	BulkGet(ids []int) (list []*Reply)
	Set(item *Reply) error
	Add(item *Reply) error
	AddUnsafe(item *Reply) error
	Remove(id int) error
	RemoveUnsafe(id int) error
	Flush()
	Length() int
	SetCapacity(cap int)
	GetCapacity() int
}

ReplyCache is an interface which spits out replies from a fast cache rather than the database, whether from memory or from an application like Redis. Replies may not be present in the cache but may be in the database

type ReplyStmts

type ReplyStmts struct {
	// contains filtered or unexported fields
}

type ReplyStore

type ReplyStore interface {
	Get(id int) (*Reply, error)
	Each(f func(*Reply) error) error
	Exists(id int) bool
	ClearIPs() error
	Create(t *Topic, content, ip string, uid int) (id int, err error)
	Count() (count int)
	CountUser(uid int) (count int)
	CountMegaUser(uid int) (count int)
	CountBigUser(uid int) (count int)

	SetCache(cache ReplyCache)
	GetCache() ReplyCache
}
var Rstore ReplyStore

type ReplyUser

type ReplyUser struct {
	Reply

	ContentHtml   string
	UserLink      string
	CreatedByName string
	Avatar        string
	MicroAvatar   string
	ClassName     string
	Tag           string
	URL           string
	//URLPrefix string
	//URLName   string
	Group      int
	Level      int
	ActionIcon string

	Attachments []*MiniAttachment
	Deletable   bool
}

func (*ReplyUser) Init

func (ru *ReplyUser) Init(u *User) (group *Group, err error)

func (*ReplyUser) Init2

func (ru *ReplyUser) Init2() (group *Group, err error)

func (*ReplyUser) Init3

func (ru *ReplyUser) Init3(u *User, tu *TopicUser) (group *Group, err error)

type ReportStore

type ReportStore interface {
	Create(title, content string, u *User, itemType string, itemID int) (int, error)
}

The report system mostly wraps around the topic system for simplicty

var Reports ReportStore

type ResetPage

type ResetPage struct {
	*Header
	UID   int
	Token string
	MFA   bool
}

type RezThumbnailer

type RezThumbnailer struct {
}

func (*RezThumbnailer) Resize

func (thumb *RezThumbnailer) Resize(format, inPath, tmpPath, outPath string, width int) error

type RouteError

type RouteError interface {
	Type() string
	Error() string
	Cause() string
	JSON() bool
	Handled() bool

	Wrap(string)
}

WIP, a new system to propagate errors up from routes

func AdminOnly

func AdminOnly(w http.ResponseWriter, r *http.Request, u *User) RouteError

AdminOnly makes sure that only admins can access certain panel routes

func Banned

func Banned(w http.ResponseWriter, r *http.Request, u *User) RouteError

? - Is this actually used? Should it be used? A ban in Gosora should be more of a permission revocation to stop them posting rather than something which spits up an error page, right?

func BannedJS

func BannedJS(w http.ResponseWriter, r *http.Request, u *User) RouteError

func BannedJSQ

func BannedJSQ(w http.ResponseWriter, r *http.Request, user *User, js bool) RouteError

nolint BannedJSQ is the version of the banned error page which handles both JavaScript requests and normal page loads

func ChangeAvatar

func ChangeAvatar(path string, w http.ResponseWriter, r *http.Request, u *User) RouteError

func CustomError

func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, h *Header, u *User) (rerr RouteError)

CustomError lets us make custom error types which aren't covered by the generic functions above

func CustomErrorJS

func CustomErrorJS(errmsg string, errcode int, w http.ResponseWriter, r *http.Request, u *User) RouteError

CustomErrorJS is the pure JSON version of CustomError

func CustomErrorJSQ

func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, h *Header, u *User, js bool) RouteError

CustomErrorJSQ is a version of CustomError which lets us handle both JSON and regular pages depending on how it's being accessed

func DatabaseError

func DatabaseError(w http.ResponseWriter, r *http.Request) RouteError

When the task system detects if the database is down, some database errors might slip by this

func Error

func Error(errmsg string) RouteError

func ErrorJSQ

func ErrorJSQ(errmsg string, js bool) RouteError

func FromError

func FromError(err error) RouteError

func HandleUploadRoute

func HandleUploadRoute(w http.ResponseWriter, r *http.Request, u *User, maxFileSize int) RouteError

func HandledRouteError

func HandledRouteError() RouteError

func InternalError

func InternalError(err error, w http.ResponseWriter, r *http.Request) RouteError

TODO: Dump the request? InternalError is the main function for handling internal errors, while simultaneously printing out a page for the end-user to let them know that *something* has gone wrong ? - Add a user parameter? ! Do not call CustomError here or we might get an error loop

func InternalErrorJS

func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) RouteError

InternalErrorJS is the JSON version of InternalError on routes we know will only be requested via JSON. E.g. An API. ? - Add a user parameter?

func InternalErrorJSQ

func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, js bool) RouteError

InternalErrorJSQ is the JSON "maybe" version of InternalError which can handle both JSON and normal requests ? - Add a user parameter?

func InternalErrorXML

func InternalErrorXML(err error, w http.ResponseWriter, r *http.Request) RouteError

func LocalError

func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, u *User) RouteError

func LocalErrorJS

func LocalErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) RouteError

func LocalErrorJSQ

func LocalErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, u *User, js bool) RouteError

func LocalErrorf

func LocalErrorf(errmsg string, w http.ResponseWriter, r *http.Request, u *User, params ...interface{}) RouteError

func LoginRequired

func LoginRequired(w http.ResponseWriter, r *http.Request, u *User) RouteError

? - Where is this used? Should we use it more? LoginRequired is an error shown to the end-user when they try to access an area which requires them to login

func LoginRequiredJS

func LoginRequiredJS(w http.ResponseWriter, r *http.Request, u *User) RouteError

nolint

func LoginRequiredJSQ

func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, u *User, js bool) RouteError

nolint

func MemberOnly

func MemberOnly(w http.ResponseWriter, r *http.Request, u *User) RouteError

MemberOnly makes sure that only logged in users can access this route

func MicroNotFound

func MicroNotFound(w http.ResponseWriter, r *http.Request) RouteError

func NoBanned

func NoBanned(w http.ResponseWriter, r *http.Request, u *User) RouteError

NoBanned stops any banned users from accessing this route

func NoPermissions

func NoPermissions(w http.ResponseWriter, r *http.Request, u *User) RouteError

TODO: We might want to centralise the error logic in the future and just return what the error handler needs to construct the response rather than handling it here NoPermissions is an error shown to the end-user when they try to access an area which they aren't authorised to access

func NoPermissionsJS

func NoPermissionsJS(w http.ResponseWriter, r *http.Request, u *User) RouteError

func NoPermissionsJSQ

func NoPermissionsJSQ(w http.ResponseWriter, r *http.Request, u *User, js bool) RouteError

func NoSessionMismatch

func NoSessionMismatch(w http.ResponseWriter, r *http.Request, u *User) RouteError

func NoUploadSessionMismatch

func NoUploadSessionMismatch(w http.ResponseWriter, r *http.Request, u *User) RouteError

func NotFound

func NotFound(w http.ResponseWriter, r *http.Request, h *Header) RouteError

NotFound is used when the requested page doesn't exist ? - Add a JSQ version of this? ? - Add a user parameter?

func NotFoundJS

func NotFoundJS(w http.ResponseWriter, r *http.Request) RouteError

? - Add a user parameter?

func NotFoundJSQ

func NotFoundJSQ(w http.ResponseWriter, r *http.Request, h *Header, js bool) RouteError

func ParseForm

func ParseForm(w http.ResponseWriter, r *http.Request, u *User) RouteError

func PreError

func PreError(errmsg string, w http.ResponseWriter, r *http.Request) RouteError

! Do not call CustomError here otherwise we might get an error loop

func PreErrorJS

func PreErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) RouteError

func PreErrorJSQ

func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, js bool) RouteError

func RouteWebsockets

func RouteWebsockets(w http.ResponseWriter, r *http.Request, user *User) RouteError

TODO: How should we handle errors for this? TODO: Move this out of common?

func SecurityError

func SecurityError(w http.ResponseWriter, r *http.Request, u *User) RouteError

SecurityError is used whenever a session mismatch is found ? - Should we add JS and JSQ versions of this?

func SilentInternalErrorXML

func SilentInternalErrorXML(err error, w http.ResponseWriter, r *http.Request) RouteError

TODO: Stop killing the instance upon hitting an error with InternalError* and deprecate this

func SimpleError

func SimpleError(errmsg string, w http.ResponseWriter, r *http.Request, h *Header) RouteError

func SuperAdminOnly

func SuperAdminOnly(w http.ResponseWriter, r *http.Request, u *User) RouteError

SuperAdminOnly makes sure that only super admin can access certain critical panel routes

func SuperModOnly

func SuperModOnly(w http.ResponseWriter, r *http.Request, u *User) RouteError

SuperModeOnly makes sure that only super mods or higher can access the panel routes

func SysError

func SysError(errmsg string) RouteError

func UploadAvatar

func UploadAvatar(w http.ResponseWriter, r *http.Request, u *User, tuid int) (ext string, ferr RouteError)

type RouteErrorImpl

type RouteErrorImpl struct {
	// contains filtered or unexported fields
}

func (*RouteErrorImpl) Cause

func (err *RouteErrorImpl) Cause() string

func (*RouteErrorImpl) Error

func (err *RouteErrorImpl) Error() string

func (*RouteErrorImpl) Handled

func (err *RouteErrorImpl) Handled() bool

Has this error been dealt with elsewhere?

func (*RouteErrorImpl) JSON

func (err *RouteErrorImpl) JSON() bool

Respond with JSON?

func (*RouteErrorImpl) Type

func (err *RouteErrorImpl) Type() string

func (*RouteErrorImpl) Wrap

func (err *RouteErrorImpl) Wrap(userErr string)

Move the current error into the system error slot and add a new one to the user error slot to show the user

type SFile

type SFile struct {
	// TODO: Move these to the end?
	Data     []byte
	GzipData []byte
	BrData   []byte

	Sha256  string
	Sha256I string
	OName   string
	Pos     int64

	Length        int64
	StrLength     string
	GzipLength    int64
	StrGzipLength string
	BrLength      int64
	StrBrLength   string

	Mimetype         string
	Info             os.FileInfo
	FormattedModTime string
}

type SFileList

type SFileList struct {
	Prefix string
	Long   map[string]*SFile
	Short  map[string]*SFile
}

? Is it efficient to have two maps for this?

func (SFileList) Add

func (l SFileList) Add(path, prefix string) error

func (SFileList) Get

func (l SFileList) Get(path string) (file *SFile, exists bool)

func (SFileList) GetShort

func (l SFileList) GetShort(name string) (file *SFile, exists bool)

fetch without /s/ to avoid allocing in pages.go

func (SFileList) Init

func (l SFileList) Init() error

func (SFileList) JSTmplInit

func (l SFileList) JSTmplInit() error

func (SFileList) Set

func (l SFileList) Set(name string, data *SFile)

type SQLAdminLogStore

type SQLAdminLogStore struct {
	// contains filtered or unexported fields
}

func NewAdminLogStore

func NewAdminLogStore(acc *qgen.Accumulator) (*SQLAdminLogStore, error)

func (*SQLAdminLogStore) Count

func (s *SQLAdminLogStore) Count() (count int)

func (*SQLAdminLogStore) Create

func (s *SQLAdminLogStore) Create(action string, elementID int, elementType, ip string, actorID int) (err error)

TODO: Make a store for this?

func (*SQLAdminLogStore) CreateExtra

func (s *SQLAdminLogStore) CreateExtra(action string, elementID int, elementType, ip string, actorID int, extra string) (err error)

func (*SQLAdminLogStore) GetOffset

func (s *SQLAdminLogStore) GetOffset(offset, perPage int) (logs []LogItem, err error)

type SQLLoginLogStore

type SQLLoginLogStore struct {
	// contains filtered or unexported fields
}

func NewLoginLogStore

func NewLoginLogStore(acc *qgen.Accumulator) (*SQLLoginLogStore, error)

func (*SQLLoginLogStore) Count

func (s *SQLLoginLogStore) Count() (count int)

func (*SQLLoginLogStore) CountUser

func (s *SQLLoginLogStore) CountUser(uid int) (count int)

func (*SQLLoginLogStore) DeleteOlderThanDays

func (s *SQLLoginLogStore) DeleteOlderThanDays(days int) error

func (*SQLLoginLogStore) GetOffset

func (s *SQLLoginLogStore) GetOffset(uid, offset, perPage int) (logs []LoginLogItem, e error)

func (*SQLLoginLogStore) Purge

func (s *SQLLoginLogStore) Purge() error

Delete all login logs

type SQLMFAStore

type SQLMFAStore struct {
	// contains filtered or unexported fields
}

func NewSQLMFAStore

func NewSQLMFAStore(acc *qgen.Accumulator) (*SQLMFAStore, error)

func (*SQLMFAStore) Create

func (s *SQLMFAStore) Create(secret string, uid int) (err error)

TODO: Write a test for this

func (*SQLMFAStore) Get

func (s *SQLMFAStore) Get(id int) (*MFAItem, error)

TODO: Write a test for this

type SQLModLogStore

type SQLModLogStore struct {
	// contains filtered or unexported fields
}

func NewModLogStore

func NewModLogStore(acc *qgen.Accumulator) (*SQLModLogStore, error)

func (*SQLModLogStore) Count

func (s *SQLModLogStore) Count() (count int)

func (*SQLModLogStore) Create

func (s *SQLModLogStore) Create(action string, elementID int, elementType, ip string, actorID int) (err error)

TODO: Make a store for this?

func (*SQLModLogStore) CreateExtra

func (s *SQLModLogStore) CreateExtra(action string, elementID int, elementType, ip string, actorID int, extra string) (err error)

func (*SQLModLogStore) GetOffset

func (s *SQLModLogStore) GetOffset(offset, perPage int) (logs []LogItem, err error)

type SQLProfileReplyStore

type SQLProfileReplyStore struct {
	// contains filtered or unexported fields
}

TODO: Refactor this to stop using the global stmt store TODO: Add more methods to this like Create()

func NewSQLProfileReplyStore

func NewSQLProfileReplyStore(acc *qgen.Accumulator) (*SQLProfileReplyStore, error)

func (*SQLProfileReplyStore) ClearIPs

func (s *SQLProfileReplyStore) ClearIPs() error

func (*SQLProfileReplyStore) Count

func (s *SQLProfileReplyStore) Count() (count int)

TODO: Write a test for this Count returns the total number of topic replies on these forums

func (*SQLProfileReplyStore) Create

func (s *SQLProfileReplyStore) Create(profileID int, content string, createdBy int, ip string) (id int, e error)

func (*SQLProfileReplyStore) Exists

func (s *SQLProfileReplyStore) Exists(id int) bool

func (*SQLProfileReplyStore) Get

func (s *SQLProfileReplyStore) Get(id int) (*ProfileReply, error)

type SQLRegLogStore

type SQLRegLogStore struct {
	// contains filtered or unexported fields
}

func NewRegLogStore

func NewRegLogStore(acc *qgen.Accumulator) (*SQLRegLogStore, error)

func (*SQLRegLogStore) Count

func (s *SQLRegLogStore) Count() (count int)

func (*SQLRegLogStore) DeleteOlderThanDays

func (s *SQLRegLogStore) DeleteOlderThanDays(days int) error

func (*SQLRegLogStore) GetOffset

func (s *SQLRegLogStore) GetOffset(offset, perPage int) (logs []RegLogItem, e error)

func (*SQLRegLogStore) Purge

func (s *SQLRegLogStore) Purge() error

Delete all registration logs

type SQLReplyStore

type SQLReplyStore struct {
	// contains filtered or unexported fields
}

func NewSQLReplyStore

func NewSQLReplyStore(acc *qgen.Accumulator, cache ReplyCache) (*SQLReplyStore, error)

func (*SQLReplyStore) ClearIPs

func (s *SQLReplyStore) ClearIPs() error

func (*SQLReplyStore) Count

func (s *SQLReplyStore) Count() (count int)

TODO: Write a test for this Count returns the total number of topic replies on these forums

func (*SQLReplyStore) CountBigUser

func (s *SQLReplyStore) CountBigUser(uid int) (count int)

func (*SQLReplyStore) CountMegaUser

func (s *SQLReplyStore) CountMegaUser(uid int) (count int)

func (*SQLReplyStore) CountUser

func (s *SQLReplyStore) CountUser(uid int) (count int)

func (*SQLReplyStore) Create

func (s *SQLReplyStore) Create(t *Topic, content, ip string, uid int) (id int, err error)

TODO: Write a test for this

func (*SQLReplyStore) Each

func (s *SQLReplyStore) Each(f func(*Reply) error) error

func (*SQLReplyStore) Exists

func (s *SQLReplyStore) Exists(id int) bool

func (*SQLReplyStore) Get

func (s *SQLReplyStore) Get(id int) (*Reply, error)

func (*SQLReplyStore) GetCache

func (s *SQLReplyStore) GetCache() ReplyCache

func (*SQLReplyStore) SetCache

func (s *SQLReplyStore) SetCache(cache ReplyCache)

type SQLSearcher

type SQLSearcher struct {
	// contains filtered or unexported fields
}

TODO: Implement this Note: This is slow compared to something like ElasticSearch and very limited

func NewSQLSearcher

func NewSQLSearcher(acc *qgen.Accumulator) (*SQLSearcher, error)

TODO: Support things other than MySQL TODO: Use LIMIT?

func (*SQLSearcher) Query

func (s *SQLSearcher) Query(q string, zones []int) (ids []int, err error)

type ScheduledTasks

type ScheduledTasks struct {
	HalfSec    TaskSet
	Sec        TaskSet
	FifteenMin TaskSet
	Hour       TaskSet
	Day        TaskSet
	Shutdown   TaskSet
}
var Tasks *ScheduledTasks

func NewScheduledTasks

func NewScheduledTasks() *ScheduledTasks

type Searcher

type Searcher interface {
	Query(q string, zones []int) ([]int, error)
}
var RepliesSearch Searcher

type Setting

type Setting struct {
	Name       string
	Content    string
	Type       string
	Constraint string
}

func (*Setting) Copy

func (s *Setting) Copy() (o *Setting)

type SettingMap

type SettingMap map[string]interface{}

SettingMap is a map type specifically for holding the various settings admins set to toggle features on and off or to otherwise alter Gosora's behaviour from the Control Panel

func (SettingMap) BypassGet

func (sBox SettingMap) BypassGet(name string) (*Setting, error)

func (SettingMap) BypassGetAll

func (sBox SettingMap) BypassGetAll() (settingList []*Setting, err error)

func (SettingMap) ParseSetting

func (sBox SettingMap) ParseSetting(name, content, typ, constraint string) (err error)

TODO: Add better support for HTML attributes (html-attribute). E.g. Meta descriptions.

func (SettingMap) Update

func (sBox SettingMap) Update(name, content string) RouteError

type SettingStmts

type SettingStmts struct {
	// contains filtered or unexported fields
}

type SettingStore

type SettingStore interface {
	ParseSetting(name, content, typ, constraint string) string
	BypassGet(name string) (*Setting, error)
	BypassGetAll(name string) ([]*Setting, error)
}

type SimplePage

type SimplePage struct {
	*Header
}

type SingleServerThaw

type SingleServerThaw struct {
	DefaultThaw
}

func NewSingleServerThaw

func NewSingleServerThaw() *SingleServerThaw

func (*SingleServerThaw) Thaw

func (t *SingleServerThaw) Thaw()

func (*SingleServerThaw) Thawed

func (t *SingleServerThaw) Thawed() bool

type SortForum

type SortForum []*Forum

TODO: Replace this sorting mechanism with something a lot more efficient ? - Use sort.Slice instead?

func (SortForum) Len

func (sf SortForum) Len() int

func (SortForum) Less

func (sf SortForum) Less(i, j int) bool
func (sf SortForum) Less(i,j int) bool {
	l := sf.less(i,j)
	if l {
		log.Printf("%s is less than %s. order: %d. id: %d.",sf[i].Name, sf[j].Name, sf[i].Order, sf[i].ID)
	} else {
		log.Printf("%s is not less than %s. order: %d. id: %d.",sf[i].Name, sf[j].Name, sf[i].Order, sf[i].ID)
	}
	return l
}

func (SortForum) Swap

func (sf SortForum) Swap(i, j int)

type SortGroup

type SortGroup []*Group

TODO: Replace this sorting mechanism with something a lot more efficient ? - Use sort.Slice instead?

func (SortGroup) Len

func (sg SortGroup) Len() int

func (SortGroup) Less

func (sg SortGroup) Less(i, j int) bool

func (SortGroup) Swap

func (sg SortGroup) Swap(i, j int)

type StatStoreInt

type StatStoreInt interface {
	LookupInt(name string, duration int, unit string) (int, error)
}
var StatStore StatStoreInt

type StringList

type StringList []string

func (StringList) Contains

func (sl StringList) Contains(needle string) bool

TODO: Write a test for this

type SubscriptionStore

type SubscriptionStore interface {
	Add(uid, elementID int, elementType string) error
	Delete(uid, targetID int, targetType string) error
	DeleteResource(targetID int, targetType string) error
}

? Should we have a subscription store for each zone? topic, forum, etc?

var Subscriptions SubscriptionStore

type TItem

type TItem struct {
	Expects    string
	ExpectsInt interface{}
	LoggedIn   bool
}

type TItemHold

type TItemHold map[string]TItem

func (TItemHold) Add

func (h TItemHold) Add(name, expects string, expectsInt interface{})

func (TItemHold) AddStd

func (h TItemHold) AddStd(name, expects string, expectsInt interface{})

type TagToAction

type TagToAction struct {
	Suffix      string
	Do          func(*TagToAction, bool, int, []rune) (int, string) // func(tagToAction,open,i,runes) (newI, output)
	Depth       int                                                 // For use by Do
	PartialMode bool
}

type TaskSet

type TaskSet interface {
	Add(func() error)
	GetList() []func() error
	Run() error
	Count() int
}

type TaskStmts

type TaskStmts struct {
	// contains filtered or unexported fields
}

type TemplateMapping

type TemplateMapping struct {
	Name   string
	Source string
}

type TestThaw

type TestThaw struct {
}

func NewTestThaw

func NewTestThaw() *TestThaw

func (*TestThaw) Thaw

func (t *TestThaw) Thaw()

func (*TestThaw) Thawed

func (t *TestThaw) Thawed() bool

func (*TestThaw) Tick

func (t *TestThaw) Tick() error

type ThawInt

type ThawInt interface {
	Thawed() bool
	Thaw()

	Tick() error
}
var TopicListThaw ThawInt

type Theme

type Theme struct {
	Path string // Redirect this file to another folder

	Name           string
	FriendlyName   string
	Version        string
	Creator        string
	FullImage      string
	MobileFriendly bool
	Disabled       bool
	HideFromThemes bool
	BgAvatars      bool // For profiles, at the moment
	GridLists      bool // User Manager
	ForkOf         string
	Tag            string
	URL            string
	Docks          []string // Allowed Values: leftSidebar, rightSidebar, footer
	DocksID        []int    // Integer versions of Docks to try to get a speed boost in BuildWidget()
	Settings       map[string]ThemeSetting
	IntTmplHandle  *htmpl.Template
	// TODO: Do we really need both OverridenTemplates AND OverridenMap?
	OverridenTemplates []string
	OverridenMap       map[string]bool
	Templates          []TemplateMapping
	TemplatesMap       map[string]string
	TmplPtr            map[string]interface{}
	Resources          []ThemeResource
	ResourceTemplates  *template.Template

	// Dock intercepters
	// TODO: Implement this
	MapTmplToDock map[string]ThemeMapTmplToDock // map[dockName]data
	RunOnDock     func(string) string           //(dock string) (sbody string)
	RunOnDockID   func(int) string              //(dock int) (sbody string)

	// This variable should only be set and unset by the system, not the theme meta file
	// TODO: Should we phase out Active and make the default theme store the primary source of truth?
	Active bool
}

func GetThemeByReq

func GetThemeByReq(r *http.Request) *Theme

func (*Theme) AddThemeStaticFiles

func (t *Theme) AddThemeStaticFiles() error

func (Theme) BuildDock

func (t Theme) BuildDock(dock string) (sbody string)

func (Theme) BuildDockByID

func (t Theme) BuildDockByID(id int) (sbody string)

func (*Theme) GetTmpl

func (t *Theme) GetTmpl(template string) interface{}

GetTmpl attempts to get the template for a specific theme, otherwise it falls back on the default template pointer, which if absent will fallback onto the template interpreter

func (Theme) HasDock

func (t Theme) HasDock(name string) bool

func (Theme) HasDockByID

func (t Theme) HasDockByID(id int) bool

func (*Theme) LoadStaticFiles

func (t *Theme) LoadStaticFiles() error

TODO: It might be unsafe to call the template parsing functions with fsnotify, do something more concurrent

func (*Theme) MapTemplates

func (t *Theme) MapTemplates()

func (*Theme) RunTmpl

func (t *Theme) RunTmpl(template string, pi interface{}, w io.Writer) error

NEW method of doing theme templates to allow one user to have a different theme to another. Under construction. TODO: Generate the type switch instead of writing it by hand TODO: Cut the number of types in half

type ThemeList

type ThemeList map[string]*Theme

TODO: Something more thread-safe

var Themes ThemeList = make(map[string]*Theme) // ? Refactor this into a store?

func NewThemeList

func NewThemeList() (themes ThemeList, err error)

func (ThemeList) LoadActiveStatus

func (t ThemeList) LoadActiveStatus() error

TODO: Make the initThemes and LoadThemes functions less confusing ? - Delete themes which no longer exist in the themes folder from the database?

func (ThemeList) LoadStaticFiles

func (t ThemeList) LoadStaticFiles() error

type ThemeMapTmplToDock

type ThemeMapTmplToDock struct {
	//Name string
	File string
}

type ThemeResource

type ThemeResource struct {
	Name     string
	Type     int // 0 = unknown, 1 = sheet, 2 = script
	Location string
	LocID    int
	Loggedin bool // Only serve this resource to logged in users
	Async    bool
}

type ThemeSetting

type ThemeSetting struct {
	FriendlyName string
	Options      []string
}

type ThemeStmts

type ThemeStmts struct {
	// contains filtered or unexported fields
}

type ThumbnailerInt

type ThumbnailerInt interface {
	Resize(format, inPath, tmpPath, outPath string, width int) error
}
var Thumbnailer ThumbnailerInt

type TickLoop

type TickLoop struct {
	HalfSec    *time.Ticker
	Sec        *time.Ticker
	FifteenMin *time.Ticker
	Hour       *time.Ticker
	Day        *time.Ticker

	HalfSecf    func() error
	Secf        func() error
	FifteenMinf func() error
	Hourf       func() error
	Dayf        func() error
}
var CTickLoop *TickLoop

func NewTickLoop

func NewTickLoop() *TickLoop

func (*TickLoop) Loop

func (l *TickLoop) Loop()

type TickWatch

type TickWatch struct {
	Name      string
	Start     int64
	DBCheck   int64
	StartHook int64
	Tasks     int64
	EndHook   int64

	Ticker     *time.Ticker
	Deadline   *time.Ticker
	EndChan    chan bool
	OutEndChan chan bool
}

func NewTickWatch

func NewTickWatch() *TickWatch

func (*TickWatch) Clear

func (w *TickWatch) Clear()

func (*TickWatch) DumpElapsed

func (w *TickWatch) DumpElapsed()

func (*TickWatch) Run

func (w *TickWatch) Run()

func (*TickWatch) Set

func (w *TickWatch) Set(a *int64, v int64)

func (*TickWatch) Stop

func (w *TickWatch) Stop()

type TmplLoggedin

type TmplLoggedin struct {
	Stub   string
	Guest  string
	Member string
}

type Topic

type Topic struct {
	ID          int
	Link        string
	Title       string
	Content     string
	CreatedBy   int
	IsClosed    bool
	Sticky      bool
	CreatedAt   time.Time
	LastReplyAt time.Time
	LastReplyBy int
	LastReplyID int
	ParentID    int
	Status      string // Deprecated. Marked for removal. -Is there anything we could use it for?
	IP          string
	ViewCount   int64
	PostCount   int
	LikeCount   int
	AttachCount int
	WeekViews   int
	ClassName   string // CSS Class Name
	Poll        int
	Data        string // Used for report metadata

	Rids []int
}

func BlankTopic

func BlankTopic() *Topic

For use in tests and for generating blank topics for forums which don't have a last poster

func TopicByReplyID

func TopicByReplyID(rid int) (*Topic, error)

TODO: Load LastReplyAt and LastReplyID?

func (*Topic) AddReply

func (t *Topic) AddReply(rid, uid int) (e error)

TODO: Write a test for this

func (*Topic) Author

func (t *Topic) Author() (*User, error)

TODO: Test this

func (*Topic) Copy

func (t *Topic) Copy() Topic

Copy gives you a non-pointer concurrency safe copy of the topic

func (*Topic) CreateActionReply

func (t *Topic) CreateActionReply(action, ip string, uid int) (err error)

TODO: Have this go through the ReplyStore? TODO: Return the rid?

func (*Topic) Delete

func (t *Topic) Delete() error

TODO: Use a transaction here

func (*Topic) GetID

func (t *Topic) GetID() int

func (*Topic) GetTable

func (t *Topic) GetTable() string

func (*Topic) Like

func (t *Topic) Like(score, uid int) (err error)

TODO: Test this TODO: Use a transaction for this

func (*Topic) Lock

func (t *Topic) Lock() (e error)

func (*Topic) MoveTo

func (t *Topic) MoveTo(destForum int) (e error)

func (*Topic) RemovePoll

func (t *Topic) RemovePoll() error

func (*Topic) SetPoll

func (t *Topic) SetPoll(pollID int) error

func (*Topic) Stick

func (t *Topic) Stick() (e error)

TODO: We might want more consistent terminology rather than using stick in some places and pin in others. If you don't understand the difference, there is none, they are one and the same.

func (*Topic) TestSetCreatedAt

func (t *Topic) TestSetCreatedAt(s time.Time) (e error)

func (*Topic) TopicsRow

func (t *Topic) TopicsRow() *TopicsRow

TODO: Stop relying on so many struct types? ! Not quite safe as Topic doesn't contain all the data needed to constructs a TopicsRow

func (*Topic) Unlike

func (t *Topic) Unlike(uid int) error

TODO: Use a transaction

func (*Topic) Unlock

func (t *Topic) Unlock() (e error)

func (*Topic) Unstick

func (t *Topic) Unstick() (e error)

func (*Topic) Update

func (t *Topic) Update(name, content string) error

TODO: Write tests for this

type TopicCAttachItem

type TopicCAttachItem struct {
	ID       int
	ImgSrc   string
	Path     string
	FullPath string
}

type TopicCEditPost

type TopicCEditPost struct {
	ID     int
	Source string
	Ref    string
}

type TopicCPollInput

type TopicCPollInput struct {
	Index int
	Place string
}

type TopicCache

type TopicCache interface {
	Get(id int) (*Topic, error)
	GetUnsafe(id int) (*Topic, error)
	BulkGet(ids []int) (list []*Topic)
	Set(item *Topic) error
	Add(item *Topic) error
	AddUnsafe(item *Topic) error
	Remove(id int) error
	RemoveUnsafe(id int) error
	RemoveMany(ids []int) error
	Flush()
	Length() int
	SetCapacity(cap int)
	GetCapacity() int
}

TopicCache is an interface which spits out topics from a fast cache rather than the database, whether from memory or from an application like Redis. Topics may not be present in the cache but may be in the database

type TopicListHolder

type TopicListHolder struct {
	List      []*TopicsRow
	ForumList []Forum
	Paginator Paginator
}

type TopicListInt

type TopicListInt interface {
	GetListByCanSee(canSee []int, page, orderby int, filterIDs []int) (topicList []*TopicsRow, forumList []Forum, pagi Paginator, err error)
	GetListByGroup(g *Group, page, orderby int, filterIDs []int) (topicList []*TopicsRow, forumList []Forum, pagi Paginator, err error)
	GetListByForum(f *Forum, page, orderby int) (topicList []*TopicsRow, pagi Paginator, err error)
	GetList(page, orderby int, filterIDs []int) (topicList []*TopicsRow, forumList []Forum, pagi Paginator, err error)
}

TODO: Should we return no rows errors on empty pages? Is this likely to break something?

var TopicList TopicListInt

type TopicListIntTest

type TopicListIntTest interface {
	RawGetListByForum(f *Forum, page, orderby int) (topicList []*TopicsRow, pagi Paginator, err error)
	Tick() error
}

type TopicListPage

type TopicListPage struct {
	*Header
	TopicList    []TopicsRowMut
	ForumList    []Forum
	DefaultForum int
	Sort         TopicListSort
	SelectedFids []int
	QuickTools
	Paginator
}

type TopicListSort

type TopicListSort struct {
	SortBy    string // lastupdate, mostviewed, mostviewedtoday, mostviewedthisweek, mostviewedthismonth
	Ascending bool
}

type TopicPage

type TopicPage struct {
	*Header
	ItemList []*ReplyUser
	Topic    TopicUser
	Forum    *Forum
	Poll     *Poll
	Paginator
}

type TopicStmts

type TopicStmts struct {
	// contains filtered or unexported fields
}

type TopicStore

type TopicStore interface {
	DirtyGet(id int) *Topic
	Get(id int) (*Topic, error)
	BypassGet(id int) (*Topic, error)
	BulkGetMap(ids []int) (list map[int]*Topic, err error)
	Exists(id int) bool
	Create(fid int, name, content string, uid int, ip string) (tid int, err error)
	AddLastTopic(t *Topic, fid int) error // unimplemented
	Reload(id int) error                  // Too much SQL logic to move into TopicCache
	// TODO: Implement these two methods
	//Replies(tid int) ([]*Reply, error)
	//RepliesRange(tid, lower, higher int) ([]*Reply, error)
	Count() int
	CountUser(uid int) int
	CountMegaUser(uid int) int
	CountBigUser(uid int) int

	ClearIPs() error
	LockMany(tids []int) error

	SetCache(cache TopicCache)
	GetCache() TopicCache
}
var Topics TopicStore

TODO: Add the watchdog goroutine TODO: Add some sort of update method ? - Should we add stick, lock, unstick, and unlock methods? These might be better on the Topics not the TopicStore

type TopicUser

type TopicUser struct {
	ID          int
	Link        string
	Title       string
	Content     string // TODO: Avoid converting this to bytes in templates, particularly if it's long
	CreatedBy   int
	IsClosed    bool
	Sticky      bool
	CreatedAt   time.Time
	LastReplyAt time.Time
	LastReplyBy int
	LastReplyID int
	ParentID    int
	Status      string // Deprecated. Marked for removal.
	IP          string
	ViewCount   int64
	PostCount   int
	LikeCount   int
	AttachCount int
	ClassName   string
	Poll        int
	Data        string // Used for report metadata

	UserLink      string
	CreatedByName string
	Group         int
	Avatar        string
	MicroAvatar   string
	ContentLines  int
	ContentHTML   string // TODO: Avoid converting this to bytes in templates, particularly if it's long
	Tag           string
	URL           string
	//URLPrefix     string
	//URLName       string
	Level int
	Liked bool

	Attachments []*MiniAttachment
	Rids        []int
	Deletable   bool
}

func GetTopicUser

func GetTopicUser(user *User, tid int) (tu TopicUser, err error)

TODO: Refactor the caller to take a Topic and a User rather than a combined TopicUser TODO: Load LastReplyAt everywhere in here?

func (*TopicUser) Replies

func (t *TopicUser) Replies(offset int, user *User) (rlist []*ReplyUser, externalHead bool, err error)

TODO: Factor TopicUser into a *Topic and *User, as this starting to become overly complicated x.x

type TopicsRow

type TopicsRow struct {
	Topic
	LastPage int

	Creator      *User
	CSS          template.CSS
	ContentLines int
	LastUser     *User

	ForumName string //TopicsRow
	ForumLink string
}

TODO: Embed TopicUser to simplify this structure and it's related logic?

func (*TopicsRow) WebSockets

func (r *TopicsRow) WebSockets() *WsTopicsRow

TODO: Can we get the client side to render the relative times instead?

func (*TopicsRow) WebSockets2

func (r *TopicsRow) WebSockets2(canMod bool) *WsTopicsRow

TODO: Can we get the client side to render the relative times instead?

type TopicsRowMut

type TopicsRowMut struct {
	*TopicsRow
	CanMod bool
}

type User

type User struct {
	ID           int
	Link         string
	Name         string
	Email        string
	Group        int
	Active       bool
	IsMod        bool
	IsSuperMod   bool
	IsAdmin      bool
	IsSuperAdmin bool
	IsBanned     bool
	Perms        Perms
	PluginPerms  map[string]bool
	Session      string
	//AuthToken    string
	Loggedin    bool
	RawAvatar   string
	Avatar      string
	MicroAvatar string
	Message     string
	// TODO: Implement something like this for profiles?
	//URLPrefix   string // Move this to another table? Create a user lite?
	//URLName     string
	Tag       string
	Level     int
	Score     int
	Posts     int
	Liked     int
	CreatedAt time.Time
	LastIP    string // ! This part of the UserCache data might fall out of date
	LastAgent int    // ! Temporary hack for http push, don't use
	TempGroup int

	ParseSettings *ParseSettings
	Privacy       UserPrivacy
}

func BlankUser

func BlankUser() *User

For use in tests and to help generate dummy users for forums which don't have last posters

func (*User) Activate

func (u *User) Activate() (e error)

TODO: Use a transaction here ? - Add a Deactivate method? Not really needed, if someone's been bad you could do a ban, I guess it might be useful, if someone says that email x isn't actually owned by the user in question?

func (*User) Ban

func (u *User) Ban(dur time.Duration, issuedBy int) error

func (*User) CacheRemove

func (u *User) CacheRemove()

TODO: Refactor this idiom into something shorter, maybe with a NullUserCache when one isn't set?

func (*User) ChangeAvatar

func (u *User) ChangeAvatar(avatar string) error

func (*User) ChangeGroup

func (u *User) ChangeGroup(group int) error

func (*User) ChangeName

func (u *User) ChangeName(name string) error

func (*User) Copy

func (u *User) Copy() User

Copy gives you a non-pointer concurrency safe copy of the user

func (*User) DecreasePostStats

func (u *User) DecreasePostStats(wcount int, topic bool) (err error)

func (*User) Delete

func (u *User) Delete() error

TODO: Write tests for this TODO: Delete this user's content too? TODO: Expose this to the admin?

func (*User) DeletePosts

func (u *User) DeletePosts() error

TODO: dismiss-event

func (*User) GetIP

func (u *User) GetIP() string

func (*User) IncreasePostStats

func (u *User) IncreasePostStats(wcount int, topic bool) (err error)

func (*User) Init

func (u *User) Init()

func (*User) InitPerms

func (u *User) InitPerms()

TODO: Write unit tests for this

func (*User) Me

func (u *User) Me() *MeUser

func (*User) RecalcPostStats

func (u *User) RecalcPostStats() error

func (*User) ResetPostStats

func (u *User) ResetPostStats() error

func (*User) RevertGroupUpdate

func (u *User) RevertGroupUpdate() error

func (*User) ScheduleAvatarResize

func (u *User) ScheduleAvatarResize() (e error)

TODO: Abstract this with an interface so we can scale this with an actual dedicated queue in a real cluster

func (*User) ScheduleGroupUpdate

func (u *User) ScheduleGroupUpdate(gid, issuedBy int, dur time.Duration) error

Make this more stateless?

func (*User) Unban

func (u *User) Unban() error

func (*User) Update

func (u *User) Update(name, email string, group int) (err error)

func (*User) UpdateIP

func (u *User) UpdateIP(ip string) error

! Only updates the database not the *User for safety reasons

func (*User) UpdatePrivacy

func (u *User) UpdatePrivacy(profileComments, enableEmbeds int) error

func (*User) WebSockets

func (u *User) WebSockets() *WsJSONUser

type UserCache

type UserCache interface {
	DeallocOverflow(evictPriority bool) (evicted int) // May cause thread contention, looks for items to evict
	Get(id int) (*User, error)
	Getn(id int) *User
	GetUnsafe(id int) (*User, error)
	BulkGet(ids []int) (list []*User)
	Set(item *User) error
	Add(item *User) error
	AddUnsafe(item *User) error
	Remove(id int) error
	RemoveUnsafe(id int) error
	Flush()
	Length() int
	SetCapacity(cap int)
	GetCapacity() int
}

UserCache is an interface which spits out users from a fast cache rather than the database, whether from memory or from an application like Redis. Users may not be present in the cache but may be in the database

type UserPrivacy

type UserPrivacy struct {
	ShowComments int  // 0 = default, 1 = public, 2 = registered, 3 = friends, 4 = self, 5 = disabled / unused
	AllowMessage int  // 0 = default, 1 = registered, 2 = friends, 3 = mods, 4 = disabled / unused
	NoPresence   bool // false = default, true = true
}

type UserStmts

type UserStmts struct {
	// contains filtered or unexported fields
}

type UserStore

type UserStore interface {
	DirtyGet(id int) *User
	Get(id int) (*User, error)
	Getn(id int) *User
	GetByName(name string) (*User, error)
	BulkGetByName(names []string) (list []*User, err error)
	RawBulkGetByNameForConvo(f func(int, string, int, bool, int, int) error, names []string) error
	Exists(id int) bool
	SearchOffset(name, email string, gid, offset, perPage int) (users []*User, err error)
	GetOffset(offset, perPage int) ([]*User, error)
	Each(f func(*User) error) error
	//BulkGet(ids []int) ([]*User, error)
	BulkGetMap(ids []int) (map[int]*User, error)
	BypassGet(id int) (*User, error)
	ClearLastIPs() error
	Create(name, password, email string, group int, active bool) (int, error)
	Reload(id int) error
	Count() int
	CountSearch(name, email string, gid int) int

	SetCache(cache UserCache)
	GetCache() UserCache
}
var Users UserStore

TODO: Add the watchdog goroutine TODO: Add some sort of update method

type Version

type Version struct {
	Major int
	Minor int
	Patch int
	Tag   string
	TagID int
}

Version stores a Gosora version

func (*Version) String

func (ver *Version) String() (out string)

TODO: Write a test for this

type WSUser

type WSUser struct {
	User    *User
	Sockets []*WSUserSocket
	sync.Mutex
}

func (*WSUser) AddSocket

func (u *WSUser) AddSocket(conn *websocket.Conn, page string)

func (*WSUser) CountSockets

func (u *WSUser) CountSockets() int

func (*WSUser) FinalizePage

func (u *WSUser) FinalizePage(page string, h func())

func (*WSUser) InPage

func (u *WSUser) InPage(page string) bool

func (*WSUser) Ping

func (u *WSUser) Ping() error

func (*WSUser) RemoveSocket

func (u *WSUser) RemoveSocket(conn *websocket.Conn)

func (*WSUser) SetPageForSocket

func (u *WSUser) SetPageForSocket(conn *websocket.Conn, page string) error

func (*WSUser) WriteAll

func (u *WSUser) WriteAll(msg string) error

func (*WSUser) WriteToPage

func (u *WSUser) WriteToPage(msg, page string) error

func (*WSUser) WriteToPageBytes

func (u *WSUser) WriteToPageBytes(msg []byte, page string) error

Inefficient as it looks for sockets for a page even if there are none

func (*WSUser) WriteToPageBytesMulti

func (u *WSUser) WriteToPageBytesMulti(msgs [][]byte, page string) error

Inefficient as it looks for sockets for a page even if there are none

type WSUserSocket

type WSUserSocket struct {
	Page string
	// contains filtered or unexported fields
}

type Widget

type Widget struct {
	ID       int
	Enabled  bool
	Location string // Coming Soon: overview, topics, topic / topic_view, forums, forum, global
	Position int
	RawBody  string
	Body     string
	Side     string
	Type     string

	Literal      bool
	TickMask     atomic.Value
	InitFunc     func(w *Widget, sched *WidgetScheduler) error
	ShutdownFunc func(w *Widget) error
	BuildFunc    func(w *Widget, hvars interface{}) (string, error)
	TickFunc     func(w *Widget) error
}

TODO: Shrink this struct for common uses in the templates? Would that really make things go faster?

func GetDock

func GetDock(dock string) []*Widget

func (*Widget) Allowed

func (w *Widget) Allowed(zone string, zoneid int) bool

TODO: Test this TODO: Add support for zone:id. Perhaps, carry a ZoneID property around in *Header? It might allow some weirdness like frontend[5] which matches any zone with an ID of 5 but it would be a tad faster than verifying each zone, although it might be problematic if users end up relying on this behaviour for areas which don't pass IDs to the widgets system but *probably* should TODO: Add a selector which also matches topics inside a specific forum?

func (*Widget) Build

func (w *Widget) Build(hvars interface{}) (string, error)

TODO: Refactor

func (*Widget) Copy

func (w *Widget) Copy() (ow *Widget)

func (*Widget) Delete

func (w *Widget) Delete() error

type WidgetDock

type WidgetDock struct {
	Items     []*Widget
	Scheduler *WidgetScheduler
}

type WidgetDocks

type WidgetDocks struct {
	LeftOfNav    []*Widget
	RightOfNav   []*Widget
	LeftSidebar  WidgetDock
	RightSidebar WidgetDock
	//PanelLeft []Menus
	Footer WidgetDock
}
var Docks WidgetDocks

TODO: Clean this file up

type WidgetEdit

type WidgetEdit struct {
	*Widget
	Data map[string]string
}

func (*WidgetEdit) Commit

func (w *WidgetEdit) Commit() error

func (*WidgetEdit) Create

func (w *WidgetEdit) Create() (int, error)

type WidgetMenu

type WidgetMenu struct {
	Name     string
	MenuList []WidgetMenuItem
}

type WidgetMenuItem

type WidgetMenuItem struct {
	Text     string
	Location string
	Compact  bool
}

type WidgetScheduler

type WidgetScheduler struct {
	// contains filtered or unexported fields
}

func (*WidgetScheduler) Add

func (s *WidgetScheduler) Add(w *Widget)

func (*WidgetScheduler) Store

func (s *WidgetScheduler) Store()

func (*WidgetScheduler) Tick

func (s *WidgetScheduler) Tick() error

type WidgetStmts

type WidgetStmts struct {
	// contains filtered or unexported fields
}

type WordFilter

type WordFilter struct {
	ID      int
	Find    string
	Replace string
}

TODO: Move some features into methods on this?

type WordFilterDiff

type WordFilterDiff struct {
	BeforeFind    string
	BeforeReplace string
	AfterFind     string
	AfterReplace  string
}

type WordFilterStore

type WordFilterStore interface {
	ReloadAll() error
	GetAll() (filters map[int]*WordFilter, err error)
	Get(id int) (*WordFilter, error)
	Create(find, replace string) (int, error)
	Delete(id int) error
	Update(id int, find, replace string) error
	Length() int
	EstCount() int
	Count() (count int)
}
var WordFilters WordFilterStore

type WsHubImpl

type WsHubImpl struct {

	// TODO: Add sharding for this too?
	OnlineGuests map[*WSUser]bool
	GuestLock    sync.RWMutex
	// contains filtered or unexported fields
}

TODO: Make this an interface? TODO: Write tests for this

var WsHub WsHubImpl

TODO: Rename this to WebSockets?

func (*WsHubImpl) AddConn

func (h *WsHubImpl) AddConn(user *User, conn *websocket.Conn) (*WSUser, error)

func (*WsHubImpl) AllUsers

func (h *WsHubImpl) AllUsers() (users []*User)

For Widget WOL, please avoid using this as it might wind up being really long and slow without the right safeguards

func (*WsHubImpl) GuestCount

func (h *WsHubImpl) GuestCount() int

func (*WsHubImpl) HasUser

func (h *WsHubImpl) HasUser(uid int) (exists bool)

func (*WsHubImpl) PushMessage

func (h *WsHubImpl) PushMessage(targetUser int, msg string) error

func (*WsHubImpl) RemoveConn

func (h *WsHubImpl) RemoveConn(wsUser *WSUser, conn *websocket.Conn)

func (*WsHubImpl) Start

func (h *WsHubImpl) Start()

func (*WsHubImpl) Tick

func (h *WsHubImpl) Tick() error

This Tick is separate from the admin one, as we want to process that in parallel with this due to the blocking calls to gopsutil

func (*WsHubImpl) UserCount

func (h *WsHubImpl) UserCount() (count int)

type WsJSONUser

type WsJSONUser struct {
	ID          int
	Link        string
	Name        string
	Group       int // Be sure to mask with TempGroup
	IsMod       bool
	Avatar      string
	MicroAvatar string
	Level       int
	Score       int
	Liked       int
}

Use struct tags to avoid having to define this? It really depends on the circumstances, sometimes we want the whole thing, sometimes... not.

type WsTopicList

type WsTopicList struct {
	Topics     []*WsTopicsRow
	LastPage   int // Not for WebSockets, but for the JSON endpoint for /topics/ to keep the paginator functional
	LastUpdate int64
}

type WsTopicsRow

type WsTopicsRow struct {
	ID                  int
	Link                string
	Title               string
	CreatedBy           int
	IsClosed            bool
	Sticky              bool
	CreatedAt           time.Time
	LastReplyAt         time.Time
	RelativeLastReplyAt string
	LastReplyBy         int
	LastReplyID         int
	ParentID            int
	ViewCount           int64
	PostCount           int
	LikeCount           int
	AttachCount         int
	ClassName           string
	Creator             *WsJSONUser
	LastUser            *WsJSONUser
	ForumName           string
	ForumLink           string
	CanMod              bool
}

Directories

Path Synopsis
Google Authenticator 2FA Borrowed from https://github.com/tilaklodha/google-authenticator, as we can't import it as a library as it's in package main
Google Authenticator 2FA Borrowed from https://github.com/tilaklodha/google-authenticator, as we can't import it as a library as it's in package main
* * Gosora Phrase System * Copyright Azareal 2017 - 2020 *
* * Gosora Phrase System * Copyright Azareal 2017 - 2020 *

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL