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{"session", "varchar", 200, false, false, "''"},
|
||||||
//tC{"authToken", "varchar", 200, false, false, "''"},
|
//tC{"authToken", "varchar", 200, false, false, "''"},
|
||||||
tC{"last_ip", "varchar", 200, false, false, "0.0.0.0.0"},
|
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{"email", "varchar", 200, false, false, "''"},
|
||||||
tC{"avatar", "varchar", 100, false, false, "''"},
|
tC{"avatar", "varchar", 100, false, false, "''"},
|
||||||
tC{"message", "text", 0, false, false, "''"},
|
tC{"message", "text", 0, false, false, "''"},
|
||||||
|
|
||||||
|
// TODO: Drop these columns?
|
||||||
tC{"url_prefix", "varchar", 20, false, false, "''"},
|
tC{"url_prefix", "varchar", 20, false, false, "''"},
|
||||||
tC{"url_name", "varchar", 100, false, false, "''"},
|
tC{"url_name", "varchar", 100, false, false, "''"},
|
||||||
|
|
||||||
tC{"level", "smallint", 0, false, false, "0"},
|
tC{"level", "smallint", 0, false, false, "0"},
|
||||||
tC{"score", "int", 0, false, false, "0"},
|
tC{"score", "int", 0, false, false, "0"},
|
||||||
tC{"posts", "int", 0, false, false, "0"},
|
tC{"posts", "int", 0, false, false, "0"},
|
||||||
|
|
|
@ -248,6 +248,13 @@ type AccountBlocksPage struct {
|
||||||
Paginator
|
Paginator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccountPrivacyPage struct {
|
||||||
|
*Header
|
||||||
|
ProfileComments bool
|
||||||
|
ReceiveConvos bool
|
||||||
|
EnableEmbeds bool
|
||||||
|
}
|
||||||
|
|
||||||
type AccountDashPage struct {
|
type AccountDashPage struct {
|
||||||
*Header
|
*Header
|
||||||
MFASetup bool
|
MFASetup bool
|
||||||
|
|
|
@ -449,10 +449,26 @@ var hashLinkMap = map[string]func(*strings.Builder, string, *int){
|
||||||
// TODO: Forum Shortcode Link
|
// 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: Write a test for this
|
||||||
// TODO: We need a lot more hooks here. E.g. To add custom media types and handlers.
|
// 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?
|
// 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
|
// TODO: Word boundary detection for these to avoid mangling code
|
||||||
msg = strings.Replace(msg, ":)", "😀", -1)
|
msg = strings.Replace(msg, ":)", "😀", -1)
|
||||||
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--
|
i--
|
||||||
} else if msg[i] == 'h' || msg[i] == 'f' || msg[i] == 'g' || msg[i] == '/' {
|
} else if msg[i] == 'h' || msg[i] == 'f' || msg[i] == 'g' || msg[i] == '/' {
|
||||||
//fmt.Println("s3")
|
//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] == '/' {
|
if len(msg) > i+6 && msg[i+4] == 's' && msg[i+5] == ':' && msg[i+6] == '/' {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else if len(msg) > i+5 && msg[i+4] == ':' && msg[i+5] == '/' {
|
} else if msg[i+4] == ':' && msg[i+5] == '/' {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
|
@ -593,7 +609,7 @@ func ParseMessage(msg string, sectionID int, sectionType string /*, user User*/)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
media, ok := parseMediaString(msg[i : i+urlLen])
|
media, ok := parseMediaString(msg[i:i+urlLen], settings)
|
||||||
if !ok {
|
if !ok {
|
||||||
//fmt.Println("o3")
|
//fmt.Println("o3")
|
||||||
sb.Write(InvalidURL)
|
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.
|
// ? - 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++ {
|
for ; len(data) > i; i++ {
|
||||||
ch := data[i] // char
|
ch := data[i]
|
||||||
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 [
|
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
|
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.
|
// ? - 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++ {
|
for ; datalen > i; i++ {
|
||||||
ch := data[i] // char
|
ch := data[i]
|
||||||
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 [
|
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
|
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.
|
// ? - 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++ {
|
for ; end >= i; i++ {
|
||||||
ch := data[i] // char
|
ch := data[i]
|
||||||
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 [
|
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
|
end = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -796,7 +812,7 @@ func PartialURLStringLen(data string) (int, bool) {
|
||||||
if ch < 33 { // space and invisibles
|
if ch < 33 { // space and invisibles
|
||||||
//fmt.Println("e2:",i)
|
//fmt.Println("e2:",i)
|
||||||
return i, i != f
|
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)
|
//log.Print("Bad Character: ", ch)
|
||||||
//fmt.Println("e3")
|
//fmt.Println("e3")
|
||||||
return i, false
|
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.
|
// ? - 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++ {
|
for ; len(data) > i; i++ {
|
||||||
ch := data[i] //char
|
ch := data[i]
|
||||||
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 [
|
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)
|
//log.Print("Bad Character: ", ch)
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
@ -850,7 +866,7 @@ type MediaEmbed struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Write a test for this
|
// 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) {
|
if !validateURLString(data) {
|
||||||
return media, false
|
return media, false
|
||||||
}
|
}
|
||||||
|
@ -907,6 +923,7 @@ func parseMediaString(data string) (media MediaEmbed, ok bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !settings.NoEmbed {
|
||||||
// ? - I don't think this hostname will hit every YT domain
|
// ? - 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
|
// TODO: Make this a more customisable handler rather than hard-coding it in here
|
||||||
if strings.HasSuffix(host, ".youtube.com") && path == "/watch" {
|
if strings.HasSuffix(host, ".youtube.com") && path == "/watch" {
|
||||||
|
@ -934,6 +951,7 @@ func parseMediaString(data string) (media MediaEmbed, ok bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var sport string
|
var sport string
|
||||||
if port != "443" && port != "80" && port != "" {
|
if port != "443" && port != "80" && port != "" {
|
||||||
|
@ -947,8 +965,8 @@ func parseMediaString(data string) (media MediaEmbed, ok bool) {
|
||||||
if len(uurl.Fragment) > 0 {
|
if len(uurl.Fragment) > 0 {
|
||||||
frag = "#" + uurl.Fragment
|
frag = "#" + uurl.Fragment
|
||||||
}
|
}
|
||||||
media.URL = scheme + "//" + host + sport + path + q + frag
|
|
||||||
media.FURL = host + sport + path + q + frag
|
media.FURL = host + sport + path + q + frag
|
||||||
|
media.URL = scheme + "//" + media.FURL
|
||||||
|
|
||||||
return media, true
|
return media, true
|
||||||
}
|
}
|
||||||
|
@ -978,7 +996,7 @@ func CoerceIntString(data string) (res int, length int) {
|
||||||
|
|
||||||
// TODO: Write tests for this
|
// TODO: Write tests for this
|
||||||
// Make sure we reflect changes to this in the JS port in /public/global.js
|
// 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
|
diff := lastPage - currentPage
|
||||||
pre := 3
|
pre := 3
|
||||||
if diff < 3 {
|
if diff < 3 {
|
||||||
|
@ -998,7 +1016,7 @@ func Paginate(currentPage int, lastPage int, maxPages int) (out []int) {
|
||||||
|
|
||||||
// TODO: Write tests for this
|
// TODO: Write tests for this
|
||||||
// Make sure we reflect changes to this in the JS port in /public/global.js
|
// 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
|
var offset int
|
||||||
lastPage := LastPage(count, perPage)
|
lastPage := LastPage(count, perPage)
|
||||||
if page > 1 {
|
if page > 1 {
|
||||||
|
@ -1020,6 +1038,6 @@ func PageOffset(count int, page int, perPage int) (int, int, int) {
|
||||||
|
|
||||||
// TODO: Write tests for this
|
// TODO: Write tests for this
|
||||||
// Make sure we reflect changes to this in the JS port in /public/global.js
|
// 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
|
return (count / perPage) + 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"html"
|
"html"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Azareal/Gosora/query_gen"
|
qgen "github.com/Azareal/Gosora/query_gen"
|
||||||
)
|
)
|
||||||
|
|
||||||
var profileReplyStmts ProfileReplyStmts
|
var profileReplyStmts ProfileReplyStmts
|
||||||
|
@ -30,9 +30,10 @@ type ProfileReplyStmts struct {
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
DbInits.Add(func(acc *qgen.Accumulator) error {
|
DbInits.Add(func(acc *qgen.Accumulator) error {
|
||||||
|
ur := "users_replies"
|
||||||
profileReplyStmts = ProfileReplyStmts{
|
profileReplyStmts = ProfileReplyStmts{
|
||||||
edit: acc.Update("users_replies").Set("content = ?, parsed_content = ?").Where("rid = ?").Prepare(),
|
edit: acc.Update(ur).Set("content = ?, parsed_content = ?").Where("rid = ?").Prepare(),
|
||||||
delete: acc.Delete("users_replies").Where("rid = ?").Prepare(),
|
delete: acc.Delete(ur).Where("rid = ?").Prepare(),
|
||||||
}
|
}
|
||||||
return acc.FirstError()
|
return acc.FirstError()
|
||||||
})
|
})
|
||||||
|
@ -51,7 +52,7 @@ func (r *ProfileReply) Delete() error {
|
||||||
|
|
||||||
func (r *ProfileReply) SetBody(content string) error {
|
func (r *ProfileReply) SetBody(content string) error {
|
||||||
content = PreparseMessage(html.UnescapeString(content))
|
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
|
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) {
|
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 {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,31 +17,18 @@ import (
|
||||||
|
|
||||||
type ReplyUser struct {
|
type ReplyUser struct {
|
||||||
Reply
|
Reply
|
||||||
//ID int
|
|
||||||
//ParentID int
|
|
||||||
//Content string
|
|
||||||
ContentHtml string
|
ContentHtml string
|
||||||
//CreatedBy int
|
|
||||||
UserLink string
|
UserLink string
|
||||||
CreatedByName string
|
CreatedByName string
|
||||||
//Group int
|
|
||||||
//CreatedAt time.Time
|
|
||||||
//LastEdit int
|
|
||||||
//LastEditBy int
|
|
||||||
Avatar string
|
Avatar string
|
||||||
MicroAvatar string
|
MicroAvatar string
|
||||||
ClassName string
|
ClassName string
|
||||||
//ContentLines int
|
|
||||||
Tag string
|
Tag string
|
||||||
URL string
|
URL string
|
||||||
URLPrefix string
|
//URLPrefix string
|
||||||
URLName string
|
//URLName string
|
||||||
Level int
|
Level int
|
||||||
//IP string
|
|
||||||
//Liked bool
|
|
||||||
//LikeCount int
|
|
||||||
//AttachCount int
|
|
||||||
//ActionType string
|
|
||||||
ActionIcon string
|
ActionIcon string
|
||||||
|
|
||||||
Attachments []*MiniAttachment
|
Attachments []*MiniAttachment
|
||||||
|
@ -139,7 +126,7 @@ func (r *Reply) SetPost(content string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
content = PreparseMessage(html.UnescapeString(content))
|
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
|
_, 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)
|
_ = Rstore.GetCache().Remove(r.ID)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -52,7 +52,7 @@ func (s *SQLReplyStore) Get(id int) (*Reply, error) {
|
||||||
|
|
||||||
// TODO: Write a test for this
|
// TODO: Write a test for this
|
||||||
func (s *SQLReplyStore) Create(t *Topic, content string, ip string, uid int) (rid int, err error) {
|
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 {
|
if err != nil {
|
||||||
return 0, err
|
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
|
// ! 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
|
var count int
|
||||||
err = s.exists.QueryRow(itemType+"_"+strconv.Itoa(itemID), ReportForumID).Scan(&count)
|
err = s.exists.QueryRow(itemType+"_"+strconv.Itoa(itemID), ReportForumID).Scan(&count)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
|
@ -44,7 +44,7 @@ func (s *DefaultReportStore) Create(title string, content string, user *User, it
|
||||||
return 0, ErrAlreadyReported
|
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 {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -53,5 +53,6 @@ func (s *DefaultReportStore) Create(title string, content string, user *User, it
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
tid = int(lastID)
|
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
|
PrimaryServer bool
|
||||||
ServerCount int
|
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
|
PostIPCutoff int
|
||||||
LogPruneCutoff int
|
LogPruneCutoff int
|
||||||
|
|
||||||
|
@ -107,6 +108,7 @@ type config struct {
|
||||||
|
|
||||||
RefNoTrack bool
|
RefNoTrack bool
|
||||||
RefNoRef bool
|
RefNoRef bool
|
||||||
|
NoEmbed bool
|
||||||
|
|
||||||
Noavatar string // ? - Move this into the settings table?
|
Noavatar string // ? - Move this into the settings table?
|
||||||
ItemsPerPage int // ? - 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) {
|
func ProcessConfig() (err error) {
|
||||||
Config.Noavatar = strings.Replace(Config.Noavatar, "{site_url}", Site.URL, -1)
|
Config.Noavatar = strings.Replace(Config.Noavatar, "{site_url}", Site.URL, -1)
|
||||||
guestAvatar = GuestAvatar{buildNoavatar(0, 200), buildNoavatar(0, 48)}
|
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.Host = Site.URL
|
||||||
Site.LocalHost = Site.Host == "localhost" || Site.Host == "127.0.0.1" || Site.Host == "::1"
|
Site.LocalHost = Site.Host == "localhost" || Site.Host == "127.0.0.1" || Site.Host == "::1"
|
||||||
Site.PortInt, err = strconv.Atoi(Site.Port)
|
Site.PortInt, err = strconv.Atoi(Site.Port)
|
||||||
|
@ -216,6 +222,9 @@ func ProcessConfig() (err error) {
|
||||||
if Config.LogPruneCutoff == 0 {
|
if Config.LogPruneCutoff == 0 {
|
||||||
Config.LogPruneCutoff = 365 // Default cutoff
|
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
|
// ? Find a way of making these unlimited if zero? It might rule out some optimisations, waste memory, and break layouts
|
||||||
if Config.MaxTopicTitleLength == 0 {
|
if Config.MaxTopicTitleLength == 0 {
|
||||||
|
@ -240,20 +249,18 @@ func ProcessConfig() (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyConfig() error {
|
func VerifyConfig() (err error) {
|
||||||
if !Forums.Exists(Config.DefaultForum) {
|
switch {
|
||||||
return errors.New("Invalid default forum")
|
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 err
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func SwitchToTestDB() {
|
func SwitchToTestDB() {
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
|
|
||||||
"github.com/Azareal/Gosora/common/alerts"
|
"github.com/Azareal/Gosora/common/alerts"
|
||||||
p "github.com/Azareal/Gosora/common/phrases"
|
p "github.com/Azareal/Gosora/common/phrases"
|
||||||
"github.com/Azareal/Gosora/common/templates"
|
tmpl "github.com/Azareal/Gosora/common/templates"
|
||||||
"github.com/Azareal/Gosora/query_gen"
|
qgen "github.com/Azareal/Gosora/query_gen"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Ctemplates []string // TODO: Use this to filter out top level templates we don't need
|
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) {
|
func tmplInitUsers() (User, User, User) {
|
||||||
avatar, microAvatar := BuildAvatar(62, "")
|
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?
|
// TODO: Do a more accurate level calculation for this?
|
||||||
avatar, microAvatar = BuildAvatar(1, "")
|
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, "")
|
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
|
return user, user2, user3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,11 +239,11 @@ func compileCommons(c *tmpl.CTemplateSet, head *Header, head2 *Header, forumList
|
||||||
}, VoteCount: 7}
|
}, VoteCount: 7}
|
||||||
avatar, microAvatar := BuildAvatar(62, "")
|
avatar, microAvatar := BuildAvatar(62, "")
|
||||||
miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}}
|
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
|
var replyList []*ReplyUser
|
||||||
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
|
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()
|
ru.Init()
|
||||||
replyList = append(replyList, ru)
|
replyList = append(replyList, ru)
|
||||||
tpage := TopicPage{htitle("Topic Name"), replyList, topic, &Forum{ID: 1, Name: "Hahaha"}, poll, Paginator{[]int{1}, 1, 1}}
|
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?
|
// TODO: Do we want the UID on this to be 0?
|
||||||
//avatar, microAvatar = BuildAvatar(0, "")
|
//avatar, microAvatar = BuildAvatar(0, "")
|
||||||
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
|
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()
|
ru.Init()
|
||||||
replyList = append(replyList, ru)
|
replyList = append(replyList, ru)
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
||||||
return err
|
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)
|
t.Add("profile", "c.ProfilePage", ppage)
|
||||||
|
|
||||||
var topicsList []*TopicsRow
|
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}}
|
forumPage := ForumPage{htitle("General Forum"), topicsList, forumItem, Paginator{[]int{1}, 1, 1}}
|
||||||
|
|
||||||
// Experimental!
|
// Experimental!
|
||||||
for _, tmpl := range strings.Split(Dev.ExtraTmpls,",") {
|
for _, tmpl := range strings.Split(Dev.ExtraTmpls, ",") {
|
||||||
sp := strings.Split(tmpl,":")
|
sp := strings.Split(tmpl, ":")
|
||||||
if len(sp) < 2 {
|
if len(sp) < 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -350,27 +350,27 @@ func compileTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName string
|
||||||
t.AddStd("account", "c.Account", accountPage)
|
t.AddStd("account", "c.Account", accountPage)
|
||||||
|
|
||||||
parti := []*User{&user}
|
parti := []*User{&user}
|
||||||
convo := &Conversation{1,user.ID,time.Now(),0,time.Now()}
|
convo := &Conversation{1, user.ID, time.Now(), 0, time.Now()}
|
||||||
convoItems := []ConvoViewRow{ConvoViewRow{&ConversationPost{1,1,"hey","",user.ID}, &user, "", 4, true}}
|
convoItems := []ConvoViewRow{ConvoViewRow{&ConversationPost{1, 1, "hey", "", user.ID}, &user, "", 4, true}}
|
||||||
convoPage := ConvoViewPage{header, convo, convoItems, parti, Paginator{[]int{1}, 1, 1}}
|
convoPage := ConvoViewPage{header, convo, convoItems, parti, Paginator{[]int{1}, 1, 1}}
|
||||||
t.AddStd("convo", "c.ConvoViewPage", convoPage)
|
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}}
|
convoListPage := ConvoListPage{header, convos, Paginator{[]int{1}, 1, 1}}
|
||||||
t.AddStd("convos", "c.ConvoListPage", convoListPage)
|
t.AddStd("convos", "c.ConvoListPage", convoListPage)
|
||||||
|
|
||||||
basePage := &BasePanelPage{header, PanelStats{}, "dashboard", ReportForumID}
|
basePage := &BasePanelPage{header, PanelStats{}, "dashboard", ReportForumID}
|
||||||
t.AddStd("panel", "c.Panel", Panel{basePage, "panel_dashboard_right", "", "panel_dashboard", inter})
|
t.AddStd("panel", "c.Panel", Panel{basePage, "panel_dashboard_right", "", "panel_dashboard", inter})
|
||||||
ges := []GridElement{GridElement{"","", "", 1, "grid_istat", "", "", ""}}
|
ges := []GridElement{GridElement{"", "", "", 1, "grid_istat", "", "", ""}}
|
||||||
t.AddStd("panel_dashboard", "c.DashGrids", DashGrids{ges,ges})
|
t.AddStd("panel_dashboard", "c.DashGrids", DashGrids{ges, ges})
|
||||||
|
|
||||||
goVersion := runtime.Version()
|
goVersion := runtime.Version()
|
||||||
dbVersion := qgen.Builder.DbVersion()
|
dbVersion := qgen.Builder.DbVersion()
|
||||||
var memStats runtime.MemStats
|
var memStats runtime.MemStats
|
||||||
runtime.ReadMemStats(&memStats)
|
runtime.ReadMemStats(&memStats)
|
||||||
debugCache := DebugPageCache{1, 1, 1, 2, 2, 2, true}
|
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}
|
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}
|
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}
|
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_debug", "c.PanelDebugPage", dpage)
|
||||||
//t.AddStd("panel_analytics", "c.PanelAnalytics", Panel{basePage, "panel_dashboard_right","panel_dashboard", inter})
|
//t.AddStd("panel_analytics", "c.PanelAnalytics", Panel{basePage, "panel_dashboard_right","panel_dashboard", inter})
|
||||||
|
@ -531,12 +531,12 @@ func compileJSTemplates(wg *sync.WaitGroup, c *tmpl.CTemplateSet, themeName stri
|
||||||
}, VoteCount: 7}
|
}, VoteCount: 7}
|
||||||
avatar, microAvatar := BuildAvatar(62, "")
|
avatar, microAvatar := BuildAvatar(62, "")
|
||||||
miniAttach := []*MiniAttachment{&MiniAttachment{Path: "/"}}
|
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
|
var replyList []*ReplyUser
|
||||||
// TODO: Do we really want the UID here to be zero?
|
// TODO: Do we really want the UID here to be zero?
|
||||||
avatar, microAvatar = BuildAvatar(0, "")
|
avatar, microAvatar = BuildAvatar(0, "")
|
||||||
reply := Reply{1, 1, "Yo!", 1, Config.DefaultGroup, now, 0, 0, 1, "::1", true, 1, 1, ""}
|
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()
|
ru.Init()
|
||||||
replyList = append(replyList, ru)
|
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_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_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}
|
parti := []*User{&user}
|
||||||
convo := &Conversation{1,user.ID,time.Now(),0,time.Now()}
|
convo := &Conversation{1, user.ID, time.Now(), 0, time.Now()}
|
||||||
convoItems := []ConvoViewRow{ConvoViewRow{&ConversationPost{1,1,"hey","",user.ID}, &user, "", 4, true}}
|
convoItems := []ConvoViewRow{ConvoViewRow{&ConversationPost{1, 1, "hey", "", user.ID}, &user, "", 4, true}}
|
||||||
convoPage := ConvoViewPage{header, convo, convoItems, parti, Paginator{[]int{1}, 1, 1}}
|
convoPage := ConvoViewPage{header, convo, convoItems, parti, Paginator{[]int{1}, 1, 1}}
|
||||||
t.AddStd("convo", "c.ConvoViewPage", convoPage)
|
t.AddStd("convo", "c.ConvoViewPage", convoPage)
|
||||||
|
|
||||||
|
|
133
common/topic.go
133
common/topic.go
|
@ -11,7 +11,6 @@ import (
|
||||||
"html"
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
|
|
||||||
//"log"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -83,8 +82,8 @@ type TopicUser struct {
|
||||||
ContentHTML string // TODO: Avoid converting this to bytes in templates, particularly if it's long
|
ContentHTML string // TODO: Avoid converting this to bytes in templates, particularly if it's long
|
||||||
Tag string
|
Tag string
|
||||||
URL string
|
URL string
|
||||||
URLPrefix string
|
//URLPrefix string
|
||||||
URLName string
|
//URLName string
|
||||||
Level int
|
Level int
|
||||||
Liked bool
|
Liked bool
|
||||||
|
|
||||||
|
@ -215,7 +214,7 @@ func init() {
|
||||||
t := "topics"
|
t := "topics"
|
||||||
topicStmts = TopicStmts{
|
topicStmts = TopicStmts{
|
||||||
getRids: acc.Select("replies").Columns("rid").Where("tid = ?").Orderby("rid ASC").Limit("?,?").Prepare(),
|
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(),
|
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(),
|
updateLastReply: acc.Update(t).Set("lastReplyID = ?").Where("lastReplyID > ? AND tid = ?").Prepare(),
|
||||||
lock: acc.Update(t).Set("is_closed = 1").Where("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(),
|
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(),
|
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 = ?", "", ""),
|
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()
|
return acc.FirstError()
|
||||||
|
@ -250,7 +249,7 @@ func (t *Topic) cacheRemove() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Write a test for this
|
// 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)
|
_, err = topicStmts.addReplies.Exec(1, uid, t.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -300,7 +299,7 @@ func (t *Topic) Unstick() (err error) {
|
||||||
|
|
||||||
// TODO: Test this
|
// TODO: Test this
|
||||||
// TODO: Use a transaction for 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
|
var disp int // Unused
|
||||||
err = topicStmts.hasLikedTopic.QueryRow(uid, t.ID).Scan(&disp)
|
err = topicStmts.hasLikedTopic.QueryRow(uid, t.ID).Scan(&disp)
|
||||||
if err != nil && err != ErrNoRows {
|
if err != nil && err != ErrNoRows {
|
||||||
|
@ -308,12 +307,10 @@ func (t *Topic) Like(score int, uid int) (err error) {
|
||||||
} else if err != ErrNoRows {
|
} else if err != ErrNoRows {
|
||||||
return ErrAlreadyLiked
|
return ErrAlreadyLiked
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = topicStmts.createLike.Exec(score, t.ID, "topics", uid)
|
_, err = topicStmts.createLike.Exec(score, t.ID, "topics", uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = topicStmts.addLikesToTopic.Exec(1, t.ID)
|
_, err = topicStmts.addLikesToTopic.Exec(1, t.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -360,7 +357,7 @@ func (t *Topic) Delete() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Write tests for this
|
// 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))
|
name = SanitiseSingleLine(html.UnescapeString(name))
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return ErrNoTitle
|
return ErrNoTitle
|
||||||
|
@ -371,7 +368,7 @@ func (t *Topic) Update(name string, content string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
content = PreparseMessage(html.UnescapeString(content))
|
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)
|
_, err := topicStmts.edit.Exec(name, content, parsedContent, t.ID)
|
||||||
t.cacheRemove()
|
t.cacheRemove()
|
||||||
return err
|
return err
|
||||||
|
@ -404,7 +401,7 @@ func (t *Topic) CreateActionReply(action string, ip string, uid int) (err error)
|
||||||
return err
|
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)
|
rows, err := topicStmts.getRids.Query(tid, offset, Config.ItemsPerPage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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...
|
// We really shouldn't have inline HTML, we should do something about this...
|
||||||
if ru.ActionType != "" {
|
if ru.ActionType != "" {
|
||||||
var action string
|
|
||||||
aarr := strings.Split(ru.ActionType, "-")
|
aarr := strings.Split(ru.ActionType, "-")
|
||||||
switch aarr[0] {
|
action := aarr[0]
|
||||||
|
switch action {
|
||||||
case "lock":
|
case "lock":
|
||||||
action = aarr[0]
|
|
||||||
ru.ActionIcon = lockai
|
ru.ActionIcon = lockai
|
||||||
case "unlock":
|
case "unlock":
|
||||||
action = aarr[0]
|
|
||||||
ru.ActionIcon = unlockai
|
ru.ActionIcon = unlockai
|
||||||
case "stick":
|
case "stick":
|
||||||
action = aarr[0]
|
|
||||||
ru.ActionIcon = stickai
|
ru.ActionIcon = stickai
|
||||||
case "unstick":
|
case "unstick":
|
||||||
action = aarr[0]
|
|
||||||
ru.ActionIcon = unstickai
|
ru.ActionIcon = unstickai
|
||||||
case "move":
|
case "move":
|
||||||
if len(aarr) == 2 {
|
if len(aarr) == 2 {
|
||||||
|
@ -471,20 +464,16 @@ func (ru *ReplyUser) Init() error {
|
||||||
forum, err := Forums.Get(fid)
|
forum, err := Forums.Get(fid)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ru.ActionType = p.GetTmplPhrasef("topic.action_topic_move_dest", forum.Link, forum.Name, ru.UserLink, ru.CreatedByName)
|
ru.ActionType = p.GetTmplPhrasef("topic.action_topic_move_dest", forum.Link, forum.Name, ru.UserLink, ru.CreatedByName)
|
||||||
} else {
|
return nil
|
||||||
action = aarr[0]
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
action = aarr[0]
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// TODO: Only fire this off if a corresponding phrase for the ActionType doesn't exist? Or maybe have some sort of action registry?
|
// 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)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -516,42 +505,52 @@ func (t *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUs
|
||||||
ruser, err = ucache.Get(re.CreatedBy)
|
ruser, err = ucache.Get(re.CreatedBy)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Factor the user fields out and embed a user struct instead
|
|
||||||
var reply *ReplyUser
|
|
||||||
hTbl := GetHookTable()
|
hTbl := GetHookTable()
|
||||||
if err == nil {
|
rf := func(r *ReplyUser) error {
|
||||||
//log.Print("reply cached serve")
|
err := r.Init()
|
||||||
reply = &ReplyUser{ClassName: "", Reply: *re, CreatedByName: ruser.Name, Avatar: ruser.Avatar, URLPrefix: ruser.URLPrefix, URLName: ruser.URLName, Level: ruser.Level}
|
|
||||||
|
|
||||||
err := reply.Init()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if reply.ID == pFrag {
|
r.ContentHtml = ParseMessage(r.Content, t.ParentID, "forums", user.ParseSettings)
|
||||||
ogdesc = reply.Content
|
// 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 {
|
if len(ogdesc) > 200 {
|
||||||
ogdesc = ogdesc[:197] + "..."
|
ogdesc = ogdesc[:197] + "..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if reply.LikeCount > 0 && user.Liked > 0 {
|
if r.LikeCount > 0 && user.Liked > 0 {
|
||||||
likedMap[reply.ID] = len(rlist)
|
likedMap[r.ID] = len(rlist)
|
||||||
likedQueryList = append(likedQueryList, reply.ID)
|
likedQueryList = append(likedQueryList, r.ID)
|
||||||
}
|
}
|
||||||
if user.Perms.EditReply && reply.AttachCount > 0 {
|
if user.Perms.EditReply && r.AttachCount > 0 {
|
||||||
attachMap[reply.ID] = len(rlist)
|
attachMap[r.ID] = len(rlist)
|
||||||
attachQueryList = append(attachQueryList, reply.ID)
|
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)
|
hTbl.VhookNoRet("topic_reply_row_assign", &rlist, &r)
|
||||||
rlist = append(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, 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 {
|
} else {
|
||||||
rows, err := topicStmts.getReplies.Query(t.ID, offset, Config.ItemsPerPage)
|
rows, err := topicStmts.getReplies.Query(t.ID, offset, Config.ItemsPerPage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -560,39 +559,15 @@ func (t *TopicUser) Replies(offset int, pFrag int, user *User) (rlist []*ReplyUs
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
reply = &ReplyUser{}
|
r := &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)
|
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 {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
if err := reply.Init(); err != nil {
|
err = rf(r)
|
||||||
|
if err != nil {
|
||||||
return nil, "", err
|
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()
|
err = rows.Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -689,7 +664,7 @@ func GetTopicUser(user *User, tid int) (tu TopicUser, err error) {
|
||||||
|
|
||||||
tu = TopicUser{ID: tid}
|
tu = TopicUser{ID: tid}
|
||||||
// TODO: This misses some important bits...
|
// 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.Avatar, tu.MicroAvatar = BuildAvatar(tu.CreatedBy, tu.Avatar)
|
||||||
tu.Link = BuildTopicURL(NameToSlug(tu.Title), tu.ID)
|
tu.Link = BuildTopicURL(NameToSlug(tu.Title), tu.ID)
|
||||||
tu.UserLink = BuildProfileURL(NameToSlug(tu.CreatedByName), tu.CreatedBy)
|
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.Group = u.Group
|
||||||
tu.Avatar = u.Avatar
|
tu.Avatar = u.Avatar
|
||||||
tu.MicroAvatar = u.MicroAvatar
|
tu.MicroAvatar = u.MicroAvatar
|
||||||
tu.URLPrefix = u.URLPrefix
|
//tu.URLPrefix = u.URLPrefix
|
||||||
tu.URLName = u.URLName
|
//tu.URLName = u.URLName
|
||||||
tu.Level = u.Level
|
tu.Level = u.Level
|
||||||
|
|
||||||
tu.ID = t.ID
|
tu.ID = t.ID
|
||||||
|
|
|
@ -29,7 +29,7 @@ type TopicStore interface {
|
||||||
BypassGet(id int) (*Topic, error)
|
BypassGet(id int) (*Topic, error)
|
||||||
BulkGetMap(ids []int) (list map[int]*Topic, err error)
|
BulkGetMap(ids []int) (list map[int]*Topic, err error)
|
||||||
Exists(id int) bool
|
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
|
AddLastTopic(item *Topic, fid int) error // unimplemented
|
||||||
Reload(id int) error // Too much SQL logic to move into TopicCache
|
Reload(id int) error // Too much SQL logic to move into TopicCache
|
||||||
// TODO: Implement these two methods
|
// TODO: Implement these two methods
|
||||||
|
@ -197,22 +197,22 @@ func (s *DefaultTopicStore) Exists(id int) bool {
|
||||||
return s.exists.QueryRow(id).Scan(&id) == nil
|
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) {
|
func (s *DefaultTopicStore) Create(fid int, name string, content string, uid int, ip string) (tid int, err error) {
|
||||||
if topicName == "" {
|
if name == "" {
|
||||||
return 0, ErrNoTitle
|
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?
|
// ? 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
|
return 0, ErrLongTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedContent := strings.TrimSpace(ParseMessage(content, fid, "forums"))
|
parsedContent := strings.TrimSpace(ParseMessage(content, fid, "forums", nil))
|
||||||
if parsedContent == "" {
|
if parsedContent == "" {
|
||||||
return 0, ErrNoBody
|
return 0, ErrNoBody
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move this statement into the topic store
|
// 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 {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,9 @@ type User struct {
|
||||||
Avatar string
|
Avatar string
|
||||||
MicroAvatar string
|
MicroAvatar string
|
||||||
Message string
|
Message string
|
||||||
URLPrefix string // Move this to another table? Create a user lite?
|
// TODO: Implement something like this for profiles?
|
||||||
URLName string
|
//URLPrefix string // Move this to another table? Create a user lite?
|
||||||
|
//URLName string
|
||||||
Tag string
|
Tag string
|
||||||
Level int
|
Level int
|
||||||
Score int
|
Score int
|
||||||
|
@ -56,6 +57,8 @@ type User struct {
|
||||||
LastIP string // ! This part of the UserCache data might fall out of date
|
LastIP string // ! This part of the UserCache data might fall out of date
|
||||||
LastAgent string // ! Temporary hack, don't use
|
LastAgent string // ! Temporary hack, don't use
|
||||||
TempGroup int
|
TempGroup int
|
||||||
|
|
||||||
|
ParseSettings *ParseSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) WebSockets() *WsJSONUser {
|
func (u *User) WebSockets() *WsJSONUser {
|
||||||
|
@ -119,7 +122,7 @@ type UserStmts struct {
|
||||||
changeGroup *sql.Stmt
|
changeGroup *sql.Stmt
|
||||||
delete *sql.Stmt
|
delete *sql.Stmt
|
||||||
setAvatar *sql.Stmt
|
setAvatar *sql.Stmt
|
||||||
setUsername *sql.Stmt
|
setName *sql.Stmt
|
||||||
incTopics *sql.Stmt
|
incTopics *sql.Stmt
|
||||||
updateLevel *sql.Stmt
|
updateLevel *sql.Stmt
|
||||||
update *sql.Stmt
|
update *sql.Stmt
|
||||||
|
@ -133,6 +136,7 @@ type UserStmts struct {
|
||||||
|
|
||||||
decLiked *sql.Stmt
|
decLiked *sql.Stmt
|
||||||
updateLastIP *sql.Stmt
|
updateLastIP *sql.Stmt
|
||||||
|
updatePrivacy *sql.Stmt
|
||||||
|
|
||||||
setPassword *sql.Stmt
|
setPassword *sql.Stmt
|
||||||
|
|
||||||
|
@ -143,27 +147,29 @@ var userStmts UserStmts
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
DbInits.Add(func(acc *qgen.Accumulator) error {
|
DbInits.Add(func(acc *qgen.Accumulator) error {
|
||||||
w := "uid = ?"
|
u := "users"
|
||||||
|
w := "uid=?"
|
||||||
userStmts = UserStmts{
|
userStmts = UserStmts{
|
||||||
activate: acc.SimpleUpdate("users", "active = 1", w),
|
activate: acc.SimpleUpdate(u, "active=1", w),
|
||||||
changeGroup: acc.SimpleUpdate("users", "group = ?", w), // TODO: Implement user_count for users_groups here
|
changeGroup: acc.SimpleUpdate(u, "group=?", w), // TODO: Implement user_count for users_groups here
|
||||||
delete: acc.SimpleDelete("users", w),
|
delete: acc.Delete(u).Where(w).Prepare(),
|
||||||
setAvatar: acc.Update("users").Set("avatar = ?").Where(w).Prepare(),
|
setAvatar: acc.Update(u).Set("avatar=?").Where(w).Prepare(),
|
||||||
setUsername: acc.Update("users").Set("name = ?").Where(w).Prepare(),
|
setName: acc.Update(u).Set("name=?").Where(w).Prepare(),
|
||||||
incTopics: acc.SimpleUpdate("users", "topics = topics + ?", w),
|
incTopics: acc.SimpleUpdate(u, "topics=topics+?", w),
|
||||||
updateLevel: acc.SimpleUpdate("users", "level = ?", w),
|
updateLevel: acc.SimpleUpdate(u, "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
|
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(),
|
incScore: acc.Update(u).Set("score=score+?").Where(w).Prepare(),
|
||||||
incPosts: acc.Update("users").Set("posts = posts + ?").Where(w).Prepare(),
|
incPosts: acc.Update(u).Set("posts=posts+?").Where(w).Prepare(),
|
||||||
incBigposts: acc.Update("users").Set("posts = posts + ?, bigposts = bigposts + ?").Where(w).Prepare(),
|
incBigposts: acc.Update(u).Set("posts=posts+?,bigposts=bigposts+?").Where(w).Prepare(),
|
||||||
incMegaposts: acc.Update("users").Set("posts = posts + ?, bigposts = bigposts + ?, megaposts = megaposts + ?").Where(w).Prepare(),
|
incMegaposts: acc.Update(u).Set("posts=posts+?,bigposts=bigposts+?,megaposts=megaposts+?").Where(w).Prepare(),
|
||||||
incLiked: acc.Update("users").Set("liked = liked + ?, lastLiked = UTC_TIMESTAMP()").Where(w).Prepare(),
|
incLiked: acc.Update(u).Set("liked=liked+?,lastLiked=UTC_TIMESTAMP()").Where(w).Prepare(),
|
||||||
decLiked: acc.Update("users").Set("liked = liked - ?").Where(w).Prepare(),
|
decLiked: acc.Update(u).Set("liked=liked-?").Where(w).Prepare(),
|
||||||
//recalcLastLiked: acc...
|
//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(),
|
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 {
|
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 {
|
if err != nil {
|
||||||
return err
|
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) {
|
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) {
|
func (u *User) ChangeAvatar(avatar string) (err error) {
|
||||||
|
@ -341,7 +347,15 @@ func (u *User) UpdateIP(host string) error {
|
||||||
return err
|
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)
|
return u.bindStmt(userStmts.update, name, email, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,7 +475,7 @@ type GuestAvatar struct {
|
||||||
Micro string
|
Micro string
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildNoavatar(uid int, width int) string {
|
func buildNoavatar(uid, width int) string {
|
||||||
if !Config.DisableNoavatarRange {
|
if !Config.DisableNoavatarRange {
|
||||||
// TODO: Find a faster algorithm
|
// TODO: Find a faster algorithm
|
||||||
if uid > 50000 {
|
if uid > 50000 {
|
||||||
|
@ -520,7 +534,6 @@ func wordsToScore(wcount int, topic bool) (score int) {
|
||||||
} else {
|
} else {
|
||||||
score = 1
|
score = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
settings := SettingBox.Load().(SettingMap)
|
settings := SettingBox.Load().(SettingMap)
|
||||||
if wcount >= settings["megapost_min_words"].(int) {
|
if wcount >= settings["megapost_min_words"].(int) {
|
||||||
score += 4
|
score += 4
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/Azareal/Gosora/query_gen"
|
qgen "github.com/Azareal/Gosora/query_gen"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,11 +20,11 @@ type UserStore interface {
|
||||||
Get(id int) (*User, error)
|
Get(id int) (*User, error)
|
||||||
GetByName(name string) (*User, error)
|
GetByName(name string) (*User, error)
|
||||||
Exists(id int) bool
|
Exists(id int) bool
|
||||||
GetOffset(offset int, perPage int) (users []*User, err error)
|
GetOffset(offset, perPage int) ([]*User, error)
|
||||||
//BulkGet(ids []int) ([]*User, error)
|
//BulkGet(ids []int) ([]*User, error)
|
||||||
BulkGetMap(ids []int) (map[int]*User, error)
|
BulkGetMap(ids []int) (map[int]*User, error)
|
||||||
BypassGet(id 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
|
Reload(id int) error
|
||||||
Count() int
|
Count() int
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ type DefaultUserStore struct {
|
||||||
getOffset *sql.Stmt
|
getOffset *sql.Stmt
|
||||||
exists *sql.Stmt
|
exists *sql.Stmt
|
||||||
register *sql.Stmt
|
register *sql.Stmt
|
||||||
usernameExists *sql.Stmt
|
nameExists *sql.Stmt
|
||||||
count *sql.Stmt
|
count *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,16 +50,17 @@ func NewDefaultUserStore(cache UserCache) (*DefaultUserStore, error) {
|
||||||
if cache == nil {
|
if cache == nil {
|
||||||
cache = NewNullUserCache()
|
cache = NewNullUserCache()
|
||||||
}
|
}
|
||||||
|
u := "users"
|
||||||
// TODO: Add an admin version of registerStmt with more flexibility?
|
// TODO: Add an admin version of registerStmt with more flexibility?
|
||||||
return &DefaultUserStore{
|
return &DefaultUserStore{
|
||||||
cache: cache,
|
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 = ?", "", ""),
|
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("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(),
|
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("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(),
|
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.SimpleSelect("users", "uid", "uid = ?", "", ""),
|
exists: acc.Exists(u, "uid").Prepare(),
|
||||||
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
|
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
|
||||||
usernameExists: acc.SimpleSelect("users", "name", "name = ?", "", ""),
|
nameExists: acc.Exists(u, "name").Prepare(),
|
||||||
count: acc.Count("users").Prepare(),
|
count: acc.Count(u).Prepare(),
|
||||||
}, acc.FirstError()
|
}, acc.FirstError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +87,13 @@ func (s *DefaultUserStore) Get(id int) (*User, error) {
|
||||||
//log.Print("uncached user")
|
//log.Print("uncached user")
|
||||||
|
|
||||||
u = &User{ID: id, Loggedin: true}
|
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 err == nil {
|
||||||
|
if embeds != -1 {
|
||||||
|
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||||
|
u.ParseSettings.NoEmbed = embeds == 0
|
||||||
|
}
|
||||||
u.Init()
|
u.Init()
|
||||||
s.cache.Set(u)
|
s.cache.Set(u)
|
||||||
}
|
}
|
||||||
|
@ -98,8 +104,13 @@ func (s *DefaultUserStore) Get(id int) (*User, error) {
|
||||||
// ! This bypasses the cache, use frugally
|
// ! This bypasses the cache, use frugally
|
||||||
func (s *DefaultUserStore) GetByName(name string) (*User, error) {
|
func (s *DefaultUserStore) GetByName(name string) (*User, error) {
|
||||||
u := &User{Loggedin: true}
|
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 err == nil {
|
||||||
|
if embeds != -1 {
|
||||||
|
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||||
|
u.ParseSettings.NoEmbed = embeds == 0
|
||||||
|
}
|
||||||
u.Init()
|
u.Init()
|
||||||
s.cache.Set(u)
|
s.cache.Set(u)
|
||||||
}
|
}
|
||||||
|
@ -115,12 +126,17 @@ func (s *DefaultUserStore) GetOffset(offset int, perPage int) (users []*User, er
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
|
var embeds int
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
u := &User{Loggedin: true}
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if embeds != -1 {
|
||||||
|
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||||
|
u.ParseSettings.NoEmbed = embeds == 0
|
||||||
|
}
|
||||||
u.Init()
|
u.Init()
|
||||||
s.cache.Set(u)
|
s.cache.Set(u)
|
||||||
users = append(users, 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
|
// TODO: Add a function for the q stuff
|
||||||
var q string
|
var q string
|
||||||
idList := make([]interface{},len(ids))
|
idList := make([]interface{}, len(ids))
|
||||||
for i, id := range ids {
|
for i, id := range ids {
|
||||||
idList[i] = strconv.Itoa(id)
|
idList[i] = strconv.Itoa(id)
|
||||||
q += "?,"
|
q += "?,"
|
||||||
}
|
}
|
||||||
q = q[0 : len(q)-1]
|
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 {
|
if err != nil {
|
||||||
return list, err
|
return list, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
|
var embeds int
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
u := &User{Loggedin: true}
|
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 {
|
if err != nil {
|
||||||
return list, err
|
return list, err
|
||||||
}
|
}
|
||||||
|
if embeds != -1 {
|
||||||
|
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||||
|
u.ParseSettings.NoEmbed = embeds == 0
|
||||||
|
}
|
||||||
u.Init()
|
u.Init()
|
||||||
s.cache.Set(u)
|
s.cache.Set(u)
|
||||||
list[u.ID] = u
|
list[u.ID] = u
|
||||||
}
|
}
|
||||||
err = rows.Err()
|
if err = rows.Err(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return list, err
|
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) {
|
func (s *DefaultUserStore) BypassGet(id int) (*User, error) {
|
||||||
u := &User{ID: id, Loggedin: true}
|
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 err == nil {
|
||||||
|
if embeds != -1 {
|
||||||
|
u.ParseSettings = DefaultParseSettings.CopyPtr()
|
||||||
|
u.ParseSettings.NoEmbed = embeds == 0
|
||||||
|
}
|
||||||
u.Init()
|
u.Init()
|
||||||
}
|
}
|
||||||
return u, err
|
return u, err
|
||||||
|
@ -240,16 +265,16 @@ func (s *DefaultUserStore) Exists(id int) bool {
|
||||||
|
|
||||||
// TODO: Change active to a bool?
|
// TODO: Change active to a bool?
|
||||||
// TODO: Use unique keys for the usernames
|
// 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?
|
// 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?
|
// ? 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
|
return 0, ErrLongUsername
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this username already taken..?
|
// Is this name already taken..?
|
||||||
err := s.usernameExists.QueryRow(username).Scan(&username)
|
err := s.nameExists.QueryRow(name).Scan(&name)
|
||||||
if err != ErrNoRows {
|
if err != ErrNoRows {
|
||||||
return 0, ErrAccountExists
|
return 0, ErrAccountExists
|
||||||
}
|
}
|
||||||
|
@ -262,7 +287,7 @@ func (s *DefaultUserStore) Create(username string, password string, email string
|
||||||
return 0, err
|
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 {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,12 @@ type Version struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Write a test for this
|
// TODO: Write a test for this
|
||||||
func (version *Version) String() (out string) {
|
func (ver *Version) String() (out string) {
|
||||||
out = strconv.Itoa(version.Major) + "." + strconv.Itoa(version.Minor) + "." + strconv.Itoa(version.Patch)
|
out = strconv.Itoa(ver.Major) + "." + strconv.Itoa(ver.Minor) + "." + strconv.Itoa(ver.Patch)
|
||||||
if version.Tag != "" {
|
if ver.Tag != "" {
|
||||||
out += "-" + version.Tag
|
out += "-" + ver.Tag
|
||||||
if version.TagID != 0 {
|
if ver.TagID != 0 {
|
||||||
out += strconv.Itoa(version.TagID)
|
out += strconv.Itoa(ver.TagID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -335,10 +335,10 @@ func HasSuspiciousEmail(email string) bool {
|
||||||
return dotCount > 7 || shortBits > 2
|
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
|
// 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)
|
lowPassword := strings.ToLower(password)
|
||||||
switch {
|
switch {
|
||||||
case password == "":
|
case password == "":
|
||||||
|
@ -422,7 +422,7 @@ func createFile(name string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Write a test for this
|
// 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)
|
f, err := os.Create(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.
|
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
|
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.
|
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
|
goto SkipListInnerLoop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if index >= datalen {
|
if index >= datalen {
|
||||||
if data[index] != '*' && data[index] != '-' {
|
if data[index] != '*' && data[index] != '-' {
|
||||||
if (lastNewline + 1) < datalen {
|
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.AccountEditAvatarSubmit": routes.AccountEditAvatarSubmit,
|
||||||
"routes.AccountEditRevokeAvatarSubmit": routes.AccountEditRevokeAvatarSubmit,
|
"routes.AccountEditRevokeAvatarSubmit": routes.AccountEditRevokeAvatarSubmit,
|
||||||
"routes.AccountEditUsernameSubmit": routes.AccountEditUsernameSubmit,
|
"routes.AccountEditUsernameSubmit": routes.AccountEditUsernameSubmit,
|
||||||
|
"routes.AccountEditPrivacy": routes.AccountEditPrivacy,
|
||||||
|
"routes.AccountEditPrivacySubmit": routes.AccountEditPrivacySubmit,
|
||||||
"routes.AccountEditMFA": routes.AccountEditMFA,
|
"routes.AccountEditMFA": routes.AccountEditMFA,
|
||||||
"routes.AccountEditMFASetup": routes.AccountEditMFASetup,
|
"routes.AccountEditMFASetup": routes.AccountEditMFASetup,
|
||||||
"routes.AccountEditMFASetupSubmit": routes.AccountEditMFASetupSubmit,
|
"routes.AccountEditMFASetupSubmit": routes.AccountEditMFASetupSubmit,
|
||||||
|
@ -290,73 +292,75 @@ var routeMapEnum = map[string]int{
|
||||||
"routes.AccountEditAvatarSubmit": 95,
|
"routes.AccountEditAvatarSubmit": 95,
|
||||||
"routes.AccountEditRevokeAvatarSubmit": 96,
|
"routes.AccountEditRevokeAvatarSubmit": 96,
|
||||||
"routes.AccountEditUsernameSubmit": 97,
|
"routes.AccountEditUsernameSubmit": 97,
|
||||||
"routes.AccountEditMFA": 98,
|
"routes.AccountEditPrivacy": 98,
|
||||||
"routes.AccountEditMFASetup": 99,
|
"routes.AccountEditPrivacySubmit": 99,
|
||||||
"routes.AccountEditMFASetupSubmit": 100,
|
"routes.AccountEditMFA": 100,
|
||||||
"routes.AccountEditMFADisableSubmit": 101,
|
"routes.AccountEditMFASetup": 101,
|
||||||
"routes.AccountEditEmail": 102,
|
"routes.AccountEditMFASetupSubmit": 102,
|
||||||
"routes.AccountEditEmailTokenSubmit": 103,
|
"routes.AccountEditMFADisableSubmit": 103,
|
||||||
"routes.AccountLogins": 104,
|
"routes.AccountEditEmail": 104,
|
||||||
"routes.AccountBlocked": 105,
|
"routes.AccountEditEmailTokenSubmit": 105,
|
||||||
"routes.LevelList": 106,
|
"routes.AccountLogins": 106,
|
||||||
"routes.Convos": 107,
|
"routes.AccountBlocked": 107,
|
||||||
"routes.ConvosCreate": 108,
|
"routes.LevelList": 108,
|
||||||
"routes.Convo": 109,
|
"routes.Convos": 109,
|
||||||
"routes.ConvosCreateSubmit": 110,
|
"routes.ConvosCreate": 110,
|
||||||
"routes.ConvosCreateReplySubmit": 111,
|
"routes.Convo": 111,
|
||||||
"routes.ConvosDeleteReplySubmit": 112,
|
"routes.ConvosCreateSubmit": 112,
|
||||||
"routes.ConvosEditReplySubmit": 113,
|
"routes.ConvosCreateReplySubmit": 113,
|
||||||
"routes.RelationsBlockCreate": 114,
|
"routes.ConvosDeleteReplySubmit": 114,
|
||||||
"routes.RelationsBlockCreateSubmit": 115,
|
"routes.ConvosEditReplySubmit": 115,
|
||||||
"routes.RelationsBlockRemove": 116,
|
"routes.RelationsBlockCreate": 116,
|
||||||
"routes.RelationsBlockRemoveSubmit": 117,
|
"routes.RelationsBlockCreateSubmit": 117,
|
||||||
"routes.ViewProfile": 118,
|
"routes.RelationsBlockRemove": 118,
|
||||||
"routes.BanUserSubmit": 119,
|
"routes.RelationsBlockRemoveSubmit": 119,
|
||||||
"routes.UnbanUser": 120,
|
"routes.ViewProfile": 120,
|
||||||
"routes.ActivateUser": 121,
|
"routes.BanUserSubmit": 121,
|
||||||
"routes.IPSearch": 122,
|
"routes.UnbanUser": 122,
|
||||||
"routes.CreateTopicSubmit": 123,
|
"routes.ActivateUser": 123,
|
||||||
"routes.EditTopicSubmit": 124,
|
"routes.IPSearch": 124,
|
||||||
"routes.DeleteTopicSubmit": 125,
|
"routes.CreateTopicSubmit": 125,
|
||||||
"routes.StickTopicSubmit": 126,
|
"routes.EditTopicSubmit": 126,
|
||||||
"routes.UnstickTopicSubmit": 127,
|
"routes.DeleteTopicSubmit": 127,
|
||||||
"routes.LockTopicSubmit": 128,
|
"routes.StickTopicSubmit": 128,
|
||||||
"routes.UnlockTopicSubmit": 129,
|
"routes.UnstickTopicSubmit": 129,
|
||||||
"routes.MoveTopicSubmit": 130,
|
"routes.LockTopicSubmit": 130,
|
||||||
"routes.LikeTopicSubmit": 131,
|
"routes.UnlockTopicSubmit": 131,
|
||||||
"routes.AddAttachToTopicSubmit": 132,
|
"routes.MoveTopicSubmit": 132,
|
||||||
"routes.RemoveAttachFromTopicSubmit": 133,
|
"routes.LikeTopicSubmit": 133,
|
||||||
"routes.ViewTopic": 134,
|
"routes.AddAttachToTopicSubmit": 134,
|
||||||
"routes.CreateReplySubmit": 135,
|
"routes.RemoveAttachFromTopicSubmit": 135,
|
||||||
"routes.ReplyEditSubmit": 136,
|
"routes.ViewTopic": 136,
|
||||||
"routes.ReplyDeleteSubmit": 137,
|
"routes.CreateReplySubmit": 137,
|
||||||
"routes.ReplyLikeSubmit": 138,
|
"routes.ReplyEditSubmit": 138,
|
||||||
"routes.AddAttachToReplySubmit": 139,
|
"routes.ReplyDeleteSubmit": 139,
|
||||||
"routes.RemoveAttachFromReplySubmit": 140,
|
"routes.ReplyLikeSubmit": 140,
|
||||||
"routes.ProfileReplyCreateSubmit": 141,
|
"routes.AddAttachToReplySubmit": 141,
|
||||||
"routes.ProfileReplyEditSubmit": 142,
|
"routes.RemoveAttachFromReplySubmit": 142,
|
||||||
"routes.ProfileReplyDeleteSubmit": 143,
|
"routes.ProfileReplyCreateSubmit": 143,
|
||||||
"routes.PollVote": 144,
|
"routes.ProfileReplyEditSubmit": 144,
|
||||||
"routes.PollResults": 145,
|
"routes.ProfileReplyDeleteSubmit": 145,
|
||||||
"routes.AccountLogin": 146,
|
"routes.PollVote": 146,
|
||||||
"routes.AccountRegister": 147,
|
"routes.PollResults": 147,
|
||||||
"routes.AccountLogout": 148,
|
"routes.AccountLogin": 148,
|
||||||
"routes.AccountLoginSubmit": 149,
|
"routes.AccountRegister": 149,
|
||||||
"routes.AccountLoginMFAVerify": 150,
|
"routes.AccountLogout": 150,
|
||||||
"routes.AccountLoginMFAVerifySubmit": 151,
|
"routes.AccountLoginSubmit": 151,
|
||||||
"routes.AccountRegisterSubmit": 152,
|
"routes.AccountLoginMFAVerify": 152,
|
||||||
"routes.AccountPasswordReset": 153,
|
"routes.AccountLoginMFAVerifySubmit": 153,
|
||||||
"routes.AccountPasswordResetSubmit": 154,
|
"routes.AccountRegisterSubmit": 154,
|
||||||
"routes.AccountPasswordResetToken": 155,
|
"routes.AccountPasswordReset": 155,
|
||||||
"routes.AccountPasswordResetTokenSubmit": 156,
|
"routes.AccountPasswordResetSubmit": 156,
|
||||||
"routes.DynamicRoute": 157,
|
"routes.AccountPasswordResetToken": 157,
|
||||||
"routes.UploadedFile": 158,
|
"routes.AccountPasswordResetTokenSubmit": 158,
|
||||||
"routes.StaticFile": 159,
|
"routes.DynamicRoute": 159,
|
||||||
"routes.RobotsTxt": 160,
|
"routes.UploadedFile": 160,
|
||||||
"routes.SitemapXml": 161,
|
"routes.StaticFile": 161,
|
||||||
"routes.OpenSearchXml": 162,
|
"routes.RobotsTxt": 162,
|
||||||
"routes.BadRoute": 163,
|
"routes.SitemapXml": 163,
|
||||||
"routes.HTTPSRedirect": 164,
|
"routes.OpenSearchXml": 164,
|
||||||
|
"routes.BadRoute": 165,
|
||||||
|
"routes.HTTPSRedirect": 166,
|
||||||
}
|
}
|
||||||
var reverseRouteMapEnum = map[int]string{
|
var reverseRouteMapEnum = map[int]string{
|
||||||
0: "routes.Overview",
|
0: "routes.Overview",
|
||||||
|
@ -457,73 +461,75 @@ var reverseRouteMapEnum = map[int]string{
|
||||||
95: "routes.AccountEditAvatarSubmit",
|
95: "routes.AccountEditAvatarSubmit",
|
||||||
96: "routes.AccountEditRevokeAvatarSubmit",
|
96: "routes.AccountEditRevokeAvatarSubmit",
|
||||||
97: "routes.AccountEditUsernameSubmit",
|
97: "routes.AccountEditUsernameSubmit",
|
||||||
98: "routes.AccountEditMFA",
|
98: "routes.AccountEditPrivacy",
|
||||||
99: "routes.AccountEditMFASetup",
|
99: "routes.AccountEditPrivacySubmit",
|
||||||
100: "routes.AccountEditMFASetupSubmit",
|
100: "routes.AccountEditMFA",
|
||||||
101: "routes.AccountEditMFADisableSubmit",
|
101: "routes.AccountEditMFASetup",
|
||||||
102: "routes.AccountEditEmail",
|
102: "routes.AccountEditMFASetupSubmit",
|
||||||
103: "routes.AccountEditEmailTokenSubmit",
|
103: "routes.AccountEditMFADisableSubmit",
|
||||||
104: "routes.AccountLogins",
|
104: "routes.AccountEditEmail",
|
||||||
105: "routes.AccountBlocked",
|
105: "routes.AccountEditEmailTokenSubmit",
|
||||||
106: "routes.LevelList",
|
106: "routes.AccountLogins",
|
||||||
107: "routes.Convos",
|
107: "routes.AccountBlocked",
|
||||||
108: "routes.ConvosCreate",
|
108: "routes.LevelList",
|
||||||
109: "routes.Convo",
|
109: "routes.Convos",
|
||||||
110: "routes.ConvosCreateSubmit",
|
110: "routes.ConvosCreate",
|
||||||
111: "routes.ConvosCreateReplySubmit",
|
111: "routes.Convo",
|
||||||
112: "routes.ConvosDeleteReplySubmit",
|
112: "routes.ConvosCreateSubmit",
|
||||||
113: "routes.ConvosEditReplySubmit",
|
113: "routes.ConvosCreateReplySubmit",
|
||||||
114: "routes.RelationsBlockCreate",
|
114: "routes.ConvosDeleteReplySubmit",
|
||||||
115: "routes.RelationsBlockCreateSubmit",
|
115: "routes.ConvosEditReplySubmit",
|
||||||
116: "routes.RelationsBlockRemove",
|
116: "routes.RelationsBlockCreate",
|
||||||
117: "routes.RelationsBlockRemoveSubmit",
|
117: "routes.RelationsBlockCreateSubmit",
|
||||||
118: "routes.ViewProfile",
|
118: "routes.RelationsBlockRemove",
|
||||||
119: "routes.BanUserSubmit",
|
119: "routes.RelationsBlockRemoveSubmit",
|
||||||
120: "routes.UnbanUser",
|
120: "routes.ViewProfile",
|
||||||
121: "routes.ActivateUser",
|
121: "routes.BanUserSubmit",
|
||||||
122: "routes.IPSearch",
|
122: "routes.UnbanUser",
|
||||||
123: "routes.CreateTopicSubmit",
|
123: "routes.ActivateUser",
|
||||||
124: "routes.EditTopicSubmit",
|
124: "routes.IPSearch",
|
||||||
125: "routes.DeleteTopicSubmit",
|
125: "routes.CreateTopicSubmit",
|
||||||
126: "routes.StickTopicSubmit",
|
126: "routes.EditTopicSubmit",
|
||||||
127: "routes.UnstickTopicSubmit",
|
127: "routes.DeleteTopicSubmit",
|
||||||
128: "routes.LockTopicSubmit",
|
128: "routes.StickTopicSubmit",
|
||||||
129: "routes.UnlockTopicSubmit",
|
129: "routes.UnstickTopicSubmit",
|
||||||
130: "routes.MoveTopicSubmit",
|
130: "routes.LockTopicSubmit",
|
||||||
131: "routes.LikeTopicSubmit",
|
131: "routes.UnlockTopicSubmit",
|
||||||
132: "routes.AddAttachToTopicSubmit",
|
132: "routes.MoveTopicSubmit",
|
||||||
133: "routes.RemoveAttachFromTopicSubmit",
|
133: "routes.LikeTopicSubmit",
|
||||||
134: "routes.ViewTopic",
|
134: "routes.AddAttachToTopicSubmit",
|
||||||
135: "routes.CreateReplySubmit",
|
135: "routes.RemoveAttachFromTopicSubmit",
|
||||||
136: "routes.ReplyEditSubmit",
|
136: "routes.ViewTopic",
|
||||||
137: "routes.ReplyDeleteSubmit",
|
137: "routes.CreateReplySubmit",
|
||||||
138: "routes.ReplyLikeSubmit",
|
138: "routes.ReplyEditSubmit",
|
||||||
139: "routes.AddAttachToReplySubmit",
|
139: "routes.ReplyDeleteSubmit",
|
||||||
140: "routes.RemoveAttachFromReplySubmit",
|
140: "routes.ReplyLikeSubmit",
|
||||||
141: "routes.ProfileReplyCreateSubmit",
|
141: "routes.AddAttachToReplySubmit",
|
||||||
142: "routes.ProfileReplyEditSubmit",
|
142: "routes.RemoveAttachFromReplySubmit",
|
||||||
143: "routes.ProfileReplyDeleteSubmit",
|
143: "routes.ProfileReplyCreateSubmit",
|
||||||
144: "routes.PollVote",
|
144: "routes.ProfileReplyEditSubmit",
|
||||||
145: "routes.PollResults",
|
145: "routes.ProfileReplyDeleteSubmit",
|
||||||
146: "routes.AccountLogin",
|
146: "routes.PollVote",
|
||||||
147: "routes.AccountRegister",
|
147: "routes.PollResults",
|
||||||
148: "routes.AccountLogout",
|
148: "routes.AccountLogin",
|
||||||
149: "routes.AccountLoginSubmit",
|
149: "routes.AccountRegister",
|
||||||
150: "routes.AccountLoginMFAVerify",
|
150: "routes.AccountLogout",
|
||||||
151: "routes.AccountLoginMFAVerifySubmit",
|
151: "routes.AccountLoginSubmit",
|
||||||
152: "routes.AccountRegisterSubmit",
|
152: "routes.AccountLoginMFAVerify",
|
||||||
153: "routes.AccountPasswordReset",
|
153: "routes.AccountLoginMFAVerifySubmit",
|
||||||
154: "routes.AccountPasswordResetSubmit",
|
154: "routes.AccountRegisterSubmit",
|
||||||
155: "routes.AccountPasswordResetToken",
|
155: "routes.AccountPasswordReset",
|
||||||
156: "routes.AccountPasswordResetTokenSubmit",
|
156: "routes.AccountPasswordResetSubmit",
|
||||||
157: "routes.DynamicRoute",
|
157: "routes.AccountPasswordResetToken",
|
||||||
158: "routes.UploadedFile",
|
158: "routes.AccountPasswordResetTokenSubmit",
|
||||||
159: "routes.StaticFile",
|
159: "routes.DynamicRoute",
|
||||||
160: "routes.RobotsTxt",
|
160: "routes.UploadedFile",
|
||||||
161: "routes.SitemapXml",
|
161: "routes.StaticFile",
|
||||||
162: "routes.OpenSearchXml",
|
162: "routes.RobotsTxt",
|
||||||
163: "routes.BadRoute",
|
163: "routes.SitemapXml",
|
||||||
164: "routes.HTTPSRedirect",
|
164: "routes.OpenSearchXml",
|
||||||
|
165: "routes.BadRoute",
|
||||||
|
166: "routes.HTTPSRedirect",
|
||||||
}
|
}
|
||||||
var osMapEnum = map[string]int{
|
var osMapEnum = map[string]int{
|
||||||
"unknown": 0,
|
"unknown": 0,
|
||||||
|
@ -681,7 +687,7 @@ type HTTPSRedirect struct {}
|
||||||
|
|
||||||
func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
w.Header().Set("Connection", "close")
|
w.Header().Set("Connection", "close")
|
||||||
co.RouteViewCounter.Bump(164)
|
co.RouteViewCounter.Bump(166)
|
||||||
dest := "https://" + req.Host + req.URL.String()
|
dest := "https://" + req.Host + req.URL.String()
|
||||||
http.Redirect(w, req, dest, http.StatusTemporaryRedirect)
|
http.Redirect(w, req, dest, http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
@ -889,7 +895,7 @@ func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
co.GlobalViewCounter.Bump()
|
co.GlobalViewCounter.Bump()
|
||||||
|
|
||||||
if prefix == "/s" { //old prefix: /static
|
if prefix == "/s" { //old prefix: /static
|
||||||
co.RouteViewCounter.Bump(159)
|
co.RouteViewCounter.Bump(161)
|
||||||
req.URL.Path += extraData
|
req.URL.Path += extraData
|
||||||
routes.StaticFile(w, req)
|
routes.StaticFile(w, req)
|
||||||
return
|
return
|
||||||
|
@ -1800,7 +1806,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(97)
|
co.RouteViewCounter.Bump(97)
|
||||||
err = routes.AccountEditUsernameSubmit(w,req,user)
|
err = routes.AccountEditUsernameSubmit(w,req,user)
|
||||||
case "/user/edit/mfa/":
|
case "/user/edit/privacy/":
|
||||||
err = c.MemberOnly(w,req,user)
|
err = c.MemberOnly(w,req,user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1808,6 +1814,31 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(98)
|
co.RouteViewCounter.Bump(98)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1818,7 +1849,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(99)
|
co.RouteViewCounter.Bump(101)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1835,7 +1866,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(100)
|
co.RouteViewCounter.Bump(102)
|
||||||
err = routes.AccountEditMFASetupSubmit(w,req,user)
|
err = routes.AccountEditMFASetupSubmit(w,req,user)
|
||||||
case "/user/edit/mfa/disable/submit/":
|
case "/user/edit/mfa/disable/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -1848,7 +1879,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(101)
|
co.RouteViewCounter.Bump(103)
|
||||||
err = routes.AccountEditMFADisableSubmit(w,req,user)
|
err = routes.AccountEditMFADisableSubmit(w,req,user)
|
||||||
case "/user/edit/email/":
|
case "/user/edit/email/":
|
||||||
err = c.MemberOnly(w,req,user)
|
err = c.MemberOnly(w,req,user)
|
||||||
|
@ -1856,14 +1887,14 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(102)
|
co.RouteViewCounter.Bump(104)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = routes.AccountEditEmail(w,req,user,head)
|
err = routes.AccountEditEmail(w,req,user,head)
|
||||||
case "/user/edit/token/":
|
case "/user/edit/token/":
|
||||||
co.RouteViewCounter.Bump(103)
|
co.RouteViewCounter.Bump(105)
|
||||||
err = routes.AccountEditEmailTokenSubmit(w,req,user,extraData)
|
err = routes.AccountEditEmailTokenSubmit(w,req,user,extraData)
|
||||||
case "/user/edit/logins/":
|
case "/user/edit/logins/":
|
||||||
err = c.MemberOnly(w,req,user)
|
err = c.MemberOnly(w,req,user)
|
||||||
|
@ -1871,7 +1902,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(104)
|
co.RouteViewCounter.Bump(106)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1883,7 +1914,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(105)
|
co.RouteViewCounter.Bump(107)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1895,7 +1926,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(106)
|
co.RouteViewCounter.Bump(108)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1907,7 +1938,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(107)
|
co.RouteViewCounter.Bump(109)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1919,7 +1950,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(108)
|
co.RouteViewCounter.Bump(110)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1931,7 +1962,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(109)
|
co.RouteViewCounter.Bump(111)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1948,7 +1979,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(110)
|
co.RouteViewCounter.Bump(112)
|
||||||
err = routes.ConvosCreateSubmit(w,req,user)
|
err = routes.ConvosCreateSubmit(w,req,user)
|
||||||
case "/user/convo/create/submit/":
|
case "/user/convo/create/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -1961,7 +1992,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(111)
|
co.RouteViewCounter.Bump(113)
|
||||||
err = routes.ConvosCreateReplySubmit(w,req,user,extraData)
|
err = routes.ConvosCreateReplySubmit(w,req,user,extraData)
|
||||||
case "/user/convo/delete/submit/":
|
case "/user/convo/delete/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -1974,7 +2005,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(112)
|
co.RouteViewCounter.Bump(114)
|
||||||
err = routes.ConvosDeleteReplySubmit(w,req,user,extraData)
|
err = routes.ConvosDeleteReplySubmit(w,req,user,extraData)
|
||||||
case "/user/convo/edit/submit/":
|
case "/user/convo/edit/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -1987,7 +2018,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(113)
|
co.RouteViewCounter.Bump(115)
|
||||||
err = routes.ConvosEditReplySubmit(w,req,user,extraData)
|
err = routes.ConvosEditReplySubmit(w,req,user,extraData)
|
||||||
case "/user/block/create/":
|
case "/user/block/create/":
|
||||||
err = c.MemberOnly(w,req,user)
|
err = c.MemberOnly(w,req,user)
|
||||||
|
@ -1995,7 +2026,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(114)
|
co.RouteViewCounter.Bump(116)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2012,7 +2043,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(115)
|
co.RouteViewCounter.Bump(117)
|
||||||
err = routes.RelationsBlockCreateSubmit(w,req,user,extraData)
|
err = routes.RelationsBlockCreateSubmit(w,req,user,extraData)
|
||||||
case "/user/block/remove/":
|
case "/user/block/remove/":
|
||||||
err = c.MemberOnly(w,req,user)
|
err = c.MemberOnly(w,req,user)
|
||||||
|
@ -2020,7 +2051,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(116)
|
co.RouteViewCounter.Bump(118)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2037,11 +2068,11 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(117)
|
co.RouteViewCounter.Bump(119)
|
||||||
err = routes.RelationsBlockRemoveSubmit(w,req,user,extraData)
|
err = routes.RelationsBlockRemoveSubmit(w,req,user,extraData)
|
||||||
default:
|
default:
|
||||||
req.URL.Path += extraData
|
req.URL.Path += extraData
|
||||||
co.RouteViewCounter.Bump(118)
|
co.RouteViewCounter.Bump(120)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2061,7 +2092,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(119)
|
co.RouteViewCounter.Bump(121)
|
||||||
err = routes.BanUserSubmit(w,req,user,extraData)
|
err = routes.BanUserSubmit(w,req,user,extraData)
|
||||||
case "/users/unban/":
|
case "/users/unban/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2074,7 +2105,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(120)
|
co.RouteViewCounter.Bump(122)
|
||||||
err = routes.UnbanUser(w,req,user,extraData)
|
err = routes.UnbanUser(w,req,user,extraData)
|
||||||
case "/users/activate/":
|
case "/users/activate/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2087,7 +2118,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(121)
|
co.RouteViewCounter.Bump(123)
|
||||||
err = routes.ActivateUser(w,req,user,extraData)
|
err = routes.ActivateUser(w,req,user,extraData)
|
||||||
case "/users/ips/":
|
case "/users/ips/":
|
||||||
err = c.MemberOnly(w,req,user)
|
err = c.MemberOnly(w,req,user)
|
||||||
|
@ -2095,7 +2126,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(122)
|
co.RouteViewCounter.Bump(124)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2119,7 +2150,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(123)
|
co.RouteViewCounter.Bump(125)
|
||||||
err = routes.CreateTopicSubmit(w,req,user)
|
err = routes.CreateTopicSubmit(w,req,user)
|
||||||
case "/topic/edit/submit/":
|
case "/topic/edit/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2132,7 +2163,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(124)
|
co.RouteViewCounter.Bump(126)
|
||||||
err = routes.EditTopicSubmit(w,req,user,extraData)
|
err = routes.EditTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/delete/submit/":
|
case "/topic/delete/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
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
|
req.URL.Path += extraData
|
||||||
co.RouteViewCounter.Bump(125)
|
co.RouteViewCounter.Bump(127)
|
||||||
err = routes.DeleteTopicSubmit(w,req,user)
|
err = routes.DeleteTopicSubmit(w,req,user)
|
||||||
case "/topic/stick/submit/":
|
case "/topic/stick/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2159,7 +2190,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(126)
|
co.RouteViewCounter.Bump(128)
|
||||||
err = routes.StickTopicSubmit(w,req,user,extraData)
|
err = routes.StickTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/unstick/submit/":
|
case "/topic/unstick/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2172,7 +2203,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(127)
|
co.RouteViewCounter.Bump(129)
|
||||||
err = routes.UnstickTopicSubmit(w,req,user,extraData)
|
err = routes.UnstickTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/lock/submit/":
|
case "/topic/lock/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
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
|
req.URL.Path += extraData
|
||||||
co.RouteViewCounter.Bump(128)
|
co.RouteViewCounter.Bump(130)
|
||||||
err = routes.LockTopicSubmit(w,req,user)
|
err = routes.LockTopicSubmit(w,req,user)
|
||||||
case "/topic/unlock/submit/":
|
case "/topic/unlock/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2199,7 +2230,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(129)
|
co.RouteViewCounter.Bump(131)
|
||||||
err = routes.UnlockTopicSubmit(w,req,user,extraData)
|
err = routes.UnlockTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/move/submit/":
|
case "/topic/move/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2212,7 +2243,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(130)
|
co.RouteViewCounter.Bump(132)
|
||||||
err = routes.MoveTopicSubmit(w,req,user,extraData)
|
err = routes.MoveTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/like/submit/":
|
case "/topic/like/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2225,7 +2256,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(131)
|
co.RouteViewCounter.Bump(133)
|
||||||
err = routes.LikeTopicSubmit(w,req,user,extraData)
|
err = routes.LikeTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/attach/add/submit/":
|
case "/topic/attach/add/submit/":
|
||||||
err = c.MemberOnly(w,req,user)
|
err = c.MemberOnly(w,req,user)
|
||||||
|
@ -2242,7 +2273,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(132)
|
co.RouteViewCounter.Bump(134)
|
||||||
err = routes.AddAttachToTopicSubmit(w,req,user,extraData)
|
err = routes.AddAttachToTopicSubmit(w,req,user,extraData)
|
||||||
case "/topic/attach/remove/submit/":
|
case "/topic/attach/remove/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2255,10 +2286,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(133)
|
co.RouteViewCounter.Bump(135)
|
||||||
err = routes.RemoveAttachFromTopicSubmit(w,req,user,extraData)
|
err = routes.RemoveAttachFromTopicSubmit(w,req,user,extraData)
|
||||||
default:
|
default:
|
||||||
co.RouteViewCounter.Bump(134)
|
co.RouteViewCounter.Bump(136)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2282,7 +2313,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(135)
|
co.RouteViewCounter.Bump(137)
|
||||||
err = routes.CreateReplySubmit(w,req,user)
|
err = routes.CreateReplySubmit(w,req,user)
|
||||||
case "/reply/edit/submit/":
|
case "/reply/edit/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2295,7 +2326,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(136)
|
co.RouteViewCounter.Bump(138)
|
||||||
err = routes.ReplyEditSubmit(w,req,user,extraData)
|
err = routes.ReplyEditSubmit(w,req,user,extraData)
|
||||||
case "/reply/delete/submit/":
|
case "/reply/delete/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2308,7 +2339,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(137)
|
co.RouteViewCounter.Bump(139)
|
||||||
err = routes.ReplyDeleteSubmit(w,req,user,extraData)
|
err = routes.ReplyDeleteSubmit(w,req,user,extraData)
|
||||||
case "/reply/like/submit/":
|
case "/reply/like/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2321,7 +2352,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(138)
|
co.RouteViewCounter.Bump(140)
|
||||||
err = routes.ReplyLikeSubmit(w,req,user,extraData)
|
err = routes.ReplyLikeSubmit(w,req,user,extraData)
|
||||||
case "/reply/attach/add/submit/":
|
case "/reply/attach/add/submit/":
|
||||||
err = c.MemberOnly(w,req,user)
|
err = c.MemberOnly(w,req,user)
|
||||||
|
@ -2338,7 +2369,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(139)
|
co.RouteViewCounter.Bump(141)
|
||||||
err = routes.AddAttachToReplySubmit(w,req,user,extraData)
|
err = routes.AddAttachToReplySubmit(w,req,user,extraData)
|
||||||
case "/reply/attach/remove/submit/":
|
case "/reply/attach/remove/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2351,7 +2382,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(140)
|
co.RouteViewCounter.Bump(142)
|
||||||
err = routes.RemoveAttachFromReplySubmit(w,req,user,extraData)
|
err = routes.RemoveAttachFromReplySubmit(w,req,user,extraData)
|
||||||
}
|
}
|
||||||
case "/profile":
|
case "/profile":
|
||||||
|
@ -2367,7 +2398,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(141)
|
co.RouteViewCounter.Bump(143)
|
||||||
err = routes.ProfileReplyCreateSubmit(w,req,user)
|
err = routes.ProfileReplyCreateSubmit(w,req,user)
|
||||||
case "/profile/reply/edit/submit/":
|
case "/profile/reply/edit/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2380,7 +2411,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(142)
|
co.RouteViewCounter.Bump(144)
|
||||||
err = routes.ProfileReplyEditSubmit(w,req,user,extraData)
|
err = routes.ProfileReplyEditSubmit(w,req,user,extraData)
|
||||||
case "/profile/reply/delete/submit/":
|
case "/profile/reply/delete/submit/":
|
||||||
err = c.NoSessionMismatch(w,req,user)
|
err = c.NoSessionMismatch(w,req,user)
|
||||||
|
@ -2393,7 +2424,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(143)
|
co.RouteViewCounter.Bump(145)
|
||||||
err = routes.ProfileReplyDeleteSubmit(w,req,user,extraData)
|
err = routes.ProfileReplyDeleteSubmit(w,req,user,extraData)
|
||||||
}
|
}
|
||||||
case "/poll":
|
case "/poll":
|
||||||
|
@ -2409,23 +2440,23 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(144)
|
co.RouteViewCounter.Bump(146)
|
||||||
err = routes.PollVote(w,req,user,extraData)
|
err = routes.PollVote(w,req,user,extraData)
|
||||||
case "/poll/results/":
|
case "/poll/results/":
|
||||||
co.RouteViewCounter.Bump(145)
|
co.RouteViewCounter.Bump(147)
|
||||||
err = routes.PollResults(w,req,user,extraData)
|
err = routes.PollResults(w,req,user,extraData)
|
||||||
}
|
}
|
||||||
case "/accounts":
|
case "/accounts":
|
||||||
switch(req.URL.Path) {
|
switch(req.URL.Path) {
|
||||||
case "/accounts/login/":
|
case "/accounts/login/":
|
||||||
co.RouteViewCounter.Bump(146)
|
co.RouteViewCounter.Bump(148)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = routes.AccountLogin(w,req,user,head)
|
err = routes.AccountLogin(w,req,user,head)
|
||||||
case "/accounts/create/":
|
case "/accounts/create/":
|
||||||
co.RouteViewCounter.Bump(147)
|
co.RouteViewCounter.Bump(149)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2442,7 +2473,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(148)
|
co.RouteViewCounter.Bump(150)
|
||||||
err = routes.AccountLogout(w,req,user)
|
err = routes.AccountLogout(w,req,user)
|
||||||
case "/accounts/login/submit/":
|
case "/accounts/login/submit/":
|
||||||
err = c.ParseForm(w,req,user)
|
err = c.ParseForm(w,req,user)
|
||||||
|
@ -2450,10 +2481,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(149)
|
co.RouteViewCounter.Bump(151)
|
||||||
err = routes.AccountLoginSubmit(w,req,user)
|
err = routes.AccountLoginSubmit(w,req,user)
|
||||||
case "/accounts/mfa_verify/":
|
case "/accounts/mfa_verify/":
|
||||||
co.RouteViewCounter.Bump(150)
|
co.RouteViewCounter.Bump(152)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2465,7 +2496,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(151)
|
co.RouteViewCounter.Bump(153)
|
||||||
err = routes.AccountLoginMFAVerifySubmit(w,req,user)
|
err = routes.AccountLoginMFAVerifySubmit(w,req,user)
|
||||||
case "/accounts/create/submit/":
|
case "/accounts/create/submit/":
|
||||||
err = c.ParseForm(w,req,user)
|
err = c.ParseForm(w,req,user)
|
||||||
|
@ -2473,10 +2504,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(152)
|
co.RouteViewCounter.Bump(154)
|
||||||
err = routes.AccountRegisterSubmit(w,req,user)
|
err = routes.AccountRegisterSubmit(w,req,user)
|
||||||
case "/accounts/password-reset/":
|
case "/accounts/password-reset/":
|
||||||
co.RouteViewCounter.Bump(153)
|
co.RouteViewCounter.Bump(155)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2488,10 +2519,10 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(154)
|
co.RouteViewCounter.Bump(156)
|
||||||
err = routes.AccountPasswordResetSubmit(w,req,user)
|
err = routes.AccountPasswordResetSubmit(w,req,user)
|
||||||
case "/accounts/password-reset/token/":
|
case "/accounts/password-reset/token/":
|
||||||
co.RouteViewCounter.Bump(155)
|
co.RouteViewCounter.Bump(157)
|
||||||
head, err := c.UserCheck(w,req,&user)
|
head, err := c.UserCheck(w,req,&user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -2503,7 +2534,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
co.RouteViewCounter.Bump(156)
|
co.RouteViewCounter.Bump(158)
|
||||||
err = routes.AccountPasswordResetTokenSubmit(w,req,user)
|
err = routes.AccountPasswordResetTokenSubmit(w,req,user)
|
||||||
}
|
}
|
||||||
/*case "/sitemaps": // TODO: Count these views
|
/*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-Type")
|
||||||
h.Del("Content-Encoding")
|
h.Del("Content-Encoding")
|
||||||
}
|
}
|
||||||
co.RouteViewCounter.Bump(158)
|
co.RouteViewCounter.Bump(160)
|
||||||
req.URL.Path += extraData
|
req.URL.Path += extraData
|
||||||
// TODO: Find a way to propagate errors up from this?
|
// TODO: Find a way to propagate errors up from this?
|
||||||
r.UploadHandler(w,req) // TODO: Count these views
|
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
|
// TODO: Add support for favicons and robots.txt files
|
||||||
switch(extraData) {
|
switch(extraData) {
|
||||||
case "robots.txt":
|
case "robots.txt":
|
||||||
co.RouteViewCounter.Bump(160)
|
co.RouteViewCounter.Bump(162)
|
||||||
return routes.RobotsTxt(w,req)
|
return routes.RobotsTxt(w,req)
|
||||||
case "favicon.ico":
|
case "favicon.ico":
|
||||||
gzw, ok := w.(c.GzipResponseWriter)
|
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)
|
routes.StaticFile(w,req)
|
||||||
return nil
|
return nil
|
||||||
case "opensearch.xml":
|
case "opensearch.xml":
|
||||||
co.RouteViewCounter.Bump(162)
|
co.RouteViewCounter.Bump(164)
|
||||||
return routes.OpenSearchXml(w,req)
|
return routes.OpenSearchXml(w,req)
|
||||||
/*case "sitemap.xml":
|
/*case "sitemap.xml":
|
||||||
co.RouteViewCounter.Bump(161)
|
co.RouteViewCounter.Bump(163)
|
||||||
return routes.SitemapXml(w,req)*/
|
return routes.SitemapXml(w,req)*/
|
||||||
}
|
}
|
||||||
return c.NotFound(w,req,nil)
|
return c.NotFound(w,req,nil)
|
||||||
|
@ -2558,7 +2589,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
r.RUnlock()
|
r.RUnlock()
|
||||||
|
|
||||||
if ok {
|
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
|
req.URL.Path += extraData
|
||||||
return handle(w,req,user)
|
return handle(w,req,user)
|
||||||
}
|
}
|
||||||
|
@ -2569,7 +2600,7 @@ func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user c
|
||||||
} else {
|
} else {
|
||||||
r.DumpRequest(req,"Bad Route")
|
r.DumpRequest(req,"Bad Route")
|
||||||
}
|
}
|
||||||
co.RouteViewCounter.Bump(163)
|
co.RouteViewCounter.Bump(165)
|
||||||
return c.NotFound(w,req,nil)
|
return c.NotFound(w,req,nil)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -791,7 +791,7 @@ func BenchmarkQueryTopicParallel(b *testing.B) {
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
var tu c.TopicUser
|
var tu c.TopicUser
|
||||||
for pb.Next() {
|
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 {
|
if err == ErrNoRows {
|
||||||
log.Fatal("No rows found!")
|
log.Fatal("No rows found!")
|
||||||
return
|
return
|
||||||
|
@ -812,14 +812,14 @@ func BenchmarkQueryPreparedTopicParallel(b *testing.B) {
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
var tu c.TopicUser
|
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 {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
defer getTopicUser.Close()
|
defer getTopicUser.Close()
|
||||||
|
|
||||||
for pb.Next() {
|
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 {
|
if err == ErrNoRows {
|
||||||
b.Fatal("No rows found!")
|
b.Fatal("No rows found!")
|
||||||
return
|
return
|
||||||
|
@ -873,7 +873,7 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
||||||
var tu c.TopicUser
|
var tu c.TopicUser
|
||||||
b.Run("topic", func(b *testing.B) {
|
b.Run("topic", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
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 {
|
if err == ErrNoRows {
|
||||||
b.Fatal("No rows found!")
|
b.Fatal("No rows found!")
|
||||||
return
|
return
|
||||||
|
@ -885,7 +885,7 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
||||||
})
|
})
|
||||||
b.Run("topic_replies", func(b *testing.B) {
|
b.Run("topic_replies", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
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 {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
return
|
return
|
||||||
|
@ -907,13 +907,13 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
||||||
var group int
|
var group int
|
||||||
b.Run("topic_replies_scan", func(b *testing.B) {
|
b.Run("topic_replies_scan", func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
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 {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for rows.Next() {
|
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 {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
return
|
return
|
||||||
|
@ -933,36 +933,19 @@ func BenchmarkQueriesSerial(b *testing.B) {
|
||||||
// TODO: Take the attachment system into account in these parser benches
|
// TODO: Take the attachment system into account in these parser benches
|
||||||
func BenchmarkParserSerial(b *testing.B) {
|
func BenchmarkParserSerial(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.Run("empty_post", func(b *testing.B) {
|
f := func(name, msg string) func(b *testing.B) {
|
||||||
|
return func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = c.ParseMessage("", 0, "")
|
_ = 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, "")
|
|
||||||
}
|
}
|
||||||
})
|
f("empty_post","")
|
||||||
b.Run("five_smilies", func(b *testing.B) {
|
f("short_post","Hey everyone, how's it going?")
|
||||||
for i := 0; i < b.N; i++ {
|
f("one_smily","Hey everyone, how's it going? :)")
|
||||||
_ = c.ParseMessage("Hey everyone, how's it going? :):):):):)", 0, "")
|
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? :):):):):):):):):):):):):):):):):):):):)")
|
||||||
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, "")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkBBCodePluginWithRegexpSerial(b *testing.B) {
|
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.
|
// TODO: Fix this hack and make the results a bit more reproducible, push the tests further in the process.
|
||||||
for _, item := range l.Items {
|
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 != "" {
|
if item.Name != "" {
|
||||||
t.Error("Name: ", 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", "<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>")
|
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 {
|
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 != "" {
|
if item.Name != "" {
|
||||||
t.Error("Name: ", 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))
|
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>"
|
expect := "<a href='/topic/1'>#nnid-1</a>"
|
||||||
if res != expect {
|
if res != expect {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
|
@ -356,7 +356,7 @@ func TestParser(t *testing.T) {
|
||||||
}
|
}
|
||||||
c.WriteURL(sb, c.BuildTopicURL("", tid), "#longidnameneedtooverflowhack-"+strconv.Itoa(tid))
|
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>"
|
expect = "<a href='/topic/1'>#longidnameneedtooverflowhack-1</a>"
|
||||||
if res != expect {
|
if res != expect {
|
||||||
t.Error("Bad output:", "'"+res+"'")
|
t.Error("Bad output:", "'"+res+"'")
|
||||||
|
|
|
@ -42,6 +42,7 @@ func init() {
|
||||||
addPatch(25, patch25)
|
addPatch(25, patch25)
|
||||||
addPatch(26, patch26)
|
addPatch(26, patch26)
|
||||||
addPatch(27, patch27)
|
addPatch(27, patch27)
|
||||||
|
addPatch(28, patch28)
|
||||||
}
|
}
|
||||||
|
|
||||||
func patch0(scanner *bufio.Scanner) (err error) {
|
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))
|
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)"),
|
UploadAction("AvatarSubmit", "/avatar/submit/").MaxSizeVar("int(c.Config.MaxRequestSize)"),
|
||||||
Action("RevokeAvatarSubmit", "/avatar/revoke/submit/"),
|
Action("RevokeAvatarSubmit", "/avatar/revoke/submit/"),
|
||||||
Action("UsernameSubmit", "/username/submit/"), // TODO: Full test this
|
Action("UsernameSubmit", "/username/submit/"), // TODO: Full test this
|
||||||
|
MView("Privacy", "/privacy/"),
|
||||||
|
Action("PrivacySubmit", "/privacy/submit/"),
|
||||||
MView("MFA", "/mfa/"),
|
MView("MFA", "/mfa/"),
|
||||||
MView("MFASetup", "/mfa/setup/"),
|
MView("MFASetup", "/mfa/setup/"),
|
||||||
Action("MFASetupSubmit", "/mfa/setup/submit/"),
|
Action("MFASetupSubmit", "/mfa/setup/submit/"),
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
p "github.com/Azareal/Gosora/common/phrases"
|
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
|
// A blank list to fill out that parameter in Page for routes which don't use it
|
||||||
|
@ -235,7 +235,7 @@ func AccountRegisterSubmit(w http.ResponseWriter, r *http.Request, user c.User)
|
||||||
if isNumeric(nameBits[0]) {
|
if isNumeric(nameBits[0]) {
|
||||||
regError(p.GetErrorPhrase("register_first_word_numeric"), "numeric-name")
|
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")
|
regError(p.GetErrorPhrase("register_url_username"), "url-name")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,11 +423,11 @@ func AccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user c.User
|
||||||
return c.NoPermissions(w, r, 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 {
|
if ferr != nil {
|
||||||
return ferr
|
return ferr
|
||||||
}
|
}
|
||||||
ferr = c.ChangeAvatar("." + ext, w, r, user)
|
ferr = c.ChangeAvatar("."+ext, w, r, user)
|
||||||
if ferr != nil {
|
if ferr != nil {
|
||||||
return ferr
|
return ferr
|
||||||
}
|
}
|
||||||
|
@ -572,6 +572,37 @@ func AccountEditMFADisableSubmit(w http.ResponseWriter, r *http.Request, user c.
|
||||||
return nil
|
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 {
|
func AccountEditEmail(w http.ResponseWriter, r *http.Request, user c.User, h *c.Header) c.RouteError {
|
||||||
accountEditHead("account_email", w, r, &user, h)
|
accountEditHead("account_email", w, r, &user, h)
|
||||||
emails, err := c.Emails.GetEmailsByUser(&user)
|
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 {
|
func AccountEditEmailAddSubmit(w http.ResponseWriter, r *http.Request, user c.User) c.RouteError {
|
||||||
email := r.PostFormValue("email")
|
email := r.PostFormValue("email")
|
||||||
|
|
||||||
_, err := c.Emails.Get(&user, email)
|
_, err := c.Emails.Get(&user, email)
|
||||||
if err == nil {
|
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 {
|
} else if err != sql.ErrNoRows && err != nil {
|
||||||
return c.InternalError(err, w, r)
|
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)
|
err = c.Emails.Add(user.ID, email, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err,w,r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
if c.Site.EnableEmails {
|
if c.Site.EnableEmails {
|
||||||
err = c.SendValidationEmail(user.Name, email, token)
|
err = c.SendValidationEmail(user.Name, email, token)
|
||||||
|
@ -635,17 +665,17 @@ func AccountEditEmailRemoveSubmit(w http.ResponseWriter, r *http.Request, user c
|
||||||
// Quick and dirty check
|
// Quick and dirty check
|
||||||
_, err := c.Emails.Get(&user, email)
|
_, err := c.Emails.Get(&user, email)
|
||||||
if err == sql.ErrNoRows {
|
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 {
|
} else if err != nil {
|
||||||
return c.InternalError(err, w, r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
if headerLite.Settings["activation_type"] == 2 && user.Email == email {
|
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)
|
err = c.Emails.Delete(user.ID, email)
|
||||||
if err != nil {
|
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)
|
http.Redirect(w, r, "/user/edit/email/?removed=1", http.StatusSeeOther)
|
||||||
|
@ -729,13 +759,13 @@ func AccountBlocked(w http.ResponseWriter, r *http.Request, user c.User, h *c.He
|
||||||
for _, uid := range uids {
|
for _, uid := range uids {
|
||||||
u, err := c.Users.Get(uid)
|
u, err := c.Users.Get(uid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.InternalError(err,w,r)
|
return c.InternalError(err, w, r)
|
||||||
}
|
}
|
||||||
blocks = append(blocks, u)
|
blocks = append(blocks, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageList := c.Paginate(page, lastPage, 5)
|
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)
|
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
|
replyLiked := false
|
||||||
replyLikeCount := 0
|
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()
|
ru.Init()
|
||||||
|
|
||||||
group, err := c.Groups.Get(ru.Group)
|
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"))
|
prid, _ := strconv.Atoi(r.FormValue("prid"))
|
||||||
if js && (prid == 0 || rids[0] == 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 {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
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 {
|
if !js {
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(topic.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(topic.ID)+"#reply-"+strconv.Itoa(rid), http.StatusSeeOther)
|
||||||
} else {
|
} 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 {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,17 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
//"fmt"
|
//"fmt"
|
||||||
|
"golang.org/x/image/tiff"
|
||||||
|
"image"
|
||||||
|
"image/gif"
|
||||||
|
"image/jpeg"
|
||||||
|
"image/png"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"image"
|
|
||||||
"image/gif"
|
|
||||||
"image/jpeg"
|
|
||||||
"image/png"
|
|
||||||
"golang.org/x/image/tiff"
|
|
||||||
|
|
||||||
c "github.com/Azareal/Gosora/common"
|
c "github.com/Azareal/Gosora/common"
|
||||||
"github.com/Azareal/Gosora/common/counters"
|
"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)
|
header.Path = c.BuildTopicURL(c.NameToSlug(topic.Title), topic.ID)
|
||||||
|
|
||||||
// TODO: Cache ContentHTML when possible?
|
// 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.
|
// TODO: Do this more efficiently by avoiding the allocations entirely in ParseMessage, if there's nothing to do.
|
||||||
if topic.ContentHTML == topic.Content {
|
if topic.ContentHTML == topic.Content {
|
||||||
topic.ContentHTML = topic.Content
|
topic.ContentHTML = topic.Content
|
||||||
}
|
}
|
||||||
topic.ContentLines = strings.Count(topic.Content, "\n")
|
topic.ContentLines = strings.Count(topic.Content, "\n")
|
||||||
|
|
||||||
|
if len(topic.Content) > 200 {
|
||||||
|
header.OGDesc = topic.Content[:197] + "..."
|
||||||
|
} else {
|
||||||
header.OGDesc = topic.Content
|
header.OGDesc = topic.Content
|
||||||
if len(header.OGDesc) > 200 {
|
|
||||||
header.OGDesc = header.OGDesc[:197] + "..."
|
|
||||||
}
|
}
|
||||||
|
|
||||||
postGroup, err := c.Groups.Get(topic.Group)
|
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-") {
|
if strings.HasPrefix(r.URL.Fragment, "post-") {
|
||||||
pFrag, _ = strconv.Atoi(strings.TrimPrefix(r.URL.Fragment, "post-"))
|
pFrag, _ = strconv.Atoi(strings.TrimPrefix(r.URL.Fragment, "post-"))
|
||||||
}
|
}
|
||||||
|
|
||||||
rlist, ogdesc, err := topic.Replies(offset, pFrag, &user)
|
rlist, ogdesc, err := topic.Replies(offset, pFrag, &user)
|
||||||
if err == sql.ErrNoRows {
|
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)
|
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 {
|
} else {
|
||||||
img, _, err := image.Decode(inFile)
|
img, _, err := image.Decode(inFile)
|
||||||
if err != nil {
|
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)
|
outFile, err := os.Create(dir + filename)
|
||||||
|
@ -524,13 +524,13 @@ func uploadFilesWithHash(w http.ResponseWriter, r *http.Request, user c.User, di
|
||||||
err = gif.Encode(outFile, img, nil)
|
err = gif.Encode(outFile, img, nil)
|
||||||
case "png":
|
case "png":
|
||||||
err = png.Encode(outFile, img)
|
err = png.Encode(outFile, img)
|
||||||
case "tiff","tif":
|
case "tiff", "tif":
|
||||||
err = tiff.Encode(outFile,img,nil)
|
err = tiff.Encode(outFile, img, nil)
|
||||||
default:
|
default:
|
||||||
err = jpeg.Encode(outFile, img, nil)
|
err = jpeg.Encode(outFile, img, nil)
|
||||||
}
|
}
|
||||||
if err != 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 {
|
if !js {
|
||||||
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
http.Redirect(w, r, "/topic/"+strconv.Itoa(tid), http.StatusSeeOther)
|
||||||
} else {
|
} 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 {
|
if err != nil {
|
||||||
return c.InternalErrorJSQ(err, w, r, js)
|
return c.InternalErrorJSQ(err, w, r, js)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ CREATE TABLE [users] (
|
||||||
[lastActiveAt] datetime not null,
|
[lastActiveAt] datetime not null,
|
||||||
[session] nvarchar (200) DEFAULT '' not null,
|
[session] nvarchar (200) DEFAULT '' not null,
|
||||||
[last_ip] nvarchar (200) DEFAULT '0.0.0.0.0' 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,
|
[email] nvarchar (200) DEFAULT '' not null,
|
||||||
[avatar] nvarchar (100) DEFAULT '' not null,
|
[avatar] nvarchar (100) DEFAULT '' not null,
|
||||||
[message] nvarchar (MAX) DEFAULT '' not null,
|
[message] nvarchar (MAX) DEFAULT '' not null,
|
||||||
|
|
|
@ -10,6 +10,7 @@ CREATE TABLE `users` (
|
||||||
`lastActiveAt` datetime not null,
|
`lastActiveAt` datetime not null,
|
||||||
`session` varchar(200) DEFAULT '' not null,
|
`session` varchar(200) DEFAULT '' not null,
|
||||||
`last_ip` varchar(200) DEFAULT '0.0.0.0.0' 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,
|
`email` varchar(200) DEFAULT '' not null,
|
||||||
`avatar` varchar(100) DEFAULT '' not null,
|
`avatar` varchar(100) DEFAULT '' not null,
|
||||||
`message` text not null,
|
`message` text not null,
|
||||||
|
|
|
@ -10,6 +10,7 @@ CREATE TABLE "users" (
|
||||||
`lastActiveAt` timestamp not null,
|
`lastActiveAt` timestamp not null,
|
||||||
`session` varchar (200) DEFAULT '' not null,
|
`session` varchar (200) DEFAULT '' not null,
|
||||||
`last_ip` varchar (200) DEFAULT '0.0.0.0.0' 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,
|
`email` varchar (200) DEFAULT '' not null,
|
||||||
`avatar` varchar (100) DEFAULT '' not null,
|
`avatar` varchar (100) DEFAULT '' not null,
|
||||||
`message` text DEFAULT '' not null,
|
`message` text DEFAULT '' not null,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<div class="colstack_item rowmenu">
|
<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/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/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/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/logins/">{{lang "account_menu_logins"}}</a></div>
|
||||||
<div class="rowitem passive"><a href="/user/edit/blocked/">{{lang "account_menu_blocked"}}</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