NoEmbeds privacy and config settings.
Phase out url_prefix and url_name. Eliminate some boilerplate and allocations while we're at it. Reduce the number of conditional statements in url validator loops. Better parsing of Site.URL to handle user error better. You will have to run the patcher / updater for this commit.
This commit is contained in:
parent
3715c800da
commit
0dede6a329
|
@ -31,11 +31,15 @@ func createTables(adapter qgen.Adapter) (err error) {
|
|||
tC{"session", "varchar", 200, false, false, "''"},
|
||||
//tC{"authToken", "varchar", 200, false, false, "''"},
|
||||
tC{"last_ip", "varchar", 200, false, false, "0.0.0.0.0"},
|
||||
tC{"enable_embeds", "int", 0, false, false, "-1"},
|
||||
tC{"email", "varchar", 200, false, false, "''"},
|
||||
tC{"avatar", "varchar", 100, false, false, "''"},
|
||||
tC{"message", "text", 0, false, false, "''"},
|
||||
|
||||
// TODO: Drop these columns?
|
||||
tC{"url_prefix", "varchar", 20, false, false, "''"},
|
||||
tC{"url_name", "varchar", 100, false, false, "''"},
|
||||
|
||||
tC{"level", "smallint", 0, false, false, "0"},
|
||||
tC{"score", "int", 0, false, false, "0"},
|
||||
tC{"posts", "int", 0, false, false, "0"},
|
||||
|
|
|
@ -248,6 +248,13 @@ type AccountBlocksPage struct {
|
|||
Paginator
|
||||
}
|
||||
|
||||
type AccountPrivacyPage struct {
|
||||
*Header
|
||||
ProfileComments bool
|
||||
ReceiveConvos bool
|
||||
EnableEmbeds bool
|
||||
}
|
||||
|
||||
type AccountDashPage struct {
|
||||
*Header
|
||||
MFASetup bool
|
||||
|
|
100
common/parser.go
100
common/parser.go
|
@ -449,10 +449,26 @@ var hashLinkMap = map[string]func(*strings.Builder, string, *int){
|
|||
// TODO: Forum Shortcode Link
|
||||
}
|
||||
|
||||
// TODO: Pack multiple bit flags into an integer instead of using a struct?
|
||||
var DefaultParseSettings = &ParseSettings{}
|
||||
|
||||
type ParseSettings struct {
|
||||
NoEmbed bool
|
||||
}
|
||||
|
||||
func (ps *ParseSettings) CopyPtr() *ParseSettings {
|
||||
n := &ParseSettings{}
|
||||
*n = *ps
|
||||
return n
|
||||
}
|
||||
|
||||
// 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 ParseMessage(msg string, sectionID int, sectionType string /*, user User*/) string {
|
||||
func ParseMessage(msg string, sectionID int, sectionType string, settings *ParseSettings /*, user User*/) string {
|
||||
if settings == nil {
|
||||
settings = DefaultParseSettings
|
||||
}
|
||||
// TODO: Word boundary detection for these to avoid mangling code
|
||||
msg = strings.Replace(msg, ":)", "😀", -1)
|
||||
msg = strings.Replace(msg, ":(", "😞", -1)
|
||||
|
@ -544,10 +560,10 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/)
|
|||
i--
|
||||
} else if msg[i] == 'h' || msg[i] == 'f' || msg[i] == 'g' || msg[i] == '/' {
|
||||
//fmt.Println("s3")
|
||||
if len(msg) > i+3 && msg[i+1] == 't' && msg[i+2] == 't' && msg[i+3] == 'p' {
|
||||
if len(msg) > i+5 && msg[i+1] == 't' && msg[i+2] == 't' && msg[i+3] == 'p' {
|
||||
if len(msg) > i+6 && msg[i+4] == 's' && msg[i+5] == ':' && msg[i+6] == '/' {
|
||||
// Do nothing
|
||||
} else if len(msg) > i+5 && msg[i+4] == ':' && msg[i+5] == '/' {
|
||||
} else if msg[i+4] == ':' && msg[i+5] == '/' {
|
||||
// Do nothing
|
||||
} else {
|
||||
continue
|
||||
|
@ -593,7 +609,7 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/)
|
|||
continue
|
||||
}
|
||||
|
||||
media, ok := parseMediaString(msg[i : i+urlLen])
|
||||
media, ok := parseMediaString(msg[i:i+urlLen], settings)
|
||||
if !ok {
|
||||
//fmt.Println("o3")
|
||||
sb.Write(InvalidURL)
|
||||
|
@ -702,8 +718,8 @@ func validateURLString(data string) bool {
|
|||
|
||||
// ? - There should only be one : and that's only if the URL is on a non-standard port. Same for ?s.
|
||||
for ; len(data) > i; i++ {
|
||||
ch := data[i] // char
|
||||
if ch != '\\' && ch != '_' && ch != ':' && ch != '?' && ch != '&' && ch != '=' && ch != ';' && ch != '@' && ch != '#' && ch != ']' && !(ch > 44 && ch < 58) && !(ch > 64 && ch < 92) && !(ch > 96 && ch < 123) { // 90 is Z, 91 is [
|
||||
ch := data[i]
|
||||
if ch != '\\' && ch != '_' && ch != '?' && ch != '&' && ch != '=' && ch != '@' && ch != '#' && ch != ']' && !(ch > 44 && ch < 60) && !(ch > 64 && ch < 92) && !(ch > 96 && ch < 123) { // 57 is 9, 58 is :, 59 is ;, 90 is Z, 91 is [
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -728,8 +744,8 @@ func validatedURLBytes(data []byte) (url []byte) {
|
|||
|
||||
// ? - There should only be one : and that's only if the URL is on a non-standard port. Same for ?s.
|
||||
for ; datalen > i; i++ {
|
||||
ch := data[i] // char
|
||||
if ch != '\\' && ch != '_' && ch != ':' && ch != '?' && ch != '&' && ch != '=' && ch != ';' && ch != '@' && ch != '#' && ch != ']' && !(ch > 44 && ch < 58) && !(ch > 64 && ch < 92) && !(ch > 96 && ch < 123) { // 90 is Z, 91 is [
|
||||
ch := data[i]
|
||||
if ch != '\\' && ch != '_' && ch != '?' && ch != '&' && ch != '=' && ch != '@' && ch != '#' && ch != ']' && !(ch > 44 && ch < 60) && !(ch > 64 && ch < 92) && !(ch > 96 && ch < 123) { // 57 is 9, 58 is :, 59 is ;, 90 is Z, 91 is [
|
||||
return InvalidURL
|
||||
}
|
||||
}
|
||||
|
@ -756,8 +772,8 @@ func PartialURLString(data string) (url []byte) {
|
|||
|
||||
// ? - There should only be one : and that's only if the URL is on a non-standard port. Same for ?s.
|
||||
for ; end >= i; i++ {
|
||||
ch := data[i] // char
|
||||
if ch != '\\' && ch != '_' && ch != ':' && ch != '?' && ch != '&' && ch != '=' && ch != ';' && ch != '@' && ch != '#' && ch != ']' && !(ch > 44 && ch < 58) && !(ch > 64 && ch < 92) && !(ch > 96 && ch < 123) { // 90 is Z, 91 is [
|
||||
ch := data[i]
|
||||
if ch != '\\' && ch != '_' && ch != '?' && ch != '&' && ch != '=' && ch != '@' && ch != '#' && ch != ']' && !(ch > 44 && ch < 60) && !(ch > 64 && ch < 92) && !(ch > 96 && ch < 123) { // 57 is 9, 58 is :, 59 is ;, 90 is Z, 91 is [
|
||||
end = i
|
||||
}
|
||||
}
|
||||
|
@ -796,7 +812,7 @@ func PartialURLStringLen(data string) (int, bool) {
|
|||
if ch < 33 { // space and invisibles
|
||||
//fmt.Println("e2:",i)
|
||||
return i, i != f
|
||||
} else if ch != '\\' && ch != '_' && ch != ':' && ch != '?' && ch != '&' && ch != '=' && ch != ';' && ch != '@' && ch != '#' && ch != ']' && !(ch > 44 && ch < 58) && !(ch > 64 && ch < 92) && !(ch > 96 && ch < 123) { // 90 is Z, 91 is [
|
||||
} else if ch != '\\' && ch != '_' && ch != '?' && ch != '&' && ch != '=' && ch != '@' && ch != '#' && ch != ']' && !(ch > 44 && ch < 60) && !(ch > 64 && ch < 92) && !(ch > 96 && ch < 123) { // 57 is 9, 58 is :, 59 is ;, 90 is Z, 91 is [
|
||||
//log.Print("Bad Character: ", ch)
|
||||
//fmt.Println("e3")
|
||||
return i, false
|
||||
|
@ -830,8 +846,8 @@ func PartialURLStringLen2(data string) int {
|
|||
|
||||
// ? - There should only be one : and that's only if the URL is on a non-standard port. Same for ?s.
|
||||
for ; len(data) > i; i++ {
|
||||
ch := data[i] //char
|
||||
if ch != '\\' && ch != '_' && ch != ':' && ch != '?' && ch != '&' && ch != '=' && ch != ';' && ch != '@' && ch != '#' && !(ch > 44 && ch < 58) && !(ch > 64 && ch < 91) && !(ch > 96 && ch < 123) { // 90 is Z, 91 is [
|
||||
ch := data[i]
|
||||
if ch != '\\' && ch != '_' && ch != '?' && ch != '&' && ch != '=' && ch != '@' && ch != '#' && ch != ']' && !(ch > 44 && ch < 60) && !(ch > 64 && ch < 91) && !(ch > 96 && ch < 123) { // 57 is 9, 58 is :, 59 is ;, 90 is Z, 91 is [
|
||||
//log.Print("Bad Character: ", ch)
|
||||
return i
|
||||
}
|
||||
|
@ -850,7 +866,7 @@ type MediaEmbed struct {
|
|||
}
|
||||
|
||||
// TODO: Write a test for this
|
||||
func parseMediaString(data string) (media MediaEmbed, ok bool) {
|
||||
func parseMediaString(data string, settings *ParseSettings) (media MediaEmbed, ok bool) {
|
||||
if !validateURLString(data) {
|
||||
return media, false
|
||||
}
|
||||
|
@ -907,32 +923,34 @@ func parseMediaString(data string) (media MediaEmbed, ok bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// ? - I don't think this hostname will hit every YT domain
|
||||
// TODO: Make this a more customisable handler rather than hard-coding it in here
|
||||
if strings.HasSuffix(host, ".youtube.com") && path == "/watch" {
|
||||
video, ok := query["v"]
|
||||
if ok && len(video) >= 1 && video[0] != "" {
|
||||
media.Type = "raw"
|
||||
// TODO: Filter the URL to make sure no nasties end up in there
|
||||
media.Body = "<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/" + video[0] + "' frameborder=0 allowfullscreen></iframe>"
|
||||
return media, true
|
||||
}
|
||||
}
|
||||
|
||||
if lastFrag := pathFrags[len(pathFrags)-1]; lastFrag != "" {
|
||||
// TODO: Write a function for getting the file extension of a string
|
||||
if extarr := strings.Split(lastFrag, "."); len(extarr) >= 2 {
|
||||
ext := extarr[len(extarr)-1]
|
||||
if ImageFileExts.Contains(ext) {
|
||||
media.Type = "image"
|
||||
var sport string
|
||||
if port != "443" && port != "80" && port != "" {
|
||||
sport = ":" + port
|
||||
}
|
||||
media.URL = scheme + "//" + host + sport + path
|
||||
if !settings.NoEmbed {
|
||||
// ? - I don't think this hostname will hit every YT domain
|
||||
// TODO: Make this a more customisable handler rather than hard-coding it in here
|
||||
if strings.HasSuffix(host, ".youtube.com") && path == "/watch" {
|
||||
video, ok := query["v"]
|
||||
if ok && len(video) >= 1 && video[0] != "" {
|
||||
media.Type = "raw"
|
||||
// TODO: Filter the URL to make sure no nasties end up in there
|
||||
media.Body = "<iframe class='postIframe' src='https://www.youtube-nocookie.com/embed/" + video[0] + "' frameborder=0 allowfullscreen></iframe>"
|
||||
return media, true
|
||||
}
|
||||
}
|
||||
|
||||
if lastFrag := pathFrags[len(pathFrags)-1]; lastFrag != "" {
|
||||
// TODO: Write a function for getting the file extension of a string
|
||||
if extarr := strings.Split(lastFrag, "."); len(extarr) >= 2 {
|
||||
ext := extarr[len(extarr)-1]
|
||||
if ImageFileExts.Contains(ext) {
|
||||
media.Type = "image"
|
||||
var sport string
|
||||
if port != "443" && port != "80" && port != "" {
|
||||
sport = ":" + port
|
||||
}
|
||||
media.URL = scheme + "//" + host + sport + path
|
||||
return media, true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sport string
|
||||
|
@ -947,8 +965,8 @@ func parseMediaString(data string) (media MediaEmbed, ok bool) {
|
|||
if len(uurl.Fragment) > 0 {
|
||||
frag = "#" + uurl.Fragment
|
||||
}
|
||||
media.URL = scheme + "//" + host + sport + path + q + frag
|
||||
media.FURL = host + sport + path + q + frag
|
||||
media.URL = scheme + "//" + media.FURL
|
||||
|
||||
return media, true
|
||||
}
|
||||
|
@ -978,7 +996,7 @@ func CoerceIntString(data string) (res int, length int) {
|
|||
|
||||
// TODO: Write tests for this
|
||||
// Make sure we reflect changes to this in the JS port in /public/global.js
|
||||
func Paginate(currentPage int, lastPage int, maxPages int) (out []int) {
|
||||
func Paginate(currentPage, lastPage, maxPages int) (out []int) {
|
||||
diff := lastPage - currentPage
|
||||
pre := 3
|
||||
if diff < 3 {
|
||||
|
@ -998,7 +1016,7 @@ func Paginate(currentPage int, lastPage int, 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 PageOffset(count int, page int, perPage int) (int, int, int) {
|
||||
func PageOffset(count, page, perPage int) (int, int, int) {
|
||||
var offset int
|
||||
lastPage := LastPage(count, perPage)
|
||||
if page > 1 {
|
||||
|
@ -1020,6 +1038,6 @@ func PageOffset(count int, page int, 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 LastPage(count int, perPage int) int {
|
||||
func LastPage(count, perPage int) int {
|
||||
return (count / perPage) + 1
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"html"
|
||||
"time"
|
||||
|
||||
"github.com/Azareal/Gosora/query_gen"
|
||||
qgen "github.com/Azareal/Gosora/query_gen"
|
||||
)
|
||||
|
||||
var profileReplyStmts ProfileReplyStmts
|
||||
|
@ -20,7 +20,7 @@ type ProfileReply struct {
|
|||
LastEdit int
|
||||
LastEditBy int
|
||||
ContentLines int
|
||||
IP string
|
||||
IP string
|
||||
}
|
||||
|
||||
type ProfileReplyStmts struct {
|
||||
|
@ -30,9 +30,10 @@ type ProfileReplyStmts struct {
|
|||
|
||||
func init() {
|
||||
DbInits.Add(func(acc *qgen.Accumulator) error {
|
||||
ur := "users_replies"
|
||||
profileReplyStmts = ProfileReplyStmts{
|
||||
edit: acc.Update("users_replies").Set("content = ?, parsed_content = ?").Where("rid = ?").Prepare(),
|
||||
delete: acc.Delete("users_replies").Where("rid = ?").Prepare(),
|
||||
edit: acc.Update(ur).Set("content = ?, parsed_content = ?").Where("rid = ?").Prepare(),
|
||||
delete: acc.Delete(ur).Where("rid = ?").Prepare(),
|
||||
}
|
||||
return acc.FirstError()
|
||||
})
|
||||
|
@ -51,7 +52,7 @@ func (r *ProfileReply) Delete() error {
|
|||
|
||||
func (r *ProfileReply) SetBody(content string) error {
|
||||
content = PreparseMessage(html.UnescapeString(content))
|
||||
_, err := profileReplyStmts.edit.Exec(content, ParseMessage(content, 0, ""), r.ID)
|
||||
_, err := profileReplyStmts.edit.Exec(content, ParseMessage(content, 0, "", nil), r.ID)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ func (s *SQLProfileReplyStore) Get(id int) (*ProfileReply, error) {
|
|||
}
|
||||
|
||||
func (s *SQLProfileReplyStore) Create(profileID int, content string, createdBy int, ipaddress string) (id int, err error) {
|
||||
res, err := s.create.Exec(profileID, content, ParseMessage(content, 0, ""), createdBy, ipaddress)
|
||||
res, err := s.create.Exec(profileID, content, ParseMessage(content, 0, "", nil), createdBy, ipaddress)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
@ -17,31 +17,18 @@ import (
|
|||
|
||||
type ReplyUser struct {
|
||||
Reply
|
||||
//ID int
|
||||
//ParentID int
|
||||
//Content string
|
||||
ContentHtml string
|
||||
//CreatedBy int
|
||||
|
||||
ContentHtml string
|
||||
UserLink string
|
||||
CreatedByName string
|
||||
//Group int
|
||||
//CreatedAt time.Time
|
||||
//LastEdit int
|
||||
//LastEditBy int
|
||||
Avatar string
|
||||
MicroAvatar string
|
||||
ClassName string
|
||||
//ContentLines int
|
||||
Tag string
|
||||
URL string
|
||||
URLPrefix string
|
||||
URLName string
|
||||
Level int
|
||||
//IP string
|
||||
//Liked bool
|
||||
//LikeCount int
|
||||
//AttachCount int
|
||||
//ActionType string
|
||||
Avatar string
|
||||
MicroAvatar string
|
||||
ClassName string
|
||||
Tag string
|
||||
URL string
|
||||
//URLPrefix string
|
||||
//URLName string
|
||||
Level int
|
||||
ActionIcon string
|
||||
|
||||
Attachments []*MiniAttachment
|
||||
|
@ -139,7 +126,7 @@ func (r *Reply) SetPost(content string) error {
|
|||
return err
|
||||
}
|
||||
content = PreparseMessage(html.UnescapeString(content))
|
||||
parsedContent := ParseMessage(content, topic.ParentID, "forums")
|
||||
parsedContent := ParseMessage(content, topic.ParentID, "forums", nil)
|
||||
_, err = replyStmts.edit.Exec(content, parsedContent, r.ID) // TODO: Sniff if this changed anything to see if we hit an existing poll
|
||||
_ = Rstore.GetCache().Remove(r.ID)
|
||||
return err
|
||||
|
|
|
@ -52,7 +52,7 @@ func (s *SQLReplyStore) Get(id int) (*Reply, error) {
|
|||
|
||||
// TODO: Write a test for this
|
||||
func (s *SQLReplyStore) Create(t *Topic, content string, ip string, uid int) (rid int, err error) {
|
||||
res, err := s.create.Exec(t.ID, content, ParseMessage(content, t.ParentID, "forums"), ip, WordCount(content), uid)
|
||||
res, err := s.create.Exec(t.ID, content, ParseMessage(content, t.ParentID, "forums", nil), ip, WordCount(content), uid)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ func NewDefaultReportStore(acc *qgen.Accumulator) (*DefaultReportStore, 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
|
||||
func (s *DefaultReportStore) Create(title string, content string, user *User, itemType string, itemID int) (tid int, err error) {
|
||||
func (s *DefaultReportStore) Create(title string, content string, u *User, itemType string, itemID int) (tid int, err error) {
|
||||
var count int
|
||||
err = s.exists.QueryRow(itemType+"_"+strconv.Itoa(itemID), ReportForumID).Scan(&count)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
|
@ -44,7 +44,7 @@ func (s *DefaultReportStore) Create(title string, content string, user *User, it
|
|||
return 0, ErrAlreadyReported
|
||||
}
|
||||
|
||||
res, err := s.create.Exec(title, content, ParseMessage(content, 0, ""), user.LastIP, user.ID, user.ID, itemType+"_"+strconv.Itoa(itemID), ReportForumID)
|
||||
res, err := s.create.Exec(title, content, ParseMessage(content, 0, "", nil), u.LastIP, u.ID, u.ID, itemType+"_"+strconv.Itoa(itemID), ReportForumID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -53,5 +53,6 @@ func (s *DefaultReportStore) Create(title string, content string, user *User, it
|
|||
return 0, err
|
||||
}
|
||||
tid = int(lastID)
|
||||
return tid, Forums.AddTopic(tid, user.ID, ReportForumID)
|
||||
|
||||
return tid, Forums.AddTopic(tid, u.ID, ReportForumID)
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ type config struct {
|
|||
|
||||
PrimaryServer bool
|
||||
ServerCount int
|
||||
LastIPCutoff int // Currently just -1, non--1, but will accept the number of months a user's last IP should be retained for in the future before being purged. Please note that the other two cutoffs below operate off the numbers of days instead.
|
||||
PostIPCutoff int
|
||||
LogPruneCutoff int
|
||||
|
||||
|
@ -99,7 +100,7 @@ type config struct {
|
|||
//LooseCSP bool
|
||||
LooseHost bool
|
||||
LoosePort bool
|
||||
SslSchema bool // Pretend we're using SSL, might be useful if a reverse-proxy terminates SSL in-front of Gosora
|
||||
SslSchema bool // Pretend we're using SSL, might be useful if a reverse-proxy terminates SSL in-front of Gosora
|
||||
DisableServerPush bool
|
||||
EnableCDNPush bool
|
||||
DisableNoavatarRange bool
|
||||
|
@ -107,6 +108,7 @@ type config struct {
|
|||
|
||||
RefNoTrack bool
|
||||
RefNoRef bool
|
||||
NoEmbed bool
|
||||
|
||||
Noavatar string // ? - Move this into the settings table?
|
||||
ItemsPerPage int // ? - Move this into the settings table?
|
||||
|
@ -163,6 +165,10 @@ func LoadConfig() error {
|
|||
func ProcessConfig() (err error) {
|
||||
Config.Noavatar = strings.Replace(Config.Noavatar, "{site_url}", Site.URL, -1)
|
||||
guestAvatar = GuestAvatar{buildNoavatar(0, 200), buildNoavatar(0, 48)}
|
||||
|
||||
// Strip these unnecessary bits, if we find them.
|
||||
Site.URL = strings.TrimPrefix(Site.URL, "http://")
|
||||
Site.URL = strings.TrimPrefix(Site.URL, "https://")
|
||||
Site.Host = Site.URL
|
||||
Site.LocalHost = Site.Host == "localhost" || Site.Host == "127.0.0.1" || Site.Host == "::1"
|
||||
Site.PortInt, err = strconv.Atoi(Site.Port)
|
||||
|
@ -216,6 +222,9 @@ func ProcessConfig() (err error) {
|
|||
if Config.LogPruneCutoff == 0 {
|
||||
Config.LogPruneCutoff = 365 // Default cutoff
|
||||
}
|
||||
if Config.NoEmbed {
|
||||
DefaultParseSettings.NoEmbed = true
|
||||
}
|
||||
|
||||
// ? Find a way of making these unlimited if zero? It might rule out some optimisations, waste memory, and break layouts
|
||||
if Config.MaxTopicTitleLength == 0 {
|
||||
|
@ -240,20 +249,18 @@ func ProcessConfig() (err error) {
|
|||
return nil
|
||||
}
|
||||
|
||||
func VerifyConfig() error {
|
||||
if !Forums.Exists(Config.DefaultForum) {
|
||||
return errors.New("Invalid default forum")
|
||||
func VerifyConfig() (err error) {
|
||||
switch {
|
||||
case !Forums.Exists(Config.DefaultForum):
|
||||
err = errors.New("Invalid default forum")
|
||||
case Config.ServerCount < 1:
|
||||
err = errors.New("You can't have less than one server")
|
||||
case Config.MaxTopicTitleLength > 100:
|
||||
err = errors.New("The max topic title length cannot be over 100 as that's unable to fit in the database row")
|
||||
case Config.MaxUsernameLength > 100:
|
||||
err = errors.New("The max username length cannot be over 100 as that's unable to fit in the database row")
|
||||
}
|
||||
if Config.ServerCount < 1 {
|
||||
return errors.New("You can't have less than one server")
|
||||
}
|
||||
if Config.MaxTopicTitleLength > 100 {
|
||||
return errors.New("The max topic title length cannot be over 100 as that's unable to fit in the database row")
|
||||
}
|
||||
if Config.MaxUsernameLength > 100 {
|
||||
return errors.New("The max username length cannot be over 100 as that's unable to fit in the database row")
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func SwitchToTestDB() {
|
||||
|
|
|
@ -14,8 +14,8 @@ import (
|
|||
|
||||
"github.com/Azareal/Gosora/common/alerts"
|
||||
p "github.com/Azareal/Gosora/common/phrases"
|
||||
"github.com/Azareal/Gosora/common/templates"
|
||||
"github.com/Azareal/Gosora/query_gen"
|
||||
tmpl "github.com/Azareal/Gosora/common/templates"
|
||||
qgen "github.com/Azareal/Gosora/query_gen"
|
||||
)
|
||||
|
||||
var Ctemplates []string // TODO: Use this to filter out top level templates we don't need
|
||||
|
@ -93,14 +93,14 @@ var Template_account_handle = genIntTmpl("account")
|
|||
|
||||
func tmplInitUsers() (User, User, User) {
|
||||
avatar, microAvatar := BuildAvatar(62, "")
|
||||
user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", avatar, microAvatar, "", "", "", "", 0, 0, 0, 0,"0.0.0.0.0", "", 0}
|
||||
user := User{62, BuildProfileURL("fake-user", 62), "Fake User", "compiler@localhost", 0, false, false, false, false, false, false, GuestPerms, make(map[string]bool), "", false, "", avatar, microAvatar, "", "", 0, 0, 0, 0, "0.0.0.0.0", "", 0, nil}
|
||||
|
||||
// TODO: Do a more accurate level calculation for this?
|
||||
avatar, microAvatar = BuildAvatar(1, "")
|
||||
user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 58, 1000, 0, 1000, "127.0.0.1", "", 0}
|
||||
user2 := User{1, BuildProfileURL("admin-alice", 1), "Admin Alice", "alice@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", 58, 1000, 0, 1000, "127.0.0.1", "", 0, nil}
|
||||
|
||||
avatar, microAvatar = BuildAvatar(2, "")
|
||||
user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", "", "", 42, 900, 0, 900, "::1", "", 0}
|
||||
user3 := User{2, BuildProfileURL("admin-fred", 62), "Admin Fred", "fred@localhost", 1, true, true, true, true, false, false, AllPerms, make(map[string]bool), "", true, "", avatar, microAvatar, "", "", 42, 900, 0, 900, "::1", "", 0, nil}
|
||||
return user, user2, user3
|
||||
}
|
||||
|
||||
|
@ -170,8 +170,8 @@ func CompileTemplates() error {
|
|||
log.Printf("overriden: %+v\n", overriden)
|
||||
|
||||
config := tmpl.CTemplateConfig{
|
||||
Minify: Config.MinifyTemplates,
|
||||
Debug: Dev.DebugMode,
|
||||
Minify: Config.MinifyTemplates,
|
||||
Debug: Dev.DebugMode,
|
||||
SuperDebug: Dev.TemplateDebug,
|
||||
}
|
||||
c := tmpl.NewCTemplateSet("normal")
|
||||
|
@ -239,11 +239,11 @@ func compileCommons(c *tmpl.CTemplateSet, head *Header, head2 *Header, forumList
|
|||
}, VoteCount: 7}
|
||||
avatar, microAvatar := BuildAvatar(62, "")
|
||||
miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}}
|
||||
topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", "", "", 58, false, miniAttach, nil,false}
|
||||
topic := TopicUser{1, "blah", "Blah", "Hey there!", 0, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", 58, false, miniAttach, nil, false}
|
||||
|
||||
var replyList []*ReplyUser
|
||||
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
|
||||
ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, URLPrefix: "", URLName: "", Level: 0, Attachments: miniAttach}
|
||||
ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, Level: 0, Attachments: miniAttach}
|
||||
ru.Init()
|
||||
replyList = append(replyList, ru)
|
||||
tpage := TopicPage{htitle("Topic Name"), replyList, topic, &Forum{ID: 1, Name: "Hahaha"}, poll, Paginator{[]int{1}, 1, 1}}
|
||||
|
@ -271,7 +271,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
|||
// TODO: Do we want the UID on this to be 0?
|
||||
//avatar, microAvatar = BuildAvatar(0, "")
|
||||
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
|
||||
ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: "", URLPrefix: "", URLName: "", Level: 0, Attachments: miniAttach}
|
||||
ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: "", Level: 0, Attachments: miniAttach}
|
||||
ru.Init()
|
||||
replyList = append(replyList, ru)
|
||||
|
||||
|
@ -296,7 +296,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
|||
return err
|
||||
}
|
||||
|
||||
ppage := ProfilePage{htitle("User 526"), replyList, user, 0, 0, false,false,false} // TODO: Use the score from user to generate the currentScore and nextScore
|
||||
ppage := ProfilePage{htitle("User 526"), replyList, user, 0, 0, false, false, false} // TODO: Use the score from user to generate the currentScore and nextScore
|
||||
t.Add("profile", "c.ProfilePage", ppage)
|
||||
|
||||
var topicsList []*TopicsRow
|
||||
|
@ -307,8 +307,8 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
|||
forumPage := ForumPage{htitle("General Forum"), topicsList, forumItem, Paginator{[]int{1}, 1, 1}}
|
||||
|
||||
// Experimental!
|
||||
for _, tmpl := range strings.Split(Dev.ExtraTmpls,",") {
|
||||
sp := strings.Split(tmpl,":")
|
||||
for _, tmpl := range strings.Split(Dev.ExtraTmpls, ",") {
|
||||
sp := strings.Split(tmpl, ":")
|
||||
if len(sp) < 2 {
|
||||
continue
|
||||
}
|
||||
|
@ -350,27 +350,27 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
|||
t.AddStd("account", "c.Account", accountPage)
|
||||
|
||||
parti := []*User{&user}
|
||||
convo := &Conversation{1,user.ID,time.Now(),0,time.Now()}
|
||||
convoItems := []ConvoViewRow{ConvoViewRow{&ConversationPost{1,1,"hey","",user.ID}, &user, "", 4, true}}
|
||||
convo := &Conversation{1, user.ID, time.Now(), 0, time.Now()}
|
||||
convoItems := []ConvoViewRow{ConvoViewRow{&ConversationPost{1, 1, "hey", "", user.ID}, &user, "", 4, true}}
|
||||
convoPage := ConvoViewPage{header, convo, convoItems, parti, Paginator{[]int{1}, 1, 1}}
|
||||
t.AddStd("convo", "c.ConvoViewPage", convoPage)
|
||||
|
||||
convos := []*ConversationExtra{&ConversationExtra{&Conversation{},[]*User{&user}}}
|
||||
convos := []*ConversationExtra{&ConversationExtra{&Conversation{}, []*User{&user}}}
|
||||
convoListPage := ConvoListPage{header, convos, Paginator{[]int{1}, 1, 1}}
|
||||
t.AddStd("convos", "c.ConvoListPage", convoListPage)
|
||||
|
||||
basePage := &BasePanelPage{header, PanelStats{}, "dashboard", ReportForumID}
|
||||
t.AddStd("panel", "c.Panel", Panel{basePage, "panel_dashboard_right", "", "panel_dashboard", inter})
|
||||
ges := []GridElement{GridElement{"","", "", 1, "grid_istat", "", "", ""}}
|
||||
t.AddStd("panel_dashboard", "c.DashGrids", DashGrids{ges,ges})
|
||||
ges := []GridElement{GridElement{"", "", "", 1, "grid_istat", "", "", ""}}
|
||||
t.AddStd("panel_dashboard", "c.DashGrids", DashGrids{ges, ges})
|
||||
|
||||
goVersion := runtime.Version()
|
||||
dbVersion := qgen.Builder.DbVersion()
|
||||
var memStats runtime.MemStats
|
||||
runtime.ReadMemStats(&memStats)
|
||||
debugCache := DebugPageCache{1, 1, 1, 2, 2, 2, true}
|
||||
debugDatabase := DebugPageDatabase{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
|
||||
debugDisk := DebugPageDisk{1,1,1,1,1,1}
|
||||
debugDatabase := DebugPageDatabase{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||
debugDisk := DebugPageDisk{1, 1, 1, 1, 1, 1}
|
||||
dpage := PanelDebugPage{basePage, goVersion, dbVersion, "0s", 1, qgen.Builder.GetAdapter().GetName(), 1, 1, memStats, debugCache, debugDatabase, debugDisk}
|
||||
t.AddStd("panel_debug", "c.PanelDebugPage", dpage)
|
||||
//t.AddStd("panel_analytics", "c.PanelAnalytics", Panel{basePage, "panel_dashboard_right","panel_dashboard", inter})
|
||||
|
@ -456,13 +456,13 @@ func CompileJSTemplates() error {
|
|||
log.Printf("overriden: %+v\n", overriden)
|
||||
|
||||
config := tmpl.CTemplateConfig{
|
||||
Minify: Config.MinifyTemplates,
|
||||
Debug: Dev.DebugMode,
|
||||
SuperDebug: Dev.TemplateDebug,
|
||||
SkipHandles: true,
|
||||
Minify: Config.MinifyTemplates,
|
||||
Debug: Dev.DebugMode,
|
||||
SuperDebug: Dev.TemplateDebug,
|
||||
SkipHandles: true,
|
||||
SkipTmplPtrMap: true,
|
||||
SkipInitBlock: false,
|
||||
PackageName: "tmpl",
|
||||
SkipInitBlock: false,
|
||||
PackageName: "tmpl",
|
||||
}
|
||||
c := tmpl.NewCTemplateSet("js")
|
||||
c.SetConfig(config)
|
||||
|
@ -531,12 +531,12 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri
|
|||
}, VoteCount: 7}
|
||||
avatar, microAvatar := BuildAvatar(62, "")
|
||||
miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}}
|
||||
topic := TopicUser{1, "blah", "Blah", "Hey there!", 62, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "", "", "", "", "", 58, false, miniAttach, nil,false}
|
||||
topic := TopicUser{1, "blah", "Blah", "Hey there!", 62, false, false, now, now, 1, 1, 0, "", "127.0.0.1", 1, 0, 1, 0, "classname", poll.ID, "weird-data", BuildProfileURL("fake-user", 62), "Fake User", Config.DefaultGroup, avatar, microAvatar, 0, "","","", 58, false, miniAttach, nil, false}
|
||||
var replyList []*ReplyUser
|
||||
// TODO: Do we really want the UID here to be zero?
|
||||
avatar, microAvatar = BuildAvatar(0, "")
|
||||
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
|
||||
ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, URLPrefix: "", URLName: "", Level: 0, Attachments: miniAttach}
|
||||
ru := &ReplyUser{ClassName: "", Reply: reply, CreatedByName: "Alice", Avatar: avatar, Level: 0, Attachments: miniAttach}
|
||||
ru.Init()
|
||||
replyList = append(replyList, ru)
|
||||
|
||||
|
@ -554,11 +554,11 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri
|
|||
|
||||
t.AddStd("topic_c_edit_post", "c.TopicCEditPost", TopicCEditPost{ID: 0, Source: "", Ref: ""})
|
||||
t.AddStd("topic_c_attach_item", "c.TopicCAttachItem", TopicCAttachItem{ID: 1, ImgSrc: "", Path: "", FullPath: ""})
|
||||
t.AddStd("topic_c_poll_input", "c.TopicCPollInput", TopicCPollInput{Index:0})
|
||||
t.AddStd("topic_c_poll_input", "c.TopicCPollInput", TopicCPollInput{Index: 0})
|
||||
|
||||
parti := []*User{&user}
|
||||
convo := &Conversation{1,user.ID,time.Now(),0,time.Now()}
|
||||
convoItems := []ConvoViewRow{ConvoViewRow{&ConversationPost{1,1,"hey","",user.ID}, &user, "", 4, true}}
|
||||
convo := &Conversation{1, user.ID, time.Now(), 0, time.Now()}
|
||||
convoItems := []ConvoViewRow{ConvoViewRow{&ConversationPost{1, 1, "hey", "", user.ID}, &user, "", 4, true}}
|
||||
convoPage := ConvoViewPage{header, convo, convoItems, parti, Paginator{[]int{1}, 1, 1}}
|
||||
t.AddStd("convo", "c.ConvoViewPage", convoPage)
|
||||
|
||||
|
@ -825,7 +825,7 @@ func loadTemplates(t *template.Template, themeName string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
tFileMap := make(map[string]int)
|
||||
for index, path := range tFiles {
|
||||
path = strings.Replace(path, "\\", "/", -1)
|
||||
|
|
139
common/topic.go
139
common/topic.go
|
@ -11,7 +11,6 @@ import (
|
|||
"html"
|
||||
"html/template"
|
||||
|
||||
//"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -83,10 +82,10 @@ type TopicUser struct {
|
|||
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
|
||||
//URLPrefix string
|
||||
//URLName string
|
||||
Level int
|
||||
Liked bool
|
||||
|
||||
Attachments []*MiniAttachment
|
||||
Rids []int
|
||||
|
@ -215,7 +214,7 @@ func init() {
|
|||
t := "topics"
|
||||
topicStmts = TopicStmts{
|
||||
getRids: acc.Select("replies").Columns("rid").Where("tid = ?").Orderby("rid ASC").Limit("?,?").Prepare(),
|
||||
getReplies: acc.SimpleLeftJoin("replies AS r", "users AS u", "r.rid, r.content, r.createdBy, r.createdAt, r.lastEdit, r.lastEditBy, u.avatar, u.name, u.group, u.url_prefix, u.url_name, u.level, r.ipaddress, r.likeCount, r.attachCount, r.actionType", "r.createdBy = u.uid", "r.tid = ?", "r.rid ASC", "?,?"),
|
||||
getReplies: acc.SimpleLeftJoin("replies AS r", "users AS u", "r.rid, r.content, r.createdBy, r.createdAt, r.lastEdit, r.lastEditBy, u.avatar, u.name, u.group, u.level, r.ipaddress, r.likeCount, r.attachCount, r.actionType", "r.createdBy = u.uid", "r.tid = ?", "r.rid ASC", "?,?"),
|
||||
addReplies: acc.Update(t).Set("postCount = postCount + ?, lastReplyBy = ?, lastReplyAt = UTC_TIMESTAMP()").Where("tid = ?").Prepare(),
|
||||
updateLastReply: acc.Update(t).Set("lastReplyID = ?").Where("lastReplyID > ? AND tid = ?").Prepare(),
|
||||
lock: acc.Update(t).Set("is_closed = 1").Where("tid = ?").Prepare(),
|
||||
|
@ -233,7 +232,7 @@ func init() {
|
|||
setPoll: acc.Update(t).Set("poll = ?").Where("tid = ? AND poll = 0").Prepare(),
|
||||
createAction: acc.Insert("replies").Columns("tid, actionType, ipaddress, createdBy, createdAt, lastUpdated, content, parsed_content").Fields("?,?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),'',''").Prepare(),
|
||||
|
||||
getTopicUser: acc.SimpleLeftJoin("topics AS t", "users AS u", "t.title, t.content, t.createdBy, t.createdAt, t.lastReplyAt, t.lastReplyBy, t.lastReplyID, t.is_closed, t.sticky, t.parentID, t.ipaddress, t.views, t.postCount, t.likeCount, t.attachCount,t.poll, u.name, u.avatar, u.group, u.url_prefix, u.url_name, u.level", "t.createdBy = u.uid", "tid = ?", "", ""),
|
||||
getTopicUser: acc.SimpleLeftJoin("topics AS t", "users AS u", "t.title, t.content, t.createdBy, t.createdAt, t.lastReplyAt, t.lastReplyBy, t.lastReplyID, t.is_closed, t.sticky, t.parentID, t.ipaddress, t.views, t.postCount, t.likeCount, t.attachCount,t.poll, u.name, u.avatar, u.group, u.level", "t.createdBy = u.uid", "tid = ?", "", ""),
|
||||
getByReplyID: acc.SimpleLeftJoin("replies AS r", "topics AS t", "t.tid, t.title, t.content, t.createdBy, t.createdAt, t.is_closed, t.sticky, t.parentID, t.ipaddress, t.views, t.postCount, t.likeCount, t.poll, t.data", "r.tid = t.tid", "rid = ?", "", ""),
|
||||
}
|
||||
return acc.FirstError()
|
||||
|
@ -250,7 +249,7 @@ func (t *Topic) cacheRemove() {
|
|||
}
|
||||
|
||||
// TODO: Write a test for this
|
||||
func (t *Topic) AddReply(rid int, uid int) (err error) {
|
||||
func (t *Topic) AddReply(rid, uid int) (err error) {
|
||||
_, err = topicStmts.addReplies.Exec(1, uid, t.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -300,7 +299,7 @@ func (t *Topic) Unstick() (err error) {
|
|||
|
||||
// TODO: Test this
|
||||
// TODO: Use a transaction for this
|
||||
func (t *Topic) Like(score int, uid int) (err error) {
|
||||
func (t *Topic) Like(score, uid int) (err error) {
|
||||
var disp int // Unused
|
||||
err = topicStmts.hasLikedTopic.QueryRow(uid, t.ID).Scan(&disp)
|
||||
if err != nil && err != ErrNoRows {
|
||||
|
@ -308,12 +307,10 @@ func (t *Topic) Like(score int, uid int) (err error) {
|
|||
} else if err != ErrNoRows {
|
||||
return ErrAlreadyLiked
|
||||
}
|
||||
|
||||
_, err = topicStmts.createLike.Exec(score, t.ID, "topics", uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = topicStmts.addLikesToTopic.Exec(1, t.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -360,7 +357,7 @@ func (t *Topic) Delete() error {
|
|||
}
|
||||
|
||||
// TODO: Write tests for this
|
||||
func (t *Topic) Update(name string, content string) error {
|
||||
func (t *Topic) Update(name, content string) error {
|
||||
name = SanitiseSingleLine(html.UnescapeString(name))
|
||||
if name == "" {
|
||||
return ErrNoTitle
|
||||
|
@ -371,7 +368,7 @@ func (t *Topic) Update(name string, content string) error {
|
|||
}
|
||||
|
||||
content = PreparseMessage(html.UnescapeString(content))
|
||||
parsedContent := ParseMessage(content, t.ParentID, "forums")
|
||||
parsedContent := ParseMessage(content, t.ParentID, "forums", nil)
|
||||
_, err := topicStmts.edit.Exec(name, content, parsedContent, t.ID)
|
||||
t.cacheRemove()
|
||||
return err
|
||||
|
@ -404,7 +401,7 @@ func (t *Topic) CreateActionReply(action string, ip string, uid int) (err error)
|
|||
return err
|
||||
}
|
||||
|
||||
func GetRidsForTopic(tid int, offset int) (rids []int, err error) {
|
||||
func GetRidsForTopic(tid, offset int) (rids []int, err error) {
|
||||
rows, err := topicStmts.getRids.Query(tid, offset, Config.ItemsPerPage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -450,20 +447,16 @@ func (ru *ReplyUser) Init() error {
|
|||
|
||||
// We really shouldn't have inline HTML, we should do something about this...
|
||||
if ru.ActionType != "" {
|
||||
var action string
|
||||
aarr := strings.Split(ru.ActionType, "-")
|
||||
switch aarr[0] {
|
||||
action := aarr[0]
|
||||
switch action {
|
||||
case "lock":
|
||||
action = aarr[0]
|
||||
ru.ActionIcon = lockai
|
||||
case "unlock":
|
||||
action = aarr[0]
|
||||
ru.ActionIcon = unlockai
|
||||
case "stick":
|
||||
action = aarr[0]
|
||||
ru.ActionIcon = stickai
|
||||
case "unstick":
|
||||
action = aarr[0]
|
||||
ru.ActionIcon = unstickai
|
||||
case "move":
|
||||
if len(aarr) == 2 {
|
||||
|
@ -471,19 +464,15 @@ func (ru *ReplyUser) Init() error {
|
|||
forum, err := Forums.Get(fid)
|
||||
if err == nil {
|
||||
ru.ActionType = p.GetTmplPhrasef("topic.action_topic_move_dest", forum.Link, forum.Name, ru.UserLink, ru.CreatedByName)
|
||||
} else {
|
||||
action = aarr[0]
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
action = aarr[0]
|
||||
}
|
||||
default:
|
||||
// TODO: Only fire this off if a corresponding phrase for the ActionType doesn't exist? Or maybe have some sort of action registry?
|
||||
ru.ActionType = p.GetTmplPhrasef("topic.action_topic_default", ru.ActionType)
|
||||
return nil
|
||||
}
|
||||
if action != "" {
|
||||
ru.ActionType = p.GetTmplPhrasef("topic.action_topic_"+action, ru.UserLink, ru.CreatedByName)
|
||||
}
|
||||
ru.ActionType = p.GetTmplPhrasef("topic.action_topic_"+action, ru.UserLink, ru.CreatedByName)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -516,42 +505,52 @@ func (t *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUs
|
|||
ruser, err = ucache.Get(re.CreatedBy)
|
||||
}
|
||||
|
||||
// TODO: Factor the user fields out and embed a user struct instead
|
||||
var reply *ReplyUser
|
||||
hTbl := GetHookTable()
|
||||
if err == nil {
|
||||
//log.Print("reply cached serve")
|
||||
reply = &ReplyUser{ClassName: "", Reply: *re, CreatedByName: ruser.Name, Avatar: ruser.Avatar, URLPrefix: ruser.URLPrefix, URLName: ruser.URLName, Level: ruser.Level}
|
||||
|
||||
err := reply.Init()
|
||||
rf := func(r *ReplyUser) error {
|
||||
err := r.Init()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
reply.ContentHtml = ParseMessage(reply.Content, t.ParentID, "forums")
|
||||
// TODO: Do this more efficiently by avoiding the allocations entirely in ParseMessage, if there's nothing to do.
|
||||
if reply.ContentHtml == reply.Content {
|
||||
reply.ContentHtml = reply.Content
|
||||
return err
|
||||
}
|
||||
|
||||
if reply.ID == pFrag {
|
||||
ogdesc = reply.Content
|
||||
r.ContentHtml = ParseMessage(r.Content, t.ParentID, "forums", user.ParseSettings)
|
||||
// TODO: Do this more efficiently by avoiding the allocations entirely in ParseMessage, if there's nothing to do.
|
||||
if r.ContentHtml == r.Content {
|
||||
r.ContentHtml = r.Content
|
||||
}
|
||||
|
||||
// TODO: This doesn't work properly so pick the first one instead?
|
||||
if r.ID == pFrag {
|
||||
ogdesc = r.Content
|
||||
if len(ogdesc) > 200 {
|
||||
ogdesc = ogdesc[:197] + "..."
|
||||
}
|
||||
}
|
||||
|
||||
if reply.LikeCount > 0 && user.Liked > 0 {
|
||||
likedMap[reply.ID] = len(rlist)
|
||||
likedQueryList = append(likedQueryList, reply.ID)
|
||||
if r.LikeCount > 0 && user.Liked > 0 {
|
||||
likedMap[r.ID] = len(rlist)
|
||||
likedQueryList = append(likedQueryList, r.ID)
|
||||
}
|
||||
if user.Perms.EditReply && reply.AttachCount > 0 {
|
||||
attachMap[reply.ID] = len(rlist)
|
||||
attachQueryList = append(attachQueryList, reply.ID)
|
||||
if user.Perms.EditReply && r.AttachCount > 0 {
|
||||
attachMap[r.ID] = len(rlist)
|
||||
attachQueryList = append(attachQueryList, r.ID)
|
||||
}
|
||||
reply.Deletable = user.Perms.DeleteReply || reply.CreatedBy == user.ID
|
||||
r.Deletable = user.Perms.DeleteReply || r.CreatedBy == user.ID
|
||||
|
||||
hTbl.VhookNoRet("topic_reply_row_assign", &rlist, &reply)
|
||||
rlist = append(rlist, reply)
|
||||
hTbl.VhookNoRet("topic_reply_row_assign", &rlist, &r)
|
||||
// TODO: Use a pointer instead to make it easier to abstract this loop? What impact would this have on escape analysis?
|
||||
rlist = append(rlist, r)
|
||||
//log.Printf("r: %d-%d", r.ID, len(rlist)-1)
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: Factor the user fields out and embed a user struct instead
|
||||
if err == nil {
|
||||
//log.Print("reply cached serve")
|
||||
reply := &ReplyUser{ClassName: "", Reply: *re, CreatedByName: ruser.Name, Avatar: ruser.Avatar /*URLPrefix: ruser.URLPrefix, URLName: ruser.URLName, */, Level: ruser.Level}
|
||||
err = rf(reply)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
} else {
|
||||
rows, err := topicStmts.getReplies.Query(t.ID, offset, Config.ItemsPerPage)
|
||||
if err != nil {
|
||||
|
@ -560,39 +559,15 @@ func (t *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUs
|
|||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
reply = &ReplyUser{}
|
||||
err := rows.Scan(&reply.ID, &reply.Content, &reply.CreatedBy, &reply.CreatedAt, &reply.LastEdit, &reply.LastEditBy, &reply.Avatar, &reply.CreatedByName, &reply.Group, &reply.URLPrefix, &reply.URLName, &reply.Level, &reply.IP, &reply.LikeCount, &reply.AttachCount, &reply.ActionType)
|
||||
r := &ReplyUser{}
|
||||
err := rows.Scan(&r.ID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.Avatar, &r.CreatedByName, &r.Group /*&r.URLPrefix, &r.URLName,*/, &r.Level, &r.IP, &r.LikeCount, &r.AttachCount, &r.ActionType)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if err := reply.Init(); err != nil {
|
||||
err = rf(r)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
reply.ContentHtml = ParseMessage(reply.Content, t.ParentID, "forums")
|
||||
|
||||
// TODO: This doesn't work properly so pick the first one instead?
|
||||
if reply.ID == pFrag {
|
||||
ogdesc = reply.Content
|
||||
if len(ogdesc) > 200 {
|
||||
ogdesc = ogdesc[:197] + "..."
|
||||
}
|
||||
}
|
||||
|
||||
if reply.LikeCount > 0 && user.Liked > 0 {
|
||||
likedMap[reply.ID] = len(rlist)
|
||||
likedQueryList = append(likedQueryList, reply.ID)
|
||||
}
|
||||
if user.Perms.EditReply && reply.AttachCount > 0 {
|
||||
attachMap[reply.ID] = len(rlist)
|
||||
attachQueryList = append(attachQueryList, reply.ID)
|
||||
}
|
||||
reply.Deletable = user.Perms.DeleteReply || reply.CreatedBy == user.ID
|
||||
|
||||
hTbl.VhookNoRet("topic_reply_row_assign", &rlist, &reply)
|
||||
// TODO: Use a pointer instead to make it easier to abstract this loop? What impact would this have on escape analysis?
|
||||
rlist = append(rlist, reply)
|
||||
//log.Printf("r: %d-%d", reply.ID, len(rlist)-1)
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
|
@ -689,7 +664,7 @@ func GetTopicUser(user *User, tid int) (tu TopicUser, err error) {
|
|||
|
||||
tu = TopicUser{ID: tid}
|
||||
// TODO: This misses some important bits...
|
||||
err = topicStmts.getTopicUser.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.LastReplyAt, &tu.LastReplyBy, &tu.LastReplyID, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &tu.AttachCount, &tu.Poll, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||
err = topicStmts.getTopicUser.QueryRow(tid).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.LastReplyAt, &tu.LastReplyBy, &tu.LastReplyID, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &tu.AttachCount, &tu.Poll, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.Level)
|
||||
tu.Avatar, tu.MicroAvatar = BuildAvatar(tu.CreatedBy, tu.Avatar)
|
||||
tu.Link = BuildTopicURL(NameToSlug(tu.Title), tu.ID)
|
||||
tu.UserLink = BuildProfileURL(NameToSlug(tu.CreatedByName), tu.CreatedBy)
|
||||
|
@ -709,8 +684,8 @@ func copyTopicToTopicUser(t *Topic, u *User) (tu TopicUser) {
|
|||
tu.Group = u.Group
|
||||
tu.Avatar = u.Avatar
|
||||
tu.MicroAvatar = u.MicroAvatar
|
||||
tu.URLPrefix = u.URLPrefix
|
||||
tu.URLName = u.URLName
|
||||
//tu.URLPrefix = u.URLPrefix
|
||||
//tu.URLName = u.URLName
|
||||
tu.Level = u.Level
|
||||
|
||||
tu.ID = t.ID
|
||||
|
|
|
@ -29,7 +29,7 @@ type TopicStore interface {
|
|||
BypassGet(id int) (*Topic, error)
|
||||
BulkGetMap(ids []int) (list map[int]*Topic, err error)
|
||||
Exists(id int) bool
|
||||
Create(fid int, topicName string, content string, uid int, ipaddress string) (tid int, err error)
|
||||
Create(fid int, name string, content string, uid int, ip string) (tid int, err error)
|
||||
AddLastTopic(item *Topic, fid int) error // unimplemented
|
||||
Reload(id int) error // Too much SQL logic to move into TopicCache
|
||||
// TODO: Implement these two methods
|
||||
|
@ -197,22 +197,22 @@ func (s *DefaultTopicStore) Exists(id int) bool {
|
|||
return s.exists.QueryRow(id).Scan(&id) == nil
|
||||
}
|
||||
|
||||
func (s *DefaultTopicStore) Create(fid int, topicName string, content string, uid int, ip string) (tid int, err error) {
|
||||
if topicName == "" {
|
||||
func (s *DefaultTopicStore) Create(fid int, name string, content string, uid int, ip string) (tid int, err error) {
|
||||
if name == "" {
|
||||
return 0, ErrNoTitle
|
||||
}
|
||||
// ? This number might be a little screwy with Unicode, but it's the only consistent thing we have, as Unicode characters can be any number of bytes in theory?
|
||||
if len(topicName) > Config.MaxTopicTitleLength {
|
||||
if len(name) > Config.MaxTopicTitleLength {
|
||||
return 0, ErrLongTitle
|
||||
}
|
||||
|
||||
parsedContent := strings.TrimSpace(ParseMessage(content, fid, "forums"))
|
||||
parsedContent := strings.TrimSpace(ParseMessage(content, fid, "forums", nil))
|
||||
if parsedContent == "" {
|
||||
return 0, ErrNoBody
|
||||
}
|
||||
|
||||
// TODO: Move this statement into the topic store
|
||||
res, err := s.create.Exec(fid, topicName, content, parsedContent, uid, ip, WordCount(content), uid)
|
||||
res, err := s.create.Exec(fid, name, content, parsedContent, uid, ip, WordCount(content), uid)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
@ -46,16 +46,19 @@ type User struct {
|
|||
Avatar string
|
||||
MicroAvatar string
|
||||
Message string
|
||||
URLPrefix string // Move this to another table? Create a user lite?
|
||||
URLName string
|
||||
Tag string
|
||||
Level int
|
||||
Score int
|
||||
Posts int
|
||||
Liked int
|
||||
LastIP string // ! This part of the UserCache data might fall out of date
|
||||
LastAgent string // ! Temporary hack, don't use
|
||||
TempGroup int
|
||||
// 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
|
||||
LastIP string // ! This part of the UserCache data might fall out of date
|
||||
LastAgent string // ! Temporary hack, don't use
|
||||
TempGroup int
|
||||
|
||||
ParseSettings *ParseSettings
|
||||
}
|
||||
|
||||
func (u *User) WebSockets() *WsJSONUser {
|
||||
|
@ -119,7 +122,7 @@ type UserStmts struct {
|
|||
changeGroup *sql.Stmt
|
||||
delete *sql.Stmt
|
||||
setAvatar *sql.Stmt
|
||||
setUsername *sql.Stmt
|
||||
setName *sql.Stmt
|
||||
incTopics *sql.Stmt
|
||||
updateLevel *sql.Stmt
|
||||
update *sql.Stmt
|
||||
|
@ -131,8 +134,9 @@ type UserStmts struct {
|
|||
incMegaposts *sql.Stmt
|
||||
incLiked *sql.Stmt
|
||||
|
||||
decLiked *sql.Stmt
|
||||
updateLastIP *sql.Stmt
|
||||
decLiked *sql.Stmt
|
||||
updateLastIP *sql.Stmt
|
||||
updatePrivacy *sql.Stmt
|
||||
|
||||
setPassword *sql.Stmt
|
||||
|
||||
|
@ -143,27 +147,29 @@ var userStmts UserStmts
|
|||
|
||||
func init() {
|
||||
DbInits.Add(func(acc *qgen.Accumulator) error {
|
||||
w := "uid = ?"
|
||||
u := "users"
|
||||
w := "uid=?"
|
||||
userStmts = UserStmts{
|
||||
activate: acc.SimpleUpdate("users", "active = 1", w),
|
||||
changeGroup: acc.SimpleUpdate("users", "group = ?", w), // TODO: Implement user_count for users_groups here
|
||||
delete: acc.SimpleDelete("users", w),
|
||||
setAvatar: acc.Update("users").Set("avatar = ?").Where(w).Prepare(),
|
||||
setUsername: acc.Update("users").Set("name = ?").Where(w).Prepare(),
|
||||
incTopics: acc.SimpleUpdate("users", "topics = topics + ?", w),
|
||||
updateLevel: acc.SimpleUpdate("users", "level = ?", w),
|
||||
update: acc.Update("users").Set("name = ?, email = ?, group = ?").Where(w).Prepare(), // TODO: Implement user_count for users_groups on things which use this
|
||||
activate: acc.SimpleUpdate(u, "active=1", w),
|
||||
changeGroup: acc.SimpleUpdate(u, "group=?", w), // TODO: Implement user_count for users_groups here
|
||||
delete: acc.Delete(u).Where(w).Prepare(),
|
||||
setAvatar: acc.Update(u).Set("avatar=?").Where(w).Prepare(),
|
||||
setName: acc.Update(u).Set("name=?").Where(w).Prepare(),
|
||||
incTopics: acc.SimpleUpdate(u, "topics=topics+?", w),
|
||||
updateLevel: acc.SimpleUpdate(u, "level=?", w),
|
||||
update: acc.Update(u).Set("name=?,email=?,group=?").Where(w).Prepare(), // TODO: Implement user_count for users_groups on things which use this
|
||||
|
||||
incScore: acc.Update("users").Set("score = score + ?").Where(w).Prepare(),
|
||||
incPosts: acc.Update("users").Set("posts = posts + ?").Where(w).Prepare(),
|
||||
incBigposts: acc.Update("users").Set("posts = posts + ?, bigposts = bigposts + ?").Where(w).Prepare(),
|
||||
incMegaposts: acc.Update("users").Set("posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ?").Where(w).Prepare(),
|
||||
incLiked: acc.Update("users").Set("liked = liked + ?, lastLiked = UTC_TIMESTAMP()").Where(w).Prepare(),
|
||||
decLiked: acc.Update("users").Set("liked = liked - ?").Where(w).Prepare(),
|
||||
incScore: acc.Update(u).Set("score=score+?").Where(w).Prepare(),
|
||||
incPosts: acc.Update(u).Set("posts=posts+?").Where(w).Prepare(),
|
||||
incBigposts: acc.Update(u).Set("posts=posts+?,bigposts=bigposts+?").Where(w).Prepare(),
|
||||
incMegaposts: acc.Update(u).Set("posts=posts+?,bigposts=bigposts+?,megaposts=megaposts+?").Where(w).Prepare(),
|
||||
incLiked: acc.Update(u).Set("liked=liked+?,lastLiked=UTC_TIMESTAMP()").Where(w).Prepare(),
|
||||
decLiked: acc.Update(u).Set("liked=liked-?").Where(w).Prepare(),
|
||||
//recalcLastLiked: acc...
|
||||
updateLastIP: acc.SimpleUpdate("users", "last_ip = ?", w),
|
||||
updateLastIP: acc.SimpleUpdate(u, "last_ip=?", w),
|
||||
updatePrivacy: acc.Update(u).Set("enable_embeds=?").Where(w).Prepare(),
|
||||
|
||||
setPassword: acc.Update("users").Set("password = ?, salt = ?").Where(w).Prepare(),
|
||||
setPassword: acc.Update(u).Set("password=?,salt=?").Where(w).Prepare(),
|
||||
|
||||
scheduleAvatarResize: acc.Insert("users_avatar_queue").Columns("uid").Fields("?").Prepare(),
|
||||
}
|
||||
|
@ -204,7 +210,7 @@ func (u *User) deleteScheduleGroupTx(tx *sql.Tx) error {
|
|||
}
|
||||
|
||||
func (u *User) setTempGroupTx(tx *sql.Tx, tempGroup int) error {
|
||||
setTempGroupStmt, err := qgen.Builder.SimpleUpdateTx(tx, "users", "temp_group = ?", "uid = ?")
|
||||
setTempGroupStmt, err := qgen.Builder.SimpleUpdateTx(tx, "users", "temp_group=?", "uid=?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -304,7 +310,7 @@ func (u *User) bindStmt(stmt *sql.Stmt, params ...interface{}) (err error) {
|
|||
}
|
||||
|
||||
func (u *User) ChangeName(name string) (err error) {
|
||||
return u.bindStmt(userStmts.setUsername, name)
|
||||
return u.bindStmt(userStmts.setName, name)
|
||||
}
|
||||
|
||||
func (u *User) ChangeAvatar(avatar string) (err error) {
|
||||
|
@ -341,7 +347,15 @@ func (u *User) UpdateIP(host string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (u *User) Update(name string, email string, group int) (err error) {
|
||||
func (u *User) UpdatePrivacy(enableEmbeds int) error {
|
||||
_, err := userStmts.updatePrivacy.Exec(enableEmbeds, u.ID)
|
||||
if uc := Users.GetCache(); uc != nil {
|
||||
uc.Remove(u.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *User) Update(name, email string, group int) (err error) {
|
||||
return u.bindStmt(userStmts.update, name, email, group)
|
||||
}
|
||||
|
||||
|
@ -461,7 +475,7 @@ type GuestAvatar struct {
|
|||
Micro string
|
||||
}
|
||||
|
||||
func buildNoavatar(uid int, width int) string {
|
||||
func buildNoavatar(uid, width int) string {
|
||||
if !Config.DisableNoavatarRange {
|
||||
// TODO: Find a faster algorithm
|
||||
if uid > 50000 {
|
||||
|
@ -520,7 +534,6 @@ func wordsToScore(wcount int, topic bool) (score int) {
|
|||
} else {
|
||||
score = 1
|
||||
}
|
||||
|
||||
settings := SettingBox.Load().(SettingMap)
|
||||
if wcount >= settings["megapost_min_words"].(int) {
|
||||
score += 4
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"errors"
|
||||
"strconv"
|
||||
|
||||
"github.com/Azareal/Gosora/query_gen"
|
||||
qgen "github.com/Azareal/Gosora/query_gen"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
|
@ -20,11 +20,11 @@ type UserStore interface {
|
|||
Get(id int) (*User, error)
|
||||
GetByName(name string) (*User, error)
|
||||
Exists(id int) bool
|
||||
GetOffset(offset int, perPage int) (users []*User, err error)
|
||||
GetOffset(offset, perPage int) ([]*User, error)
|
||||
//BulkGet(ids []int) ([]*User, error)
|
||||
BulkGetMap(ids []int) (map[int]*User, error)
|
||||
BypassGet(id int) (*User, error)
|
||||
Create(username string, password string, email string, group int, active bool) (int, error)
|
||||
Create(name string, password string, email string, group int, active bool) (int, error)
|
||||
Reload(id int) error
|
||||
Count() int
|
||||
|
||||
|
@ -35,12 +35,12 @@ type UserStore interface {
|
|||
type DefaultUserStore struct {
|
||||
cache UserCache
|
||||
|
||||
get *sql.Stmt
|
||||
getByName *sql.Stmt
|
||||
getOffset *sql.Stmt
|
||||
exists *sql.Stmt
|
||||
register *sql.Stmt
|
||||
usernameExists *sql.Stmt
|
||||
get *sql.Stmt
|
||||
getByName *sql.Stmt
|
||||
getOffset *sql.Stmt
|
||||
exists *sql.Stmt
|
||||
register *sql.Stmt
|
||||
nameExists *sql.Stmt
|
||||
count *sql.Stmt
|
||||
}
|
||||
|
||||
|
@ -50,16 +50,17 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) {
|
|||
if cache == nil {
|
||||
cache = NewNullUserCache()
|
||||
}
|
||||
u := "users"
|
||||
// TODO: Add an admin version of registerStmt with more flexibility?
|
||||
return &DefaultUserStore{
|
||||
cache: cache,
|
||||
get: acc.SimpleSelect("users", "name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, posts, liked, last_ip, temp_group", "uid = ?", "", ""),
|
||||
getByName: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, posts, liked, last_ip, temp_group").Where("name = ?").Prepare(),
|
||||
getOffset: acc.Select("users").Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, url_prefix, url_name, level, score, posts, liked, last_ip, temp_group").Orderby("uid ASC").Limit("?,?").Prepare(),
|
||||
exists: acc.SimpleSelect("users", "uid", "uid = ?", "", ""),
|
||||
register: acc.Insert("users").Columns("name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt, lastLiked, oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here
|
||||
usernameExists: acc.SimpleSelect("users", "name", "name = ?", "", ""),
|
||||
count: acc.Count("users").Prepare(),
|
||||
cache: cache,
|
||||
get: acc.Select(u).Columns("name, group, active, is_super_admin, session, email, avatar, message, level, score, posts, liked, last_ip, temp_group, enable_embeds").Where("uid = ?").Prepare(),
|
||||
getByName: acc.Select(u).Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, level, score, posts, liked, last_ip, temp_group, enable_embeds").Where("name = ?").Prepare(),
|
||||
getOffset: acc.Select(u).Columns("uid, name, group, active, is_super_admin, session, email, avatar, message, level, score, posts, liked, last_ip, temp_group, enable_embeds").Orderby("uid ASC").Limit("?,?").Prepare(),
|
||||
exists: acc.Exists(u, "uid").Prepare(),
|
||||
register: acc.Insert(u).Columns("name, email, password, salt, group, is_super_admin, session, active, message, createdAt, lastActiveAt, lastLiked, oldestItemLikedCreatedAt").Fields("?,?,?,?,?,0,'',?,'',UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP(),UTC_TIMESTAMP()").Prepare(), // TODO: Implement user_count on users_groups here
|
||||
nameExists: acc.Exists(u, "name").Prepare(),
|
||||
count: acc.Count(u).Prepare(),
|
||||
}, acc.FirstError()
|
||||
}
|
||||
|
||||
|
@ -86,8 +87,13 @@ func (s *DefaultUserStore) Get(id int) (*User, error) {
|
|||
//log.Print("uncached user")
|
||||
|
||||
u = &User{ID: id, Loggedin: true}
|
||||
err = s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts,&u.Liked, &u.LastIP, &u.TempGroup)
|
||||
var embeds int
|
||||
err = s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &embeds)
|
||||
if err == nil {
|
||||
if embeds != -1 {
|
||||
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||
u.ParseSettings.NoEmbed = embeds == 0
|
||||
}
|
||||
u.Init()
|
||||
s.cache.Set(u)
|
||||
}
|
||||
|
@ -98,8 +104,13 @@ func (s *DefaultUserStore) Get(id int) (*User, error) {
|
|||
// ! This bypasses the cache, use frugally
|
||||
func (s *DefaultUserStore) GetByName(name string) (*User, error) {
|
||||
u := &User{Loggedin: true}
|
||||
err := s.getByName.QueryRow(name).Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts,&u.Liked, &u.LastIP, &u.TempGroup)
|
||||
var embeds int
|
||||
err := s.getByName.QueryRow(name).Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &embeds)
|
||||
if err == nil {
|
||||
if embeds != -1 {
|
||||
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||
u.ParseSettings.NoEmbed = embeds == 0
|
||||
}
|
||||
u.Init()
|
||||
s.cache.Set(u)
|
||||
}
|
||||
|
@ -115,12 +126,17 @@ func (s *DefaultUserStore) GetOffset(offset int, perPage int) (users []*User, er
|
|||
}
|
||||
defer rows.Close()
|
||||
|
||||
var embeds int
|
||||
for rows.Next() {
|
||||
u := &User{Loggedin: true}
|
||||
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup)
|
||||
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &embeds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if embeds != -1 {
|
||||
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||
u.ParseSettings.NoEmbed = embeds == 0
|
||||
}
|
||||
u.Init()
|
||||
s.cache.Set(u)
|
||||
users = append(users, u)
|
||||
|
@ -164,31 +180,35 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error)
|
|||
|
||||
// TODO: Add a function for the q stuff
|
||||
var q string
|
||||
idList := make([]interface{},len(ids))
|
||||
idList := make([]interface{}, len(ids))
|
||||
for i, id := range ids {
|
||||
idList[i] = strconv.Itoa(id)
|
||||
q += "?,"
|
||||
}
|
||||
q = q[0 : len(q)-1]
|
||||
|
||||
rows, err := qgen.NewAcc().Select("users").Columns("uid,name,group,active,is_super_admin,session,email,avatar,message,url_prefix,url_name,level,score,posts,liked,last_ip,temp_group").Where("uid IN(" + q + ")").Query(idList...)
|
||||
rows, err := qgen.NewAcc().Select("users").Columns("uid,name,group,active,is_super_admin,session,email,avatar,message,level,score,posts,liked,last_ip,temp_group,enable_embeds").Where("uid IN(" + q + ")").Query(idList...)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var embeds int
|
||||
for rows.Next() {
|
||||
u := &User{Loggedin: true}
|
||||
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup)
|
||||
err := rows.Scan(&u.ID, &u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &embeds)
|
||||
if err != nil {
|
||||
return list, err
|
||||
}
|
||||
if embeds != -1 {
|
||||
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||
u.ParseSettings.NoEmbed = embeds == 0
|
||||
}
|
||||
u.Init()
|
||||
s.cache.Set(u)
|
||||
list[u.ID] = u
|
||||
}
|
||||
err = rows.Err()
|
||||
if err != nil {
|
||||
if err = rows.Err(); err != nil {
|
||||
return list, err
|
||||
}
|
||||
|
||||
|
@ -212,8 +232,13 @@ func (s *DefaultUserStore) BulkGetMap(ids []int) (list map[int]*User, err error)
|
|||
|
||||
func (s *DefaultUserStore) BypassGet(id int) (*User, error) {
|
||||
u := &User{ID: id, Loggedin: true}
|
||||
err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.URLPrefix, &u.URLName, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup)
|
||||
var embeds int
|
||||
err := s.get.QueryRow(id).Scan(&u.Name, &u.Group, &u.Active, &u.IsSuperAdmin, &u.Session, &u.Email, &u.RawAvatar, &u.Message, &u.Level, &u.Score, &u.Posts, &u.Liked, &u.LastIP, &u.TempGroup, &embeds)
|
||||
if err == nil {
|
||||
if embeds != -1 {
|
||||
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||
u.ParseSettings.NoEmbed = embeds == 0
|
||||
}
|
||||
u.Init()
|
||||
}
|
||||
return u, err
|
||||
|
@ -240,16 +265,16 @@ func (s *DefaultUserStore) Exists(id int) bool {
|
|||
|
||||
// TODO: Change active to a bool?
|
||||
// TODO: Use unique keys for the usernames
|
||||
func (s *DefaultUserStore) Create(username string, password string, email string, group int, active bool) (int, error) {
|
||||
func (s *DefaultUserStore) Create(name string, password string, email string, group int, active bool) (int, error) {
|
||||
// TODO: Strip spaces?
|
||||
|
||||
// ? This number might be a little screwy with Unicode, but it's the only consistent thing we have, as Unicode characters can be any number of bytes in theory?
|
||||
if len(username) > Config.MaxUsernameLength {
|
||||
if len(name) > Config.MaxUsernameLength {
|
||||
return 0, ErrLongUsername
|
||||
}
|
||||
|
||||
// Is this username already taken..?
|
||||
err := s.usernameExists.QueryRow(username).Scan(&username)
|
||||
// Is this name already taken..?
|
||||
err := s.nameExists.QueryRow(name).Scan(&name)
|
||||
if err != ErrNoRows {
|
||||
return 0, ErrAccountExists
|
||||
}
|
||||
|
@ -262,7 +287,7 @@ func (s *DefaultUserStore) Create(username string, password string, email string
|
|||
return 0, err
|
||||
}
|
||||
|
||||
res, err := s.register.Exec(username, email, string(hashedPassword), salt, group, active)
|
||||
res, err := s.register.Exec(name, email, string(hashedPassword), salt, group, active)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
|
|
@ -31,12 +31,12 @@ type Version struct {
|
|||
}
|
||||
|
||||
// TODO: Write a test for this
|
||||
func (version *Version) String() (out string) {
|
||||
out = strconv.Itoa(version.Major) + "." + strconv.Itoa(version.Minor) + "." + strconv.Itoa(version.Patch)
|
||||
if version.Tag != "" {
|
||||
out += "-" + version.Tag
|
||||
if version.TagID != 0 {
|
||||
out += strconv.Itoa(version.TagID)
|
||||
func (ver *Version) String() (out string) {
|
||||
out = strconv.Itoa(ver.Major) + "." + strconv.Itoa(ver.Minor) + "." + strconv.Itoa(ver.Patch)
|
||||
if ver.Tag != "" {
|
||||
out += "-" + ver.Tag
|
||||
if ver.TagID != 0 {
|
||||
out += strconv.Itoa(ver.TagID)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -335,10 +335,10 @@ func HasSuspiciousEmail(email string) bool {
|
|||
return dotCount > 7 || shortBits > 2
|
||||
}
|
||||
|
||||
var weakPassStrings = []string{"test", "123","6969","password", "qwerty", "fuck", "love"}
|
||||
var weakPassStrings = []string{"test", "123", "6969", "password", "qwerty", "fuck", "love"}
|
||||
|
||||
// TODO: Write a test for this
|
||||
func WeakPassword(password string, username string, email string) error {
|
||||
func WeakPassword(password, username, email string) error {
|
||||
lowPassword := strings.ToLower(password)
|
||||
switch {
|
||||
case password == "":
|
||||
|
@ -422,7 +422,7 @@ func createFile(name string) error {
|
|||
}
|
||||
|
||||
// TODO: Write a test for this
|
||||
func writeFile(name string, content string) (err error) {
|
||||
func writeFile(name, content string) (err error) {
|
||||
f, err := os.Create(name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -110,6 +110,8 @@ RefNoTrack - This switch disables tracking the referrers of users who click from
|
|||
|
||||
RefNoRef - This switch makes it so that if a user clicks on a link, then the incoming site won't know which site they're coming from.
|
||||
|
||||
NoEmbed - Avoid expanding links into videos or images. Default: false
|
||||
|
||||
NoAvatar - The default avatar to use for users when they don't have their own. The default for this may change in the near future to better utilise HTTP/2. Example: https://api.adorable.io/avatars/{width}/{id}.png
|
||||
|
||||
ItemsPerPage - The number of posts, topics, etc. you want on each page.
|
||||
|
|
|
@ -373,7 +373,6 @@ func markdownSkipList(data string, index int) int {
|
|||
goto SkipListInnerLoop
|
||||
}
|
||||
}
|
||||
|
||||
if index >= datalen {
|
||||
if data[index] != '*' && data[index] != '-' {
|
||||
if (lastNewline + 1) < datalen {
|
||||
|
|
433
gen_router.go
433
gen_router.go
|
@ -121,6 +121,8 @@ var RouteMap = map[string]interface{}{
|
|||
"routes.AccountEditAvatarSubmit": routes.AccountEditAvatarSubmit,
|
||||
"routes.AccountEditRevokeAvatarSubmit": routes.AccountEditRevokeAvatarSubmit,
|
||||
"routes.AccountEditUsernameSubmit": routes.AccountEditUsernameSubmit,
|
||||
"routes.AccountEditPrivacy": routes.AccountEditPrivacy,
|
||||
"routes.AccountEditPrivacySubmit": routes.AccountEditPrivacySubmit,
|
||||
"routes.AccountEditMFA": routes.AccountEditMFA,
|
||||
"routes.AccountEditMFASetup": routes.AccountEditMFASetup,
|
||||
"routes.AccountEditMFASetupSubmit": routes.AccountEditMFASetupSubmit,
|
||||
|
@ -290,73 +292,75 @@ var routeMapEnum = map[string]int{
|
|||
"routes.AccountEditAvatarSubmit": 95,
|
||||
"routes.AccountEditRevokeAvatarSubmit": 96,
|
||||
"routes.AccountEditUsernameSubmit": 97,
|
||||
"routes.AccountEditMFA": 98,
|
||||
"routes.AccountEditMFASetup": 99,
|
||||
"routes.AccountEditMFASetupSubmit": 100,
|
||||
"routes.AccountEditMFADisableSubmit": 101,
|
||||
"routes.AccountEditEmail": 102,
|
||||
"routes.AccountEditEmailTokenSubmit": 103,
|
||||
"routes.AccountLogins": 104,
|
||||
"routes.AccountBlocked": 105,
|
||||
"routes.LevelList": 106,
|
||||
"routes.Convos": 107,
|
||||
"routes.ConvosCreate": 108,
|
||||
"routes.Convo": 109,
|
||||
"routes.ConvosCreateSubmit": 110,
|
||||
"routes.ConvosCreateReplySubmit": 111,
|
||||
"routes.ConvosDeleteReplySubmit": 112,
|
||||
"routes.ConvosEditReplySubmit": 113,
|
||||
"routes.RelationsBlockCreate": 114,
|
||||
"routes.RelationsBlockCreateSubmit": 115,
|
||||
"routes.RelationsBlockRemove": 116,
|
||||
"routes.RelationsBlockRemoveSubmit": 117,
|
||||
"routes.ViewProfile": 118,
|
||||
"routes.BanUserSubmit": 119,
|
||||
"routes.UnbanUser": 120,
|
||||
"routes.ActivateUser": 121,
|
||||
"routes.IPSearch": 122,
|
||||
"routes.CreateTopicSubmit": 123,
|
||||
"routes.EditTopicSubmit": 124,
|
||||
"routes.DeleteTopicSubmit": 125,
|
||||
"routes.StickTopicSubmit": 126,
|
||||
"routes.UnstickTopicSubmit": 127,
|
||||
"routes.LockTopicSubmit": 128,
|
||||
"routes.UnlockTopicSubmit": 129,
|
||||
"routes.MoveTopicSubmit": 130,
|
||||
"routes.LikeTopicSubmit": 131,
|
||||
"routes.AddAttachToTopicSubmit": 132,
|
||||
"routes.RemoveAttachFromTopicSubmit": 133,
|
||||
"routes.ViewTopic": 134,
|
||||
"routes.CreateReplySubmit": 135,
|
||||
"routes.ReplyEditSubmit": 136,
|
||||
"routes.ReplyDeleteSubmit": 137,
|
||||
"routes.ReplyLikeSubmit": 138,
|
||||
"routes.AddAttachToReplySubmit": 139,
|
||||
"routes.RemoveAttachFromReplySubmit": 140,
|
||||
"routes.ProfileReplyCreateSubmit": 141,
|
||||
"routes.ProfileReplyEditSubmit": 142,
|
||||
"routes.ProfileReplyDeleteSubmit": 143,
|
||||
"routes.PollVote": 144,
|
||||
"routes.PollResults": 145,
|
||||
"routes.AccountLogin": 146,
|
||||
"routes.AccountRegister": 147,
|
||||
"routes.AccountLogout": 148,
|
||||
"routes.AccountLoginSubmit": 149,
|
||||
"routes.AccountLoginMFAVerify": 150,
|
||||
"routes.AccountLoginMFAVerifySubmit": 151,
|
||||
"routes.AccountRegisterSubmit": 152,
|
||||
"routes.AccountPasswordReset": 153,
|
||||
"routes.AccountPasswordResetSubmit": 154,
|
||||
"routes.AccountPasswordResetToken": 155,
|
||||
"routes.AccountPasswordResetTokenSubmit": 156,
|
||||
"routes.DynamicRoute": 157,
|
||||
"routes.UploadedFile": 158,
|
||||
"routes.StaticFile": 159,
|
||||
"routes.RobotsTxt": 160,
|
||||
"routes.SitemapXml": 161,
|
||||
"routes.OpenSearchXml": 162,
|
||||
"routes.BadRoute": 163,
|
||||
"routes.HTTPSRedirect": 164,
|
||||
"routes.AccountEditPrivacy": 98,
|
||||
"routes.AccountEditPrivacySubmit": 99,
|
||||
"routes.AccountEditMFA": 100,
|
||||
"routes.AccountEditMFASetup": 101,
|
||||
"routes.AccountEditMFASetupSubmit": 102,
|
||||
"routes.AccountEditMFADisableSubmit": 103,
|
||||
"routes.AccountEditEmail": 104,
|
||||
"routes.AccountEditEmailTokenSubmit": 105,
|
||||
"routes.AccountLogins": 106,
|
||||
"routes.AccountBlocked": 107,
|
||||
"routes.LevelList": 108,
|
||||
"routes.Convos": 109,
|
||||
"routes.ConvosCreate": 110,
|
||||
"routes.Convo": 111,
|
||||
"routes.ConvosCreateSubmit": 112,
|
||||
"routes.ConvosCreateReplySubmit": 113,
|
||||
"routes.ConvosDeleteReplySubmit": 114,
|
||||
"routes.ConvosEditReplySubmit": 115,
|
||||
"routes.RelationsBlockCreate": 116,
|
||||
"routes.RelationsBlockCreateSubmit": 117,
|
||||
"routes.RelationsBlockRemove": 118,
|
||||
"routes.RelationsBlockRemoveSubmit": 119,
|
||||
"routes.ViewProfile": 120,
|
||||
"routes.BanUserSubmit": 121,
|
||||
"routes.UnbanUser": 122,
|
||||
"routes.ActivateUser": 123,
|
||||
"routes.IPSearch": 124,
|
||||
"routes.CreateTopicSubmit": 125,
|
||||
"routes.EditTopicSubmit": 126,
|
||||
"routes.DeleteTopicSubmit": 127,
|
||||
"routes.StickTopicSubmit": 128,
|
||||
"routes.UnstickTopicSubmit": 129,
|
||||
"routes.LockTopicSubmit": 130,
|
||||
"routes.UnlockTopicSubmit": 131,
|
||||
"routes.MoveTopicSubmit": 132,
|
||||
"routes.LikeTopicSubmit": 133,
|
||||
"routes.AddAttachToTopicSubmit": 134,
|
||||
"routes.RemoveAttachFromTopicSubmit": 135,
|
||||
"routes.ViewTopic": 136,
|
||||
"routes.CreateReplySubmit": 137,
|
||||
"routes.ReplyEditSubmit": 138,
|
||||
"routes.ReplyDeleteSubmit": 139,
|
||||
"routes.ReplyLikeSubmit": 140,
|
||||
"routes.AddAttachToReplySubmit": 141,
|
||||
"routes.RemoveAttachFromReplySubmit": 142,
|
||||
"routes.ProfileReplyCreateSubmit": 143,
|
||||
"routes.ProfileReplyEditSubmit": 144,
|
||||
"routes.ProfileReplyDeleteSubmit": 145,
|
||||
"routes.PollVote": 146,
|
||||
"routes.PollResults": 147,
|
||||
"routes.AccountLogin": 148,
|
||||
"routes.AccountRegister": 149,
|
||||
"routes.AccountLogout": 150,
|
||||
"routes.AccountLoginSubmit": 151,
|
||||
"routes.AccountLoginMFAVerify": 152,
|
||||
"routes.AccountLoginMFAVerifySubmit": 153,
|
||||
"routes.AccountRegisterSubmit": 154,
|
||||
"routes.AccountPasswordReset": 155,
|
||||
"routes.AccountPasswordResetSubmit": 156,
|
||||
"routes.AccountPasswordResetToken": 157,
|
||||
"routes.AccountPasswordResetTokenSubmit": 158,
|
||||
"routes.DynamicRoute": 159,
|
||||
"routes.UploadedFile": 160,
|
||||
"routes.StaticFile": 161,
|
||||
"routes.RobotsTxt": 162,
|
||||
"routes.SitemapXml": 163,
|
||||
"routes.OpenSearchXml": 164,
|
||||
"routes.BadRoute": 165,
|
||||
"routes.HTTPSRedirect": 166,
|
||||
}
|
||||
var reverseRouteMapEnum = map[int]string{
|
||||
0: "routes.Overview",
|
||||
|
@ -457,73 +461,75 @@ var reverseRouteMapEnum = map[int]string{
|
|||
95: "routes.AccountEditAvatarSubmit",
|
||||
96: "routes.AccountEditRevokeAvatarSubmit",
|
||||
97: "routes.AccountEditUsernameSubmit",
|
||||
98: "routes.AccountEditMFA",
|
||||
99: "routes.AccountEditMFASetup",
|
||||
100: "routes.AccountEditMFASetupSubmit",
|
||||
101: "routes.AccountEditMFADisableSubmit",
|
||||
102: "routes.AccountEditEmail",
|
||||
103: "routes.AccountEditEmailTokenSubmit",
|
||||
104: "routes.AccountLogins",
|
||||
105: "routes.AccountBlocked",
|
||||
106: "routes.LevelList",
|
||||
107: "routes.Convos",
|
||||
108: "routes.ConvosCreate",
|
||||
109: "routes.Convo",
|
||||
110: "routes.ConvosCreateSubmit",
|
||||
111: "routes.ConvosCreateReplySubmit",
|
||||
112: "routes.ConvosDeleteReplySubmit",
|
||||
113: "routes.ConvosEditReplySubmit",
|
||||
114: "routes.RelationsBlockCreate",
|
||||
115: "routes.RelationsBlockCreateSubmit",
|
||||
116: "routes.RelationsBlockRemove",
|
||||
117: "routes.RelationsBlockRemoveSubmit",
|
||||
118: "routes.ViewProfile",
|
||||
119: "routes.BanUserSubmit",
|
||||
120: "routes.UnbanUser",
|
||||
121: "routes.ActivateUser",
|
||||
122: "routes.IPSearch",
|
||||
123: "routes.CreateTopicSubmit",
|
||||
124: "routes.EditTopicSubmit",
|
||||
125: "routes.DeleteTopicSubmit",
|
||||
126: "routes.StickTopicSubmit",
|
||||
127: "routes.UnstickTopicSubmit",
|
||||
128: "routes.LockTopicSubmit",
|
||||
129: "routes.UnlockTopicSubmit",
|
||||
130: "routes.MoveTopicSubmit",
|
||||
131: "routes.LikeTopicSubmit",
|
||||
132: "routes.AddAttachToTopicSubmit",
|
||||
133: "routes.RemoveAttachFromTopicSubmit",
|
||||
134: "routes.ViewTopic",
|
||||
135: "routes.CreateReplySubmit",
|
||||
136: "routes.ReplyEditSubmit",
|
||||
137: "routes.ReplyDeleteSubmit",
|
||||
138: "routes.ReplyLikeSubmit",
|
||||
139: "routes.AddAttachToReplySubmit",
|
||||
140: "routes.RemoveAttachFromReplySubmit",
|
||||
141: "routes.ProfileReplyCreateSubmit",
|
||||
142: "routes.ProfileReplyEditSubmit",
|
||||
143: "routes.ProfileReplyDeleteSubmit",
|
||||
144: "routes.PollVote",
|
||||
145: "routes.PollResults",
|
||||
146: "routes.AccountLogin",
|
||||
147: "routes.AccountRegister",
|
||||
148: "routes.AccountLogout",
|
||||
149: "routes.AccountLoginSubmit",
|
||||
150: "routes.AccountLoginMFAVerify",
|
||||
151: "routes.AccountLoginMFAVerifySubmit",
|
||||
152: "routes.AccountRegisterSubmit",
|
||||
153: "routes.AccountPasswordReset",
|
||||
154: "routes.AccountPasswordResetSubmit",
|
||||
155: "routes.AccountPasswordResetToken",
|
||||
156: "routes.AccountPasswordResetTokenSubmit",
|
||||
157: "routes.DynamicRoute",
|
||||
158: "routes.UploadedFile",
|
||||
159: "routes.StaticFile",
|
||||
160: "routes.RobotsTxt",
|
||||
161: "routes.SitemapXml",
|
||||
162: "routes.OpenSearchXml",
|
||||
163: "routes.BadRoute",
|
||||
164: "routes.HTTPSRedirect",
|
||||
98: "routes.AccountEditPrivacy",
|
||||
99: "routes.AccountEditPrivacySubmit",
|
||||
100: "routes.AccountEditMFA",
|
||||
101: "routes.AccountEditMFASetup",
|
||||
102: "routes.AccountEditMFASetupSubmit",
|
||||
103: "routes.AccountEditMFADisableSubmit",
|
||||
104: "routes.AccountEditEmail",
|
||||
105: "routes.AccountEditEmailTokenSubmit",
|
||||
106: "routes.AccountLogins",
|
||||
107: "routes.AccountBlocked",
|
||||
108: "routes.LevelList",
|
||||
109: "routes.Convos",
|
||||
110: "routes.ConvosCreate",
|
||||
111: "routes.Convo",
|
||||
112: "routes.ConvosCreateSubmit",
|
||||
113: "routes.ConvosCreateReplySubmit",
|
||||
114: "routes.ConvosDeleteReplySubmit",
|
||||
115: "routes.ConvosEditReplySubmit",
|
||||
116: "routes.RelationsBlockCreate",
|
||||
117: "routes.RelationsBlockCreateSubmit",
|
||||
118: "routes.RelationsBlockRemove",
|
||||
119: "routes.RelationsBlockRemoveSubmit",
|
||||
120: "routes.ViewProfile",
|
||||
121: "routes.BanUserSubmit",
|
||||
122: "routes.UnbanUser",
|
||||
123: "routes.ActivateUser",
|
||||
124: "routes.IPSearch",
|
||||
125: "routes.CreateTopicSubmit",
|
||||
126: "routes.EditTopicSubmit",
|
||||
127: "routes.DeleteTopicSubmit",
|
||||
128: "routes.StickTopicSubmit",
|
||||
129: "routes.UnstickTopicSubmit",
|
||||
130: "routes.LockTopicSubmit",
|
||||
131: "routes.UnlockTopicSubmit",
|
||||
132: "routes.MoveTopicSubmit",
|
||||
133: "routes.LikeTopicSubmit",
|
||||
134: "routes.AddAttachToTopicSubmit",
|
||||
135: "routes.RemoveAttachFromTopicSubmit",
|
||||
136: "routes.ViewTopic",
|
||||
137: "routes.CreateReplySubmit",
|
||||
138: "routes.ReplyEditSubmit",
|
||||
139: "routes.ReplyDeleteSubmit",
|
||||
140: "routes.ReplyLikeSubmit",
|
||||
141: "routes.AddAttachToReplySubmit",
|
||||
142: "routes.RemoveAttachFromReplySubmit",
|
||||
143: "routes.ProfileReplyCreateSubmit",
|
||||
144: "routes.ProfileReplyEditSubmit",
|
||||
145: "routes.ProfileReplyDeleteSubmit",
|
||||
146: "routes.PollVote",
|
||||
147: "routes.PollResults",
|
||||
148: "routes.AccountLogin",
|
||||
149: "routes.AccountRegister",
|
||||
150: "routes.AccountLogout",
|
||||
151: "routes.AccountLoginSubmit",
|
||||
152: "routes.AccountLoginMFAVerify",
|
||||
153: "routes.AccountLoginMFAVerifySubmit",
|
||||
154: "routes.AccountRegisterSubmit",
|
||||
155: "routes.AccountPasswordReset",
|
||||
156: "routes.AccountPasswordResetSubmit",
|
||||
157: "routes.AccountPasswordResetToken",
|
||||
158: "routes.AccountPasswordResetTokenSubmit",
|
||||
159: "routes.DynamicRoute",
|
||||
160: "routes.UploadedFile",
|
||||
161: "routes.StaticFile",
|
||||
162: "routes.RobotsTxt",
|
||||
163: "routes.SitemapXml",
|
||||
164: "routes.OpenSearchXml",
|
||||
165: "routes.BadRoute",
|
||||
166: "routes.HTTPSRedirect",
|
||||
}
|
||||
var osMapEnum = map[string]int{
|
||||
"unknown": 0,
|
||||
|
@ -681,7 +687,7 @@ type HTTPSRedirect struct {}
|
|||
|
||||
func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set("Connection", "close")
|
||||
co.RouteViewCounter.Bump(164)
|
||||
co.RouteViewCounter.Bump(166)
|
||||
dest := "https://" + req.Host + req.URL.String()
|
||||
http.Redirect(w, req, dest, http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
@ -889,7 +895,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
co.GlobalViewCounter.Bump()
|
||||
|
||||
if prefix == "/s" { //old prefix: /static
|
||||
co.RouteViewCounter.Bump(159)
|
||||
co.RouteViewCounter.Bump(161)
|
||||
req.URL.Path += extraData
|
||||
routes.StaticFile(w, req)
|
||||
return
|
||||
|
@ -1800,7 +1806,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
|
||||
co.RouteViewCounter.Bump(97)
|
||||
err = routes.AccountEditUsernameSubmit(w,req,user)
|
||||
case "/user/edit/mfa/":
|
||||
case "/user/edit/privacy/":
|
||||
err = c.MemberOnly(w,req,user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1808,6 +1814,31 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
|
||||
co.RouteViewCounter.Bump(98)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = routes.AccountEditPrivacy(w,req,user,head)
|
||||
case "/user/edit/privacy/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = c.MemberOnly(w,req,user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(99)
|
||||
err = routes.AccountEditPrivacySubmit(w,req,user)
|
||||
case "/user/edit/mfa/":
|
||||
err = c.MemberOnly(w,req,user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(100)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1818,7 +1849,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(99)
|
||||
co.RouteViewCounter.Bump(101)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1835,7 +1866,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(100)
|
||||
co.RouteViewCounter.Bump(102)
|
||||
err = routes.AccountEditMFASetupSubmit(w,req,user)
|
||||
case "/user/edit/mfa/disable/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -1848,7 +1879,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(101)
|
||||
co.RouteViewCounter.Bump(103)
|
||||
err = routes.AccountEditMFADisableSubmit(w,req,user)
|
||||
case "/user/edit/email/":
|
||||
err = c.MemberOnly(w,req,user)
|
||||
|
@ -1856,14 +1887,14 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(102)
|
||||
co.RouteViewCounter.Bump(104)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = routes.AccountEditEmail(w,req,user,head)
|
||||
case "/user/edit/token/":
|
||||
co.RouteViewCounter.Bump(103)
|
||||
co.RouteViewCounter.Bump(105)
|
||||
err = routes.AccountEditEmailTokenSubmit(w,req,user,extraData)
|
||||
case "/user/edit/logins/":
|
||||
err = c.MemberOnly(w,req,user)
|
||||
|
@ -1871,7 +1902,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(104)
|
||||
co.RouteViewCounter.Bump(106)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1883,7 +1914,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(105)
|
||||
co.RouteViewCounter.Bump(107)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1895,7 +1926,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(106)
|
||||
co.RouteViewCounter.Bump(108)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1907,7 +1938,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(107)
|
||||
co.RouteViewCounter.Bump(109)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1919,7 +1950,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(108)
|
||||
co.RouteViewCounter.Bump(110)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1931,7 +1962,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(109)
|
||||
co.RouteViewCounter.Bump(111)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1948,7 +1979,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(110)
|
||||
co.RouteViewCounter.Bump(112)
|
||||
err = routes.ConvosCreateSubmit(w,req,user)
|
||||
case "/user/convo/create/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -1961,7 +1992,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(111)
|
||||
co.RouteViewCounter.Bump(113)
|
||||
err = routes.ConvosCreateReplySubmit(w,req,user,extraData)
|
||||
case "/user/convo/delete/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -1974,7 +2005,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(112)
|
||||
co.RouteViewCounter.Bump(114)
|
||||
err = routes.ConvosDeleteReplySubmit(w,req,user,extraData)
|
||||
case "/user/convo/edit/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -1987,7 +2018,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(113)
|
||||
co.RouteViewCounter.Bump(115)
|
||||
err = routes.ConvosEditReplySubmit(w,req,user,extraData)
|
||||
case "/user/block/create/":
|
||||
err = c.MemberOnly(w,req,user)
|
||||
|
@ -1995,7 +2026,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(114)
|
||||
co.RouteViewCounter.Bump(116)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2012,7 +2043,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(115)
|
||||
co.RouteViewCounter.Bump(117)
|
||||
err = routes.RelationsBlockCreateSubmit(w,req,user,extraData)
|
||||
case "/user/block/remove/":
|
||||
err = c.MemberOnly(w,req,user)
|
||||
|
@ -2020,7 +2051,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(116)
|
||||
co.RouteViewCounter.Bump(118)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2037,11 +2068,11 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(117)
|
||||
co.RouteViewCounter.Bump(119)
|
||||
err = routes.RelationsBlockRemoveSubmit(w,req,user,extraData)
|
||||
default:
|
||||
req.URL.Path += extraData
|
||||
co.RouteViewCounter.Bump(118)
|
||||
co.RouteViewCounter.Bump(120)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2061,7 +2092,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(119)
|
||||
co.RouteViewCounter.Bump(121)
|
||||
err = routes.BanUserSubmit(w,req,user,extraData)
|
||||
case "/users/unban/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2074,7 +2105,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(120)
|
||||
co.RouteViewCounter.Bump(122)
|
||||
err = routes.UnbanUser(w,req,user,extraData)
|
||||
case "/users/activate/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2087,7 +2118,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(121)
|
||||
co.RouteViewCounter.Bump(123)
|
||||
err = routes.ActivateUser(w,req,user,extraData)
|
||||
case "/users/ips/":
|
||||
err = c.MemberOnly(w,req,user)
|
||||
|
@ -2095,7 +2126,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(122)
|
||||
co.RouteViewCounter.Bump(124)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2119,7 +2150,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(123)
|
||||
co.RouteViewCounter.Bump(125)
|
||||
err = routes.CreateTopicSubmit(w,req,user)
|
||||
case "/topic/edit/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2132,7 +2163,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(124)
|
||||
co.RouteViewCounter.Bump(126)
|
||||
err = routes.EditTopicSubmit(w,req,user,extraData)
|
||||
case "/topic/delete/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2146,7 +2177,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
}
|
||||
|
||||
req.URL.Path += extraData
|
||||
co.RouteViewCounter.Bump(125)
|
||||
co.RouteViewCounter.Bump(127)
|
||||
err = routes.DeleteTopicSubmit(w,req,user)
|
||||
case "/topic/stick/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2159,7 +2190,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(126)
|
||||
co.RouteViewCounter.Bump(128)
|
||||
err = routes.StickTopicSubmit(w,req,user,extraData)
|
||||
case "/topic/unstick/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2172,7 +2203,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(127)
|
||||
co.RouteViewCounter.Bump(129)
|
||||
err = routes.UnstickTopicSubmit(w,req,user,extraData)
|
||||
case "/topic/lock/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2186,7 +2217,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
}
|
||||
|
||||
req.URL.Path += extraData
|
||||
co.RouteViewCounter.Bump(128)
|
||||
co.RouteViewCounter.Bump(130)
|
||||
err = routes.LockTopicSubmit(w,req,user)
|
||||
case "/topic/unlock/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2199,7 +2230,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(129)
|
||||
co.RouteViewCounter.Bump(131)
|
||||
err = routes.UnlockTopicSubmit(w,req,user,extraData)
|
||||
case "/topic/move/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2212,7 +2243,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(130)
|
||||
co.RouteViewCounter.Bump(132)
|
||||
err = routes.MoveTopicSubmit(w,req,user,extraData)
|
||||
case "/topic/like/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2225,7 +2256,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(131)
|
||||
co.RouteViewCounter.Bump(133)
|
||||
err = routes.LikeTopicSubmit(w,req,user,extraData)
|
||||
case "/topic/attach/add/submit/":
|
||||
err = c.MemberOnly(w,req,user)
|
||||
|
@ -2242,7 +2273,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(132)
|
||||
co.RouteViewCounter.Bump(134)
|
||||
err = routes.AddAttachToTopicSubmit(w,req,user,extraData)
|
||||
case "/topic/attach/remove/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2255,10 +2286,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(133)
|
||||
co.RouteViewCounter.Bump(135)
|
||||
err = routes.RemoveAttachFromTopicSubmit(w,req,user,extraData)
|
||||
default:
|
||||
co.RouteViewCounter.Bump(134)
|
||||
co.RouteViewCounter.Bump(136)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2282,7 +2313,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(135)
|
||||
co.RouteViewCounter.Bump(137)
|
||||
err = routes.CreateReplySubmit(w,req,user)
|
||||
case "/reply/edit/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2295,7 +2326,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(136)
|
||||
co.RouteViewCounter.Bump(138)
|
||||
err = routes.ReplyEditSubmit(w,req,user,extraData)
|
||||
case "/reply/delete/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2308,7 +2339,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(137)
|
||||
co.RouteViewCounter.Bump(139)
|
||||
err = routes.ReplyDeleteSubmit(w,req,user,extraData)
|
||||
case "/reply/like/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2321,7 +2352,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(138)
|
||||
co.RouteViewCounter.Bump(140)
|
||||
err = routes.ReplyLikeSubmit(w,req,user,extraData)
|
||||
case "/reply/attach/add/submit/":
|
||||
err = c.MemberOnly(w,req,user)
|
||||
|
@ -2338,7 +2369,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(139)
|
||||
co.RouteViewCounter.Bump(141)
|
||||
err = routes.AddAttachToReplySubmit(w,req,user,extraData)
|
||||
case "/reply/attach/remove/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2351,7 +2382,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(140)
|
||||
co.RouteViewCounter.Bump(142)
|
||||
err = routes.RemoveAttachFromReplySubmit(w,req,user,extraData)
|
||||
}
|
||||
case "/profile":
|
||||
|
@ -2367,7 +2398,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(141)
|
||||
co.RouteViewCounter.Bump(143)
|
||||
err = routes.ProfileReplyCreateSubmit(w,req,user)
|
||||
case "/profile/reply/edit/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2380,7 +2411,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(142)
|
||||
co.RouteViewCounter.Bump(144)
|
||||
err = routes.ProfileReplyEditSubmit(w,req,user,extraData)
|
||||
case "/profile/reply/delete/submit/":
|
||||
err = c.NoSessionMismatch(w,req,user)
|
||||
|
@ -2393,7 +2424,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(143)
|
||||
co.RouteViewCounter.Bump(145)
|
||||
err = routes.ProfileReplyDeleteSubmit(w,req,user,extraData)
|
||||
}
|
||||
case "/poll":
|
||||
|
@ -2409,23 +2440,23 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(144)
|
||||
co.RouteViewCounter.Bump(146)
|
||||
err = routes.PollVote(w,req,user,extraData)
|
||||
case "/poll/results/":
|
||||
co.RouteViewCounter.Bump(145)
|
||||
co.RouteViewCounter.Bump(147)
|
||||
err = routes.PollResults(w,req,user,extraData)
|
||||
}
|
||||
case "/accounts":
|
||||
switch(req.URL.Path) {
|
||||
case "/accounts/login/":
|
||||
co.RouteViewCounter.Bump(146)
|
||||
co.RouteViewCounter.Bump(148)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = routes.AccountLogin(w,req,user,head)
|
||||
case "/accounts/create/":
|
||||
co.RouteViewCounter.Bump(147)
|
||||
co.RouteViewCounter.Bump(149)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2442,7 +2473,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(148)
|
||||
co.RouteViewCounter.Bump(150)
|
||||
err = routes.AccountLogout(w,req,user)
|
||||
case "/accounts/login/submit/":
|
||||
err = c.ParseForm(w,req,user)
|
||||
|
@ -2450,10 +2481,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(149)
|
||||
co.RouteViewCounter.Bump(151)
|
||||
err = routes.AccountLoginSubmit(w,req,user)
|
||||
case "/accounts/mfa_verify/":
|
||||
co.RouteViewCounter.Bump(150)
|
||||
co.RouteViewCounter.Bump(152)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2465,7 +2496,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(151)
|
||||
co.RouteViewCounter.Bump(153)
|
||||
err = routes.AccountLoginMFAVerifySubmit(w,req,user)
|
||||
case "/accounts/create/submit/":
|
||||
err = c.ParseForm(w,req,user)
|
||||
|
@ -2473,10 +2504,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(152)
|
||||
co.RouteViewCounter.Bump(154)
|
||||
err = routes.AccountRegisterSubmit(w,req,user)
|
||||
case "/accounts/password-reset/":
|
||||
co.RouteViewCounter.Bump(153)
|
||||
co.RouteViewCounter.Bump(155)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2488,10 +2519,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(154)
|
||||
co.RouteViewCounter.Bump(156)
|
||||
err = routes.AccountPasswordResetSubmit(w,req,user)
|
||||
case "/accounts/password-reset/token/":
|
||||
co.RouteViewCounter.Bump(155)
|
||||
co.RouteViewCounter.Bump(157)
|
||||
head, err := c.UserCheck(w,req,&user)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -2503,7 +2534,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
return err
|
||||
}
|
||||
|
||||
co.RouteViewCounter.Bump(156)
|
||||
co.RouteViewCounter.Bump(158)
|
||||
err = routes.AccountPasswordResetTokenSubmit(w,req,user)
|
||||
}
|
||||
/*case "/sitemaps": // TODO: Count these views
|
||||
|
@ -2520,7 +2551,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
h.Del("Content-Type")
|
||||
h.Del("Content-Encoding")
|
||||
}
|
||||
co.RouteViewCounter.Bump(158)
|
||||
co.RouteViewCounter.Bump(160)
|
||||
req.URL.Path += extraData
|
||||
// TODO: Find a way to propagate errors up from this?
|
||||
r.UploadHandler(w,req) // TODO: Count these views
|
||||
|
@ -2530,7 +2561,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
// TODO: Add support for favicons and robots.txt files
|
||||
switch(extraData) {
|
||||
case "robots.txt":
|
||||
co.RouteViewCounter.Bump(160)
|
||||
co.RouteViewCounter.Bump(162)
|
||||
return routes.RobotsTxt(w,req)
|
||||
case "favicon.ico":
|
||||
gzw, ok := w.(c.GzipResponseWriter)
|
||||
|
@ -2544,10 +2575,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
routes.StaticFile(w,req)
|
||||
return nil
|
||||
case "opensearch.xml":
|
||||
co.RouteViewCounter.Bump(162)
|
||||
co.RouteViewCounter.Bump(164)
|
||||
return routes.OpenSearchXml(w,req)
|
||||
/*case "sitemap.xml":
|
||||
co.RouteViewCounter.Bump(161)
|
||||
co.RouteViewCounter.Bump(163)
|
||||
return routes.SitemapXml(w,req)*/
|
||||
}
|
||||
return c.NotFound(w,req,nil)
|
||||
|
@ -2558,7 +2589,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
r.RUnlock()
|
||||
|
||||
if ok {
|
||||
co.RouteViewCounter.Bump(157) // TODO: Be more specific about *which* dynamic route it is
|
||||
co.RouteViewCounter.Bump(159) // TODO: Be more specific about *which* dynamic route it is
|
||||
req.URL.Path += extraData
|
||||
return handle(w,req,user)
|
||||
}
|
||||
|
@ -2569,7 +2600,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
|||
} else {
|
||||
r.DumpRequest(req,"Bad Route")
|
||||
}
|
||||
co.RouteViewCounter.Bump(163)
|
||||
co.RouteViewCounter.Bump(165)
|
||||
return c.NotFound(w,req,nil)
|
||||
}
|
||||
return err
|
||||
|
|
|
@ -791,7 +791,7 @@ func BenchmarkQueryTopicParallel(b *testing.B) {
|
|||
b.RunParallel(func(pb *testing.PB) {
|
||||
var tu c.TopicUser
|
||||
for pb.Next() {
|
||||
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.views, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.views, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.ViewCount, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.Level)
|
||||
if err == ErrNoRows {
|
||||
log.Fatal("No rows found!")
|
||||
return
|
||||
|
@ -812,14 +812,14 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
|
|||
b.RunParallel(func(pb *testing.PB) {
|
||||
var tu c.TopicUser
|
||||
|
||||
getTopicUser, err := qgen.Builder.SimpleLeftJoin("topics", "users", "topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level", "topics.createdBy = users.uid", "tid = ?", "", "")
|
||||
getTopicUser, err := qgen.Builder.SimpleLeftJoin("topics", "users", "topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.level", "topics.createdBy = users.uid", "tid = ?", "", "")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
defer getTopicUser.Close()
|
||||
|
||||
for pb.Next() {
|
||||
err := getTopicUser.QueryRow(1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||
err := getTopicUser.QueryRow(1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.Level)
|
||||
if err == ErrNoRows {
|
||||
b.Fatal("No rows found!")
|
||||
return
|
||||
|
@ -873,7 +873,7 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
|||
var tu c.TopicUser
|
||||
b.Run("topic", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.url_prefix, users.url_name, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.URLPrefix, &tu.URLName, &tu.Level)
|
||||
err := db.QueryRow("select topics.title, topics.content, topics.createdBy, topics.createdAt, topics.is_closed, topics.sticky, topics.parentID, topics.ipaddress, topics.postCount, topics.likeCount, users.name, users.avatar, users.group, users.level from topics left join users ON topics.createdBy = users.uid where tid = ?", 1).Scan(&tu.Title, &tu.Content, &tu.CreatedBy, &tu.CreatedAt, &tu.IsClosed, &tu.Sticky, &tu.ParentID, &tu.IP, &tu.PostCount, &tu.LikeCount, &tu.CreatedByName, &tu.Avatar, &tu.Group, &tu.Level)
|
||||
if err == ErrNoRows {
|
||||
b.Fatal("No rows found!")
|
||||
return
|
||||
|
@ -885,7 +885,7 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
|||
})
|
||||
b.Run("topic_replies", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.is_super_admin, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress from replies left join users ON replies.createdBy = users.uid where tid = ?", 1)
|
||||
rows, err := db.Query("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.is_super_admin, users.group, users.level, replies.ipaddress from replies left join users ON replies.createdBy = users.uid where tid = ?", 1)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
return
|
||||
|
@ -907,13 +907,13 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
|||
var group int
|
||||
b.Run("topic_replies_scan", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
rows, err := db.Query("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.is_super_admin, users.group, users.url_prefix, users.url_name, users.level, replies.ipaddress from replies left join users ON replies.createdBy = users.uid where tid = ?", 1)
|
||||
rows, err := db.Query("select replies.rid, replies.content, replies.createdBy, replies.createdAt, replies.lastEdit, replies.lastEditBy, users.avatar, users.name, users.is_super_admin, users.group, users.level, replies.ipaddress from replies left join users ON replies.createdBy = users.uid where tid = ?", 1)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
return
|
||||
}
|
||||
for rows.Next() {
|
||||
err := rows.Scan(&r.ID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.Avatar, &r.CreatedByName, &isSuperAdmin, &group, &r.URLPrefix, &r.URLName, &r.Level, &r.IP)
|
||||
err := rows.Scan(&r.ID, &r.Content, &r.CreatedBy, &r.CreatedAt, &r.LastEdit, &r.LastEditBy, &r.Avatar, &r.CreatedByName, &isSuperAdmin, &group, &r.Level, &r.IP)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
return
|
||||
|
@ -933,36 +933,19 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
|||
// TODO: Take the attachment system into account in these parser benches
|
||||
func BenchmarkParserSerial(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.Run("empty_post", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.ParseMessage("", 0, "")
|
||||
f := func(name, msg string) func(b *testing.B) {
|
||||
return func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.ParseMessage(msg, 0, "", nil)
|
||||
}
|
||||
}
|
||||
})
|
||||
b.Run("short_post", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.ParseMessage("Hey everyone, how's it going?", 0, "")
|
||||
}
|
||||
})
|
||||
b.Run("one_smily", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.ParseMessage("Hey everyone, how's it going? :)", 0, "")
|
||||
}
|
||||
})
|
||||
b.Run("five_smilies", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.ParseMessage("Hey everyone, how's it going? :):):):):)", 0, "")
|
||||
}
|
||||
})
|
||||
b.Run("ten_smilies", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.ParseMessage("Hey everyone, how's it going? :):):):):):):):):):)", 0, "")
|
||||
}
|
||||
})
|
||||
b.Run("twenty_smilies", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.ParseMessage("Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)", 0, "")
|
||||
}
|
||||
})
|
||||
}
|
||||
f("empty_post","")
|
||||
f("short_post","Hey everyone, how's it going?")
|
||||
f("one_smily","Hey everyone, how's it going? :)")
|
||||
f("five_smilies","Hey everyone, how's it going? :):):):):)")
|
||||
f("ten_smilies","Hey everyone, how's it going? :):):):):):):):):):)")
|
||||
f("twenty_smilies","Hey everyone, how's it going? :):):):):):):):):):):):):):):):):):):):)")
|
||||
}
|
||||
|
||||
func BenchmarkBBCodePluginWithRegexpSerial(b *testing.B) {
|
||||
|
|
|
@ -293,7 +293,7 @@ func TestParser(t *testing.T) {
|
|||
|
||||
// TODO: Fix this hack and make the results a bit more reproducible, push the tests further in the process.
|
||||
for _, item := range l.Items {
|
||||
if res := c.ParseMessage(item.Msg, 1, "forums"); res != item.Expects {
|
||||
if res := c.ParseMessage(item.Msg, 1, "forums", nil); res != item.Expects {
|
||||
if item.Name != "" {
|
||||
t.Error("Name: ", item.Name)
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ func TestParser(t *testing.T) {
|
|||
l.Add("//"+c.Site.URL+"\n", "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a><br>")
|
||||
l.Add("//"+c.Site.URL+"\n//"+c.Site.URL, "<a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a><br><a href='https://"+c.Site.URL+"'>"+c.Site.URL+"</a>")
|
||||
for _, item := range l.Items {
|
||||
if res := c.ParseMessage(item.Msg, 1, "forums"); res != item.Expects {
|
||||
if res := c.ParseMessage(item.Msg, 1, "forums", nil); res != item.Expects {
|
||||
if item.Name != "" {
|
||||
t.Error("Name: ", item.Name)
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ func TestParser(t *testing.T) {
|
|||
}
|
||||
c.WriteURL(sb, c.BuildTopicURL("", tid), "#nnid-"+strconv.Itoa(tid))
|
||||
})
|
||||
res := c.ParseMessage("#nnid-1", 1, "forums")
|
||||
res := c.ParseMessage("#nnid-1", 1, "forums", nil)
|
||||
expect := "<a href='/topic/1'>#nnid-1</a>"
|
||||
if res != expect {
|
||||
t.Error("Bad output:", "'"+res+"'")
|
||||
|
@ -356,7 +356,7 @@ func TestParser(t *testing.T) {
|
|||
}
|
||||
c.WriteURL(sb, c.BuildTopicURL("", tid), "#longidnameneedtooverflowhack-"+strconv.Itoa(tid))
|
||||
})
|
||||
res = c.ParseMessage("#longidnameneedtooverflowhack-1", 1, "forums")
|
||||
res = c.ParseMessage("#longidnameneedtooverflowhack-1", 1, "forums", nil)
|
||||
expect = "<a href='/topic/1'>#longidnameneedtooverflowhack-1</a>"
|
||||
if res != expect {
|
||||
t.Error("Bad output:", "'"+res+"'")
|
||||
|
|
|
@ -42,6 +42,7 @@ func init() {
|
|||
addPatch(25, patch25)
|
||||
addPatch(26, patch26)
|
||||
addPatch(27, patch27)
|
||||
addPatch(28, patch28)
|
||||
}
|
||||
|
||||
func patch0(scanner *bufio.Scanner) (err error) {
|
||||
|
@ -745,3 +746,7 @@ func patch27(scanner *bufio.Scanner) error {
|
|||
}
|
||||
return execStmt(qgen.Builder.AddColumn("administration_logs", tC{"extra", "text", 0, false, false, ""}, nil))
|
||||
}
|
||||
|
||||
func patch28(scanner *bufio.Scanner) error {
|
||||
return execStmt(qgen.Builder.AddColumn("users", tC{"enable_embeds", "int", 0, false, false, "-1"}, nil))
|
||||
}
|
|
@ -56,6 +56,8 @@ func userRoutes() *RouteGroup {
|
|||
UploadAction("AvatarSubmit", "/avatar/submit/").MaxSizeVar("int(c.Config.MaxRequestSize)"),
|
||||
Action("RevokeAvatarSubmit", "/avatar/revoke/submit/"),
|
||||
Action("UsernameSubmit", "/username/submit/"), // TODO: Full test this
|
||||
MView("Privacy", "/privacy/"),
|
||||
Action("PrivacySubmit", "/privacy/submit/"),
|
||||
MView("MFA", "/mfa/"),
|
||||
MView("MFASetup", "/mfa/setup/"),
|
||||
Action("MFASetupSubmit", "/mfa/setup/submit/"),
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
|
||||
c "github.com/Azareal/Gosora/common"
|
||||
p "github.com/Azareal/Gosora/common/phrases"
|
||||
"github.com/Azareal/Gosora/query_gen"
|
||||
qgen "github.com/Azareal/Gosora/query_gen"
|
||||
)
|
||||
|
||||
// A blank list to fill out that parameter in Page for routes which don't use it
|
||||
|
@ -153,7 +153,7 @@ func AccountLoginMFAVerify(w http.ResponseWriter, r *http.Request, user c.User,
|
|||
if !mfaVerifySession(provSession, signedSession, uid) {
|
||||
return c.LocalError("Invalid session", w, r, user)
|
||||
}
|
||||
|
||||
|
||||
return renderTemplate("login_mfa_verify", w, r, h, c.Page{h, tList, nil})
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
|
|||
if isNumeric(nameBits[0]) {
|
||||
regError(p.GetErrorPhrase("register_first_word_numeric"), "numeric-name")
|
||||
}
|
||||
if strings.Contains(name,"http://") || strings.Contains(name,"https://") || strings.Contains(name,"ftp://") || strings.Contains(name,"ssh://") {
|
||||
if strings.Contains(name, "http://") || strings.Contains(name, "https://") || strings.Contains(name, "ftp://") || strings.Contains(name, "ssh://") {
|
||||
regError(p.GetErrorPhrase("register_url_username"), "url-name")
|
||||
}
|
||||
|
||||
|
@ -423,15 +423,15 @@ func AccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user c.User
|
|||
return c.NoPermissions(w, r, user)
|
||||
}
|
||||
|
||||
ext, ferr := c.UploadAvatar(w,r,user,user.ID)
|
||||
ext, ferr := c.UploadAvatar(w, r, user, user.ID)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
ferr = c.ChangeAvatar("." + ext, w, r, user)
|
||||
ferr = c.ChangeAvatar("."+ext, w, r, user)
|
||||
if ferr != nil {
|
||||
return ferr
|
||||
}
|
||||
|
||||
|
||||
// TODO: Only schedule a resize if the avatar isn't tiny
|
||||
err := user.ScheduleAvatarResize()
|
||||
if err != nil {
|
||||
|
@ -572,6 +572,37 @@ func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, user c.
|
|||
return nil
|
||||
}
|
||||
|
||||
func AccountEditPrivacy(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
|
||||
accountEditHead("account_privacy", w, r, &user, h)
|
||||
profileComments := false
|
||||
receiveConvos := false
|
||||
enableEmbeds := !c.DefaultParseSettings.NoEmbed
|
||||
if user.ParseSettings != nil {
|
||||
enableEmbeds = !user.ParseSettings.NoEmbed
|
||||
}
|
||||
pi := c.Account{h, "privacy", "account_own_edit_privacy", c.AccountPrivacyPage{h, profileComments, receiveConvos, enableEmbeds}}
|
||||
return renderTemplate("account", w, r, h, pi)
|
||||
}
|
||||
|
||||
func AccountEditPrivacySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||
//headerLite, _ := c.SimpleUserCheck(w, r, &user)
|
||||
|
||||
sEnableEmbeds := r.FormValue("enable_embeds")
|
||||
enableEmbeds, err := strconv.Atoi(sEnableEmbeds)
|
||||
if err != nil {
|
||||
return c.LocalError("enable_embeds must be 0 or 1", w, r, user)
|
||||
}
|
||||
if sEnableEmbeds != r.FormValue("o_enable_embeds") {
|
||||
err = (&user).UpdatePrivacy(enableEmbeds)
|
||||
if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "/user/edit/privacy/?updated=1", http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
||||
func AccountEditEmail(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
|
||||
accountEditHead("account_email", w, r, &user, h)
|
||||
emails, err := c.Emails.GetEmailsByUser(&user)
|
||||
|
@ -598,10 +629,9 @@ func AccountEditEmail(w http.ResponseWriter, r *http.Request, user c.User, h *c.
|
|||
|
||||
func AccountEditEmailAddSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||
email := r.PostFormValue("email")
|
||||
|
||||
_, err := c.Emails.Get(&user, email)
|
||||
if err == nil {
|
||||
return c.LocalError("You have already added this email.",w,r,user)
|
||||
return c.LocalError("You have already added this email.", w, r, user)
|
||||
} else if err != sql.ErrNoRows && err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
@ -615,7 +645,7 @@ func AccountEditEmailAddSubmit(w http.ResponseWriter, r *http.Request, user c.Us
|
|||
}
|
||||
err = c.Emails.Add(user.ID, email, token)
|
||||
if err != nil {
|
||||
return c.InternalError(err,w,r)
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
if c.Site.EnableEmails {
|
||||
err = c.SendValidationEmail(user.Name, email, token)
|
||||
|
@ -623,7 +653,7 @@ func AccountEditEmailAddSubmit(w http.ResponseWriter, r *http.Request, user c.Us
|
|||
return c.LocalError(p.GetErrorPhrase("register_email_fail"), w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
http.Redirect(w, r, "/user/edit/email/?added=1", http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
@ -635,19 +665,19 @@ func AccountEditEmailRemoveSubmit(w http.ResponseWriter, r *http.Request, user c
|
|||
// Quick and dirty check
|
||||
_, err := c.Emails.Get(&user, email)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("This email isn't set on this user.",w,r,user)
|
||||
return c.LocalError("This email isn't set on this user.", w, r, user)
|
||||
} else if err != nil {
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
if headerLite.Settings["activation_type"] == 2 && user.Email == email {
|
||||
return c.LocalError("You can't remove your primary email when mandatory email activation is enabled.",w,r,user)
|
||||
return c.LocalError("You can't remove your primary email when mandatory email activation is enabled.", w, r, user)
|
||||
}
|
||||
|
||||
err = c.Emails.Delete(user.ID, email)
|
||||
if err != nil {
|
||||
return c.InternalError(err,w,r)
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
|
||||
|
||||
http.Redirect(w, r, "/user/edit/email/?removed=1", http.StatusSeeOther)
|
||||
return nil
|
||||
}
|
||||
|
@ -729,13 +759,13 @@ func AccountBlocked(w http.ResponseWriter, r *http.Request, user c.User, h *c.He
|
|||
for _, uid := range uids {
|
||||
u, err := c.Users.Get(uid)
|
||||
if err != nil {
|
||||
return c.InternalError(err,w,r)
|
||||
return c.InternalError(err, w, r)
|
||||
}
|
||||
blocks = append(blocks, u)
|
||||
}
|
||||
|
||||
pageList := c.Paginate(page, lastPage, 5)
|
||||
pi := c.Account{h, "logins", "account_blocked", c.AccountBlocksPage{h, blocks, c.Paginator{pageList, page, lastPage}}}
|
||||
pi := c.Account{h, "blocked", "account_blocked", c.AccountBlocksPage{h, blocks, c.Paginator{pageList, page, lastPage}}}
|
||||
return renderTemplate("account", w, r, h, pi)
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ func ViewProfile(w http.ResponseWriter, r *http.Request, user c.User, header *c.
|
|||
|
||||
replyLiked := false
|
||||
replyLikeCount := 0
|
||||
ru := &c.ReplyUser{Reply: c.Reply{rid, puser.ID, replyContent, replyCreatedBy, replyGroup, replyCreatedAt, replyLastEdit, replyLastEditBy, 0, "", replyLiked, replyLikeCount, 0, ""}, ContentHtml: c.ParseMessage(replyContent, 0, ""), CreatedByName: replyCreatedByName, Avatar: replyAvatar, Level: 0}
|
||||
ru := &c.ReplyUser{Reply: c.Reply{rid, puser.ID, replyContent, replyCreatedBy, replyGroup, replyCreatedAt, replyLastEdit, replyLastEditBy, 0, "", replyLiked, replyLikeCount, 0, ""}, ContentHtml: c.ParseMessage(replyContent, 0, "", user.ParseSettings), CreatedByName: replyCreatedByName, Avatar: replyAvatar, Level: 0}
|
||||
ru.Init()
|
||||
|
||||
group, err := c.Groups.Get(ru.Group)
|
||||
|
|
|
@ -194,7 +194,7 @@ func CreateReplySubmit(w http.ResponseWriter, r *http.Request, user c.User) c.Ro
|
|||
|
||||
prid, _ := strconv.Atoi(r.FormValue("prid"))
|
||||
if js && (prid == 0 || rids[0] == prid) {
|
||||
outBytes, err := json.Marshal(JsonReply{c.ParseMessage(reply.Content, topic.ParentID, "forums")})
|
||||
outBytes, err := json.Marshal(JsonReply{c.ParseMessage(reply.Content, topic.ParentID, "forums", user.ParseSettings)})
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ func ReplyEditSubmit(w http.ResponseWriter, r *http.Request, user c.User, srid s
|
|||
if !js {
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(topic.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
||||
} else {
|
||||
outBytes, err := json.Marshal(JsonReply{c.ParseMessage(reply.Content, topic.ParentID, "forums")})
|
||||
outBytes, err := json.Marshal(JsonReply{c.ParseMessage(reply.Content, topic.ParentID, "forums", user.ParseSettings)})
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
|
|
@ -9,17 +9,17 @@ import (
|
|||
"io"
|
||||
|
||||
//"fmt"
|
||||
"golang.org/x/image/tiff"
|
||||
"image"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"image"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"golang.org/x/image/tiff"
|
||||
|
||||
c "github.com/Azareal/Gosora/common"
|
||||
"github.com/Azareal/Gosora/common/counters"
|
||||
|
@ -72,16 +72,17 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
|
|||
header.Path = c.BuildTopicURL(c.NameToSlug(topic.Title), topic.ID)
|
||||
|
||||
// TODO: Cache ContentHTML when possible?
|
||||
topic.ContentHTML = c.ParseMessage(topic.Content, topic.ParentID, "forums")
|
||||
topic.ContentHTML = c.ParseMessage(topic.Content, topic.ParentID, "forums", user.ParseSettings)
|
||||
// TODO: Do this more efficiently by avoiding the allocations entirely in ParseMessage, if there's nothing to do.
|
||||
if topic.ContentHTML == topic.Content {
|
||||
topic.ContentHTML = topic.Content
|
||||
}
|
||||
topic.ContentLines = strings.Count(topic.Content, "\n")
|
||||
|
||||
header.OGDesc = topic.Content
|
||||
if len(header.OGDesc) > 200 {
|
||||
header.OGDesc = header.OGDesc[:197] + "..."
|
||||
if len(topic.Content) > 200 {
|
||||
header.OGDesc = topic.Content[:197] + "..."
|
||||
} else {
|
||||
header.OGDesc = topic.Content
|
||||
}
|
||||
|
||||
postGroup, err := c.Groups.Get(topic.Group)
|
||||
|
@ -141,7 +142,6 @@ func ViewTopic(w http.ResponseWriter, r *http.Request, user c.User, header *c.He
|
|||
if strings.HasPrefix(r.URL.Fragment, "post-") {
|
||||
pFrag, _ = strconv.Atoi(strings.TrimPrefix(r.URL.Fragment, "post-"))
|
||||
}
|
||||
|
||||
rlist, ogdesc, err := topic.Replies(offset, pFrag, &user)
|
||||
if err == sql.ErrNoRows {
|
||||
return c.LocalError("Bad Page. Some of the posts may have been deleted or you got here by directly typing in the page number.", w, r, user)
|
||||
|
@ -510,7 +510,7 @@ func uploadFilesWithHash(w http.ResponseWriter, r *http.Request, user c.User, di
|
|||
} else {
|
||||
img, _, err := image.Decode(inFile)
|
||||
if err != nil {
|
||||
return nil, c.LocalError("Upload failed [Image Decoding Failed]",w,r,user)
|
||||
return nil, c.LocalError("Upload failed [Image Decoding Failed]", w, r, user)
|
||||
}
|
||||
|
||||
outFile, err := os.Create(dir + filename)
|
||||
|
@ -518,19 +518,19 @@ func uploadFilesWithHash(w http.ResponseWriter, r *http.Request, user c.User, di
|
|||
return nil, c.LocalError("Upload failed [File Creation Failed]", w, r, user)
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
|
||||
switch ext {
|
||||
case "gif":
|
||||
err = gif.Encode(outFile, img, nil)
|
||||
case "png":
|
||||
err = png.Encode(outFile, img)
|
||||
case "tiff","tif":
|
||||
err = tiff.Encode(outFile,img,nil)
|
||||
case "tiff", "tif":
|
||||
err = tiff.Encode(outFile, img, nil)
|
||||
default:
|
||||
err = jpeg.Encode(outFile, img, nil)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, c.LocalError("Upload failed [Image Encoding Failed]", w,r,user)
|
||||
return nil, c.LocalError("Upload failed [Image Encoding Failed]", w, r, user)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -603,7 +603,7 @@ func EditTopicSubmit(w http.ResponseWriter, r *http.Request, user c.User, stid s
|
|||
if !js {
|
||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||
} else {
|
||||
outBytes, err := json.Marshal(JsonReply{c.ParseMessage(topic.Content, topic.ParentID, "forums")})
|
||||
outBytes, err := json.Marshal(JsonReply{c.ParseMessage(topic.Content, topic.ParentID, "forums", user.ParseSettings)})
|
||||
if err != nil {
|
||||
return c.InternalErrorJSQ(err, w, r, js)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ CREATE TABLE [users] (
|
|||
[lastActiveAt] datetime not null,
|
||||
[session] nvarchar (200) DEFAULT '' not null,
|
||||
[last_ip] nvarchar (200) DEFAULT '0.0.0.0.0' not null,
|
||||
[enable_embeds] int DEFAULT -1 not null,
|
||||
[email] nvarchar (200) DEFAULT '' not null,
|
||||
[avatar] nvarchar (100) DEFAULT '' not null,
|
||||
[message] nvarchar (MAX) DEFAULT '' not null,
|
||||
|
|
|
@ -10,6 +10,7 @@ CREATE TABLE `users` (
|
|||
`lastActiveAt` datetime not null,
|
||||
`session` varchar(200) DEFAULT '' not null,
|
||||
`last_ip` varchar(200) DEFAULT '0.0.0.0.0' not null,
|
||||
`enable_embeds` int DEFAULT -1 not null,
|
||||
`email` varchar(200) DEFAULT '' not null,
|
||||
`avatar` varchar(100) DEFAULT '' not null,
|
||||
`message` text not null,
|
||||
|
|
|
@ -10,6 +10,7 @@ CREATE TABLE "users" (
|
|||
`lastActiveAt` timestamp not null,
|
||||
`session` varchar (200) DEFAULT '' not null,
|
||||
`last_ip` varchar (200) DEFAULT '0.0.0.0.0' not null,
|
||||
`enable_embeds` int DEFAULT -1 not null,
|
||||
`email` varchar (200) DEFAULT '' not null,
|
||||
`avatar` varchar (100) DEFAULT '' not null,
|
||||
`message` text DEFAULT '' not null,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<div class="colstack_item rowmenu">
|
||||
<div class="rowitem passive"><a href="/user/edit/password/">{{lang "account_menu_password"}}</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/email/">{{lang "account_menu_email"}}</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/privacy/">{{lang "account_menu_privacy"}}</a></div>
|
||||
<!--<div class="rowitem passive"><a href="/user/edit/notifications/">{{lang "account_menu_notifications"}}</a> <span class="account_soon">Coming Soon</span></div>-->
|
||||
<div class="rowitem passive"><a href="/user/edit/logins/">{{lang "account_menu_logins"}}</a></div>
|
||||
<div class="rowitem passive"><a href="/user/edit/blocked/">{{lang "account_menu_blocked"}}</a></div>
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<div class="colstack_item colstack_head rowhead">
|
||||
<div class="rowitem"><h1>{{lang "account_privacy_head"}}</h1></div>
|
||||
</div>
|
||||
<div class="colstack_item the_form">
|
||||
<form action="/user/edit/privacy/submit/?s={{.CurrentUser.Session}}" method="post">
|
||||
<!--<input name="o_profile_comments" value="{{if .ProfileComments}}1{{else}}0{{end}}" type="hidden" />
|
||||
<input name="o_receive_convos" value="{{if .ReceiveConvos}}1{{else}}0{{end}}" type="hidden" />-->
|
||||
<input name="o_enable_embeds" value="{{if .EnableEmbeds}}1{{else}}0{{end}}" type="hidden" />
|
||||
<!--<div class="formrow real_first_child">
|
||||
<div class="formitem formlabel">{{lang "account_privacy_profile_comments"}}</div>
|
||||
<div class="formitem"><select name="profile_comments">
|
||||
<option{{if .ProfileComments}} selected{{end}} value=1>{{lang "option_yes"}}</option>
|
||||
<option{{if not .ProfileComments}} selected{{end}} value=0>{{lang "option_no"}}</option>
|
||||
</select></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>Receive Conversations</a></div>
|
||||
<div class="formitem"><select name="receive_convos">
|
||||
<option{{if .ReceiveConvos}} selected{{end}} value=1>{{lang "option_yes"}}</option>
|
||||
<option{{if not .ReceiveConvos}} selected{{end}} value=0>{{lang "option_no"}}</option>
|
||||
</select></div>
|
||||
</div>-->
|
||||
<div class="formrow">
|
||||
<div class="formitem formlabel"><a>Enable Embeds</a></div>
|
||||
<div class="formitem"><select name="enable_embeds">
|
||||
<option{{if .EnableEmbeds}} selected{{end}} value=1>{{lang "option_yes"}}</option>
|
||||
<option{{if not .EnableEmbeds}} selected{{end}} value=0>{{lang "option_no"}}</option>
|
||||
</select></div>
|
||||
</div>
|
||||
<div class="formrow">
|
||||
<div class="formitem"><button name="account-button" class="formbutton form_middle_button">{{lang "account_privacy_button"}}</button></div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
Loading…
Reference in New Issue