diff --git a/client/main.go b/client/main.go index 6257c7dd..b1458716 100644 --- a/client/main.go +++ b/client/main.go @@ -4,7 +4,8 @@ import ( "bytes" "../common" - "../tmpl_gen/client" + "../common/alerts" + "../tmpl_gen" "github.com/gopherjs/gopherjs/js" ) @@ -19,7 +20,7 @@ func main() { js.Global.Set("renderAlert", func(asid int, path string, msg string, avatar string) string { var buf bytes.Buffer - alertItem := common.AlertItem{asid, path, msg, avatar} + alertItem := alerts.AlertItem{asid, path, msg, avatar} err := tmpl.Template_alert(alertItem, &buf) if err != nil { println(err.Error()) diff --git a/common/alerts/tmpls.go b/common/alerts/tmpls.go new file mode 100644 index 00000000..d391ccdf --- /dev/null +++ b/common/alerts/tmpls.go @@ -0,0 +1,10 @@ +package alerts + +// TODO: Move the other alert related stuff to package alerts, maybe move notification logic here too? + +type AlertItem struct { + ASID int + Path string + Message string + Avatar string +} diff --git a/common/auth.go b/common/auth.go index 09f0c626..63b70a34 100644 --- a/common/auth.go +++ b/common/auth.go @@ -101,18 +101,18 @@ func (auth *DefaultAuth) ForceLogout(uid int) error { // Logout logs you out of the computer you requested the logout for, but not the other computers you're logged in with func (auth *DefaultAuth) Logout(w http.ResponseWriter, _ int) { - cookie := http.Cookie{Name: "uid", Value: "", Path: "/", MaxAge: Year} + cookie := http.Cookie{Name: "uid", Value: "", Path: "/", MaxAge: int(Year)} http.SetCookie(w, &cookie) - cookie = http.Cookie{Name: "session", Value: "", Path: "/", MaxAge: Year} + cookie = http.Cookie{Name: "session", Value: "", Path: "/", MaxAge: int(Year)} http.SetCookie(w, &cookie) } // TODO: Set the cookie domain // SetCookies sets the two cookies required for the current user to be recognised as a specific user in future requests func (auth *DefaultAuth) SetCookies(w http.ResponseWriter, uid int, session string) { - cookie := http.Cookie{Name: "uid", Value: strconv.Itoa(uid), Path: "/", MaxAge: Year} + cookie := http.Cookie{Name: "uid", Value: strconv.Itoa(uid), Path: "/", MaxAge: int(Year)} http.SetCookie(w, &cookie) - cookie = http.Cookie{Name: "session", Value: session, Path: "/", MaxAge: Year} + cookie = http.Cookie{Name: "session", Value: session, Path: "/", MaxAge: int(Year)} http.SetCookie(w, &cookie) } diff --git a/common/common.go b/common/common.go index f19bd51a..81fd62d4 100644 --- a/common/common.go +++ b/common/common.go @@ -8,16 +8,16 @@ import ( ) // nolint I don't want to write comments for each of these o.o -const Hour int = 60 * 60 -const Day int = Hour * 24 -const Week int = Day * 7 -const Month int = Day * 30 -const Year int = Day * 365 -const Kilobyte int = 1024 -const Megabyte int = Kilobyte * 1024 -const Gigabyte int = Megabyte * 1024 -const Terabyte int = Gigabyte * 1024 -const Petabyte int = Terabyte * 1024 +const Hour int64 = 60 * 60 +const Day int64 = Hour * 24 +const Week int64 = Day * 7 +const Month int64 = Day * 30 +const Year int64 = Day * 365 +const Kilobyte int64 = 1024 +const Megabyte int64 = Kilobyte * 1024 +const Gigabyte int64 = Megabyte * 1024 +const Terabyte int64 = Gigabyte * 1024 +const Petabyte int64 = Terabyte * 1024 const SaltLength int = 32 const SessionLength int = 80 diff --git a/common/files.go b/common/files.go index 07f96037..e2d3500a 100644 --- a/common/files.go +++ b/common/files.go @@ -2,6 +2,8 @@ package common import ( "bytes" + "errors" + "fmt" "mime" "strings" "sync" @@ -11,6 +13,8 @@ import ( "net/http" "os" "path/filepath" + + "../tmpl_gen" ) type SFileList map[string]SFile @@ -33,6 +37,153 @@ type CSSData struct { Phrases map[string]string } +func (list SFileList) JSTmplInit() error { + var fragMap = make(map[string][][]byte) + fragMap["alert"] = tmpl.Get_alert_frags() // TODO: Add a generic fetch function, so we don't rely on the presence of the template files for this + fmt.Println("fragMap: ", fragMap) + return filepath.Walk("./tmpl_gen", func(path string, f os.FileInfo, err error) error { + if f.IsDir() { + return nil + } + if strings.HasSuffix(path, "template_list.go") { + return nil + } + + path = strings.Replace(path, "\\", "/", -1) + DebugLog("Processing client template " + path) + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + var replace = func(data []byte, replaceThis string, withThis string) []byte { + return bytes.Replace(data, []byte(replaceThis), []byte(withThis), -1) + } + + startIndex, hasFunc := skipAllUntilCharsExist(data, 0, []byte("func Template")) + if !hasFunc { + return errors.New("no template function found") + } + data = data[startIndex-len([]byte("func Template")):] + data = replace(data, "func ", "function ") + data = replace(data, " error {\n", " {\nlet out = \"\"\n") + spaceIndex, hasSpace := skipUntilIfExists(data, 10, ' ') + if !hasSpace { + return errors.New("no spaces found after the template function name") + } + endBrace, hasBrace := skipUntilIfExists(data, spaceIndex, ')') + if !hasBrace { + return errors.New("no right brace found after the template function name") + } + fmt.Println("spaceIndex: ", spaceIndex) + fmt.Println("endBrace: ", endBrace) + fmt.Println("string(data[spaceIndex:endBrace]): ", string(data[spaceIndex:endBrace])) + preLen := len(data) + data = replace(data, string(data[spaceIndex:endBrace]), "") + data = replace(data, "))\n", "\n") + endBrace -= preLen - len(data) // Offset it as we've deleted portions + + var showPos = func(data []byte, index int) (out string) { + out = "[" + for j, char := range data { + if index == j { + out += "[" + string(char) + "] " + } else { + out += string(char) + " " + } + } + return out + "]" + } + + // ? Can we just use a regex? I'm thinking of going more efficient, or just outright rolling wasm, this is a temp hack in a place where performance doesn't particularly matter + var each = func(phrase string, handle func(index int)) { + fmt.Println("find each '" + phrase + "'") + var index = endBrace + var foundIt bool + for { + fmt.Println("in index: ", index) + fmt.Println("pos: ", showPos(data, index)) + index, foundIt = skipAllUntilCharsExist(data, index, []byte(phrase)) + if !foundIt { + break + } + handle(index) + } + } + each("strconv.Itoa(", func(index int) { + braceAt, hasEndBrace := skipUntilIfExists(data, index, ')') + // TODO: Make sure we don't go onto the next line in case someone misplaced a brace + if hasEndBrace { + data[braceAt] = ' ' // Blank it + } + }) + each("w.Write([]byte(", func(index int) { + braceAt, hasEndBrace := skipUntilIfExists(data, index, ')') + // TODO: Make sure we don't go onto the next line in case someone misplaced a brace + if hasEndBrace { + data[braceAt] = ' ' // Blank it + } + braceAt, hasEndBrace = skipUntilIfExists(data, braceAt, ')') + if hasEndBrace { + data[braceAt] = ' ' // Blank this one too + } + }) + each("w.Write(", func(index int) { + braceAt, hasEndBrace := skipUntilIfExists(data, index, ')') + // TODO: Make sure we don't go onto the next line in case someone misplaced a brace + if hasEndBrace { + data[braceAt] = ' ' // Blank it + } + }) + each("if ", func(index int) { + fmt.Println("if index: ", index) + braceAt, hasBrace := skipUntilIfExists(data, index, '{') + if hasBrace { + if data[braceAt-1] != ' ' { + panic("couldn't find space before brace, found ' " + string(data[braceAt-1]) + "' instead") + } + data[braceAt-1] = ')' // Drop a brace here to satisfy JS + } + }) + data = replace(data, "w.Write([]byte(", "out += ") + data = replace(data, "w.Write(", "out += ") + data = replace(data, "strconv.Itoa(", "") + data = replace(data, "if ", "if(") + data = replace(data, "return nil", "return out") + data = replace(data, " )", ")") + data = replace(data, " \n", "\n") + data = replace(data, "\n", ";\n") + data = replace(data, "{;", "{") + data = replace(data, "};", "}") + data = replace(data, ";;", ";") + + path = strings.TrimPrefix(path, "tmpl_gen/") + tmplName := strings.TrimSuffix(path, ".go") + fragset, ok := fragMap[strings.TrimPrefix(tmplName, "template_")] + if !ok { + fmt.Println("tmplName: ", tmplName) + return errors.New("couldn't find template in fragmap") + } + + var sfrags = []byte("let alert_frags = [];\n") + for _, frags := range fragset { + sfrags = append(sfrags, []byte("alert_frags.push(`"+string(frags)+"`);\n")...) + } + data = append(sfrags, data...) + data = replace(data, "\n;", "\n") + + path = tmplName + ".js" + DebugLog("js path: ", path) + var ext = filepath.Ext("/tmpl_gen/" + path) + gzipData := compressBytesGzip(data) + + list.Set("/static/"+path, SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}) + + DebugLogf("Added the '%s' static file.", path) + return nil + }) +} + func (list SFileList) Init() error { return filepath.Walk("./public", func(path string, f os.FileInfo, err error) error { if f.IsDir() { diff --git a/common/menus.go b/common/menus.go index 0297694c..2ab9c986 100644 --- a/common/menus.go +++ b/common/menus.go @@ -168,6 +168,13 @@ func nextCharIs(tmplData []byte, i int, expects byte) bool { return tmplData[i+1] == expects } +func peekNextChar(tmplData []byte, i int) byte { + if len(tmplData) <= (i + 1) { + return 0 + } + return tmplData[i+1] +} + func skipUntilIfExists(tmplData []byte, i int, expects byte) (newI int, hasIt bool) { j := i for ; j < len(tmplData); j++ { @@ -182,14 +189,47 @@ func skipUntilCharsExist(tmplData []byte, i int, expects []byte) (newI int, hasI j := i expectIndex := 0 for ; j < len(tmplData) && expectIndex < len(expects); j++ { + //fmt.Println("tmplData[j]: ", string(tmplData[j])) if tmplData[j] != expects[expectIndex] { return j, false } + //fmt.Printf("found %+v at %d\n", string(expects[expectIndex]), expectIndex) expectIndex++ } return j, true } +func skipAllUntilCharsExist(tmplData []byte, i int, expects []byte) (newI int, hasIt bool) { + j := i + expectIndex := 0 + //fmt.Printf("tmplData: %+v\n", string(tmplData)) + for ; j < len(tmplData) && expectIndex < len(expects); j++ { + //fmt.Println("tmplData[j]: ", string(tmplData[j]) + " ") + if tmplData[j] == expects[expectIndex] { + //fmt.Printf("expects[expectIndex]: %+v - %d\n", string(expects[expectIndex]), expectIndex) + expectIndex++ + if len(expects) <= expectIndex { + //fmt.Println("breaking") + break + } + } else { + /*if expectIndex != 0 { + fmt.Println("broke expectations") + fmt.Println("expected: ", string(expects[expectIndex])) + fmt.Println("got: ", string(tmplData[j])) + fmt.Println("next: ", string(peekNextChar(tmplData, j))) + fmt.Println("next: ", string(peekNextChar(tmplData, j+1))) + fmt.Println("next: ", string(peekNextChar(tmplData, j+2))) + fmt.Println("next: ", string(peekNextChar(tmplData, j+3))) + }*/ + expectIndex = 0 + } + } + //fmt.Println("len(expects): ", len(expects)) + //fmt.Println("expectIndex: ", expectIndex) + return j, len(expects) == expectIndex +} + type menuRenderItem struct { Type int // 0: text, 1: variable Index int diff --git a/common/pages.go b/common/pages.go index ca55505c..86a82ead 100644 --- a/common/pages.go +++ b/common/pages.go @@ -59,13 +59,6 @@ type ExtData struct { sync.RWMutex } -type AlertItem struct { - ASID int - Path string - Message string - Avatar string -} - type Page struct { Title string CurrentUser User diff --git a/common/phrases.go b/common/phrases.go index ba8c48bf..27aafb38 100644 --- a/common/phrases.go +++ b/common/phrases.go @@ -100,7 +100,6 @@ func InitPhrases() error { return nil }) - if err != nil { return err } diff --git a/common/profile_reply_store.go b/common/profile_reply_store.go index 185f371f..c9b96d2a 100644 --- a/common/profile_reply_store.go +++ b/common/profile_reply_store.go @@ -20,8 +20,7 @@ type SQLProfileReplyStore struct { create *sql.Stmt } -func NewSQLProfileReplyStore() (*SQLProfileReplyStore, error) { - acc := qgen.Builder.Accumulator() +func NewSQLProfileReplyStore(acc *qgen.Accumulator) (*SQLProfileReplyStore, error) { return &SQLProfileReplyStore{ get: acc.Select("users_replies").Columns("uid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress").Where("rid = ?").Prepare(), create: acc.Insert("users_replies").Columns("uid, content, parsed_content, createdAt, createdBy, ipaddress").Fields("?,?,?,UTC_TIMESTAMP(),?,?").Prepare(), diff --git a/common/reply_store.go b/common/reply_store.go index e73a9257..1f3eb8ff 100644 --- a/common/reply_store.go +++ b/common/reply_store.go @@ -15,8 +15,7 @@ type SQLReplyStore struct { create *sql.Stmt } -func NewSQLReplyStore() (*SQLReplyStore, error) { - acc := qgen.Builder.Accumulator() +func NewSQLReplyStore(acc *qgen.Accumulator) (*SQLReplyStore, error) { return &SQLReplyStore{ get: acc.Select("replies").Columns("tid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount").Where("rid = ?").Prepare(), create: acc.Insert("replies").Columns("tid, content, parsed_content, createdAt, lastUpdated, ipaddress, words, createdBy").Fields("?,?,?,UTC_TIMESTAMP(),UTC_TIMESTAMP(),?,?,?").Prepare(), diff --git a/common/site.go b/common/site.go index 22b237c5..3b2ddb5d 100644 --- a/common/site.go +++ b/common/site.go @@ -52,7 +52,7 @@ type config struct { SslPrivkey string SslFullchain string - MaxRequestSize int + MaxRequestSize int64 CacheTopicUser int UserCacheCapacity int TopicCacheCapacity int diff --git a/common/template_init.go b/common/template_init.go index fe46407d..4f28262a 100644 --- a/common/template_init.go +++ b/common/template_init.go @@ -10,6 +10,7 @@ import ( "sync" "time" + "./alerts" "./templates" ) @@ -297,24 +298,25 @@ func CompileJSTemplates() error { config.Minify = Config.MinifyTemplates config.SuperDebug = Dev.TemplateDebug config.SkipHandles = true + config.SkipInitBlock = true config.PackageName = "tmpl" c := tmpl.NewCTemplateSet() c.SetConfig(config) c.SetBaseImportMap(map[string]string{ - "io": "io", - "../../common": "../../common", + "io": "io", + "../common/alerts": "../common/alerts", }) var varList = make(map[string]tmpl.VarItem) // TODO: Check what sort of path is sent exactly and use it here - alertItem := AlertItem{Avatar: "", ASID: 1, Path: "/", Message: "uh oh, something happened"} - alertTmpl, err := c.Compile("alert.html", "templates/", "common.AlertItem", alertItem, varList) + alertItem := alerts.AlertItem{Avatar: "", ASID: 1, Path: "/", Message: "uh oh, something happened"} + alertTmpl, err := c.Compile("alert.html", "templates/", "alerts.AlertItem", alertItem, varList) if err != nil { return err } - var dirPrefix = "./tmpl_gen/client/" + var dirPrefix = "./tmpl_gen/" var wg sync.WaitGroup var writeTemplate = func(name string, content string) { log.Print("Writing template '" + name + "'") @@ -343,6 +345,7 @@ func writeTemplateList(c *tmpl.CTemplateSet, wg *sync.WaitGroup, prefix string) out := "package " + c.GetConfig().PackageName + "\n\n" for templateName, count := range c.TemplateFragmentCount { out += "var " + templateName + "_frags = make([][]byte," + strconv.Itoa(count) + ")\n" + out += "\n// nolint\nfunc Get_" + templateName + "_frags() [][]byte {\nreturn " + templateName + "_frags\n}\n" } out += "\n// nolint\nfunc init() {\n" + c.FragOut + "}\n" err := writeFile(prefix+"template_list.go", out) diff --git a/common/templates/templates.go b/common/templates/templates.go index 54c11a33..c8be011d 100644 --- a/common/templates/templates.go +++ b/common/templates/templates.go @@ -107,7 +107,6 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe if c.config.Debug { fmt.Println("Compiling template '" + name + "'") } - c.importMap = map[string]string{} for index, item := range c.baseImportMap { c.importMap[index] = item @@ -135,7 +134,6 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe return "", err } } - content := string(res) if c.config.Minify { content = minify(content) @@ -149,7 +147,6 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe } c.detail(name) - out = "" fname := strings.TrimSuffix(name, filepath.Ext(name)) c.templateList = map[string]*parse.Tree{fname: tree} varholder := "tmpl_" + fname + "_vars" @@ -212,7 +209,7 @@ func (c *CTemplateSet) Compile(name string, fileDir string, expects string, expe if len(c.langIndexToName) > 0 { fout += "var phrases = common.GetTmplPhrasesBytes(" + fname + "_tmpl_phrase_id)\n" } - fout += varString + out + "\treturn nil\n}\n" + fout += varString + out + "return nil\n}\n" fout = strings.Replace(fout, `)) w.Write([]byte(`, " + ", -1) @@ -278,7 +275,6 @@ func (c *CTemplateSet) compileSwitch(varholder string, holdreflect reflect.Value c.detail("Selected Branch 1") return out + "\n" } - c.detail("Selected Branch 2") return out + " else {\n" + c.compileSwitch(varholder, holdreflect, templateName, node.ElseList) + "}\n" case *parse.ListNode: @@ -947,7 +943,6 @@ func (c *CTemplateSet) compileSubtemplate(pvarholder string, pholdreflect reflec log.Fatal(err) } } - content := string(res) if c.config.Minify { content = minify(content) diff --git a/common/utils.go b/common/utils.go index 6b84fd27..8071d2d6 100644 --- a/common/utils.go +++ b/common/utils.go @@ -148,10 +148,11 @@ func ConvertByteInUnit(bytes float64, unit string) (count float64) { } // TODO: Write a test for this +// TODO: Re-add T as int64 func ConvertUnit(num int) (int, string) { switch { - case num >= 1000000000000: - return num / 1000000000000, "T" + //case num >= 1000000000000: + // return num / 1000000000000, "T" case num >= 1000000000: return num / 1000000000, "B" case num >= 1000000: @@ -164,12 +165,14 @@ func ConvertUnit(num int) (int, string) { } // TODO: Write a test for this +// TODO: Re-add quadrillion as int64 +// TODO: Re-add trillion as int64 func ConvertFriendlyUnit(num int) (int, string) { switch { - case num >= 1000000000000000: - return 0, " quadrillion" - case num >= 1000000000000: - return 0, " trillion" + //case num >= 1000000000000000: + // return 0, " quadrillion" + //case num >= 1000000000000: + // return 0, " trillion" case num >= 1000000000: return num / 1000000000, " billion" case num >= 1000000: diff --git a/gen_mssql.go b/gen_mssql.go index 352b75a6..03e2a5b2 100644 --- a/gen_mssql.go +++ b/gen_mssql.go @@ -9,7 +9,6 @@ import "./common" // nolint type Stmts struct { - getPassword *sql.Stmt isPluginActive *sql.Stmt getUsersOffset *sql.Stmt isThemeDefault *sql.Stmt @@ -59,14 +58,6 @@ type Stmts struct { func _gen_mssql() (err error) { common.DebugLog("Building the generated statements") - common.DebugLog("Preparing getPassword statement.") - stmts.getPassword, err = db.Prepare("SELECT [password],[salt] FROM [users] WHERE [uid] = ?1") - if err != nil { - log.Print("Error in getPassword statement.") - log.Print("Bad Query: ","SELECT [password],[salt] FROM [users] WHERE [uid] = ?1") - return err - } - common.DebugLog("Preparing isPluginActive statement.") stmts.isPluginActive, err = db.Prepare("SELECT [active] FROM [plugins] WHERE [uname] = ?1") if err != nil { diff --git a/gen_mysql.go b/gen_mysql.go index b0c40975..18d71b9e 100644 --- a/gen_mysql.go +++ b/gen_mysql.go @@ -11,7 +11,6 @@ import "./common" // nolint type Stmts struct { - getPassword *sql.Stmt isPluginActive *sql.Stmt getUsersOffset *sql.Stmt isThemeDefault *sql.Stmt @@ -61,13 +60,6 @@ type Stmts struct { func _gen_mysql() (err error) { common.DebugLog("Building the generated statements") - common.DebugLog("Preparing getPassword statement.") - stmts.getPassword, err = db.Prepare("SELECT `password`,`salt` FROM `users` WHERE `uid` = ?") - if err != nil { - log.Print("Error in getPassword statement.") - return err - } - common.DebugLog("Preparing isPluginActive statement.") stmts.isPluginActive, err = db.Prepare("SELECT `active` FROM `plugins` WHERE `uname` = ?") if err != nil { diff --git a/gen_router.go b/gen_router.go index 23427049..3dde6ba4 100644 --- a/gen_router.go +++ b/gen_router.go @@ -89,11 +89,11 @@ var RouteMap = map[string]interface{}{ "routePanelDebug": routePanelDebug, "routePanelDashboard": routePanelDashboard, "routes.AccountEditCritical": routes.AccountEditCritical, - "routeAccountEditCriticalSubmit": routeAccountEditCriticalSubmit, - "routeAccountEditAvatar": routeAccountEditAvatar, - "routeAccountEditAvatarSubmit": routeAccountEditAvatarSubmit, - "routeAccountEditUsername": routeAccountEditUsername, - "routeAccountEditUsernameSubmit": routeAccountEditUsernameSubmit, + "routes.AccountEditCriticalSubmit": routes.AccountEditCriticalSubmit, + "routes.AccountEditAvatar": routes.AccountEditAvatar, + "routes.AccountEditAvatarSubmit": routes.AccountEditAvatarSubmit, + "routes.AccountEditUsername": routes.AccountEditUsername, + "routes.AccountEditUsernameSubmit": routes.AccountEditUsernameSubmit, "routeAccountEditEmail": routeAccountEditEmail, "routeAccountEditEmailTokenSubmit": routeAccountEditEmailTokenSubmit, "routes.ViewProfile": routes.ViewProfile, @@ -205,11 +205,11 @@ var routeMapEnum = map[string]int{ "routePanelDebug": 67, "routePanelDashboard": 68, "routes.AccountEditCritical": 69, - "routeAccountEditCriticalSubmit": 70, - "routeAccountEditAvatar": 71, - "routeAccountEditAvatarSubmit": 72, - "routeAccountEditUsername": 73, - "routeAccountEditUsernameSubmit": 74, + "routes.AccountEditCriticalSubmit": 70, + "routes.AccountEditAvatar": 71, + "routes.AccountEditAvatarSubmit": 72, + "routes.AccountEditUsername": 73, + "routes.AccountEditUsernameSubmit": 74, "routeAccountEditEmail": 75, "routeAccountEditEmailTokenSubmit": 76, "routes.ViewProfile": 77, @@ -319,11 +319,11 @@ var reverseRouteMapEnum = map[int]string{ 67: "routePanelDebug", 68: "routePanelDashboard", 69: "routes.AccountEditCritical", - 70: "routeAccountEditCriticalSubmit", - 71: "routeAccountEditAvatar", - 72: "routeAccountEditAvatarSubmit", - 73: "routeAccountEditUsername", - 74: "routeAccountEditUsernameSubmit", + 70: "routes.AccountEditCriticalSubmit", + 71: "routes.AccountEditAvatar", + 72: "routes.AccountEditAvatarSubmit", + 73: "routes.AccountEditUsername", + 74: "routes.AccountEditUsernameSubmit", 75: "routeAccountEditEmail", 76: "routeAccountEditEmailTokenSubmit", 77: "routes.ViewProfile", @@ -529,7 +529,7 @@ func NewGenRouter(uploads http.Handler) (*GenRouter, error) { writ := NewWriterIntercept(w) http.StripPrefix("/uploads/",uploads).ServeHTTP(writ,req) if writ.GetCode() == 200 { - w.Header().Set("Cache-Control", "max-age=" + strconv.Itoa(common.Day)) + w.Header().Set("Cache-Control", "max-age=" + strconv.Itoa(int(common.Day))) w.Header().Set("Vary", "Accept-Encoding") } }, @@ -1337,7 +1337,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(70) - err = routeAccountEditCriticalSubmit(w,req,user) + err = routes.AccountEditCriticalSubmit(w,req,user) case "/user/edit/avatar/": err = common.MemberOnly(w,req,user) if err != nil { @@ -1346,7 +1346,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(71) - err = routeAccountEditAvatar(w,req,user) + err = routes.AccountEditAvatar(w,req,user) case "/user/edit/avatar/submit/": err = common.MemberOnly(w,req,user) if err != nil { @@ -1354,7 +1354,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - err = common.HandleUploadRoute(w,req,user,common.Config.MaxRequestSize) + err = common.HandleUploadRoute(w,req,user,int(common.Config.MaxRequestSize)) if err != nil { router.handleError(err,w,req,user) return @@ -1366,7 +1366,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(72) - err = routeAccountEditAvatarSubmit(w,req,user) + err = routes.AccountEditAvatarSubmit(w,req,user) case "/user/edit/username/": err = common.MemberOnly(w,req,user) if err != nil { @@ -1375,7 +1375,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(73) - err = routeAccountEditUsername(w,req,user) + err = routes.AccountEditUsername(w,req,user) case "/user/edit/username/submit/": err = common.NoSessionMismatch(w,req,user) if err != nil { @@ -1390,7 +1390,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { } counters.RouteViewCounter.Bump(74) - err = routeAccountEditUsernameSubmit(w,req,user) + err = routes.AccountEditUsernameSubmit(w,req,user) case "/user/edit/email/": err = common.MemberOnly(w,req,user) if err != nil { @@ -1492,7 +1492,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - err = common.HandleUploadRoute(w,req,user,common.Config.MaxRequestSize) + err = common.HandleUploadRoute(w,req,user,int(common.Config.MaxRequestSize)) if err != nil { router.handleError(err,w,req,user) return @@ -1649,7 +1649,7 @@ func (router *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - err = common.HandleUploadRoute(w,req,user,common.Config.MaxRequestSize) + err = common.HandleUploadRoute(w,req,user,int(common.Config.MaxRequestSize)) if err != nil { router.handleError(err,w,req,user) return diff --git a/main.go b/main.go index 1be52abc..bd4996b5 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ import ( "./common" "./common/counters" "./config" + "./query_gen/lib" "github.com/fsnotify/fsnotify" ) @@ -38,11 +39,12 @@ type Globs struct { } func afterDBInit() (err error) { - common.Rstore, err = common.NewSQLReplyStore() + acc := qgen.Builder.Accumulator() + common.Rstore, err = common.NewSQLReplyStore(acc) if err != nil { return err } - common.Prstore, err = common.NewSQLProfileReplyStore() + common.Prstore, err = common.NewSQLProfileReplyStore(acc) if err != nil { return err } @@ -65,6 +67,10 @@ func afterDBInit() (err error) { if err != nil { return err } + err = common.StaticFiles.JSTmplInit() + if err != nil { + return err + } log.Print("Initialising the widgets") err = common.InitWidgets() diff --git a/member_routes.go b/member_routes.go index b77e1c18..57c9296c 100644 --- a/member_routes.go +++ b/member_routes.go @@ -1,12 +1,8 @@ package main import ( - "html" - "io" "net/http" - "os" "path/filepath" - "regexp" "strconv" "strings" @@ -258,179 +254,6 @@ func routeReportSubmit(w http.ResponseWriter, r *http.Request, user common.User, return nil } -func routeAccountEditCriticalSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - _, ferr := common.SimpleUserCheck(w, r, &user) - if ferr != nil { - return ferr - } - - var realPassword, salt string - currentPassword := r.PostFormValue("account-current-password") - newPassword := r.PostFormValue("account-new-password") - confirmPassword := r.PostFormValue("account-confirm-password") - - err := stmts.getPassword.QueryRow(user.ID).Scan(&realPassword, &salt) - if err == ErrNoRows { - return common.LocalError("Your account no longer exists.", w, r, user) - } else if err != nil { - return common.InternalError(err, w, r) - } - - err = common.CheckPassword(realPassword, currentPassword, salt) - if err == common.ErrMismatchedHashAndPassword { - return common.LocalError("That's not the correct password.", w, r, user) - } else if err != nil { - return common.InternalError(err, w, r) - } - if newPassword != confirmPassword { - return common.LocalError("The two passwords don't match.", w, r, user) - } - common.SetPassword(user.ID, newPassword) - - // Log the user out as a safety precaution - common.Auth.ForceLogout(user.ID) - http.Redirect(w, r, "/", http.StatusSeeOther) - return nil -} - -func routeAccountEditAvatar(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - headerVars, ferr := common.UserCheck(w, r, &user) - if ferr != nil { - return ferr - } - - pi := common.Page{"Edit Avatar", user, headerVars, tList, nil} - if common.RunPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { - return nil - } - err := common.Templates.ExecuteTemplate(w, "account_own_edit_avatar.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil -} - -func routeAccountEditAvatarSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - headerVars, ferr := common.UserCheck(w, r, &user) - if ferr != nil { - return ferr - } - - var filename, ext string - for _, fheaders := range r.MultipartForm.File { - for _, hdr := range fheaders { - if hdr.Filename == "" { - continue - } - infile, err := hdr.Open() - if err != nil { - return common.LocalError("Upload failed", w, r, user) - } - defer infile.Close() - - // We don't want multiple files - // TODO: Check the length of r.MultipartForm.File and error rather than doing this x.x - if filename != "" { - if filename != hdr.Filename { - os.Remove("./uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext) - return common.LocalError("You may only upload one avatar", w, r, user) - } - } else { - filename = hdr.Filename - } - - if ext == "" { - extarr := strings.Split(hdr.Filename, ".") - if len(extarr) < 2 { - return common.LocalError("Bad file", w, r, user) - } - ext = extarr[len(extarr)-1] - - // TODO: Can we do this without a regex? - reg, err := regexp.Compile("[^A-Za-z0-9]+") - if err != nil { - return common.LocalError("Bad file extension", w, r, user) - } - ext = reg.ReplaceAllString(ext, "") - ext = strings.ToLower(ext) - } - - outfile, err := os.Create("./uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext) - if err != nil { - return common.LocalError("Upload failed [File Creation Failed]", w, r, user) - } - defer outfile.Close() - - _, err = io.Copy(outfile, infile) - if err != nil { - return common.LocalError("Upload failed [Copy Failed]", w, r, user) - } - } - } - if ext == "" { - return common.LocalError("No file", w, r, user) - } - - err := user.ChangeAvatar("." + ext) - if err != nil { - return common.InternalError(err, w, r) - } - user.Avatar = "/uploads/avatar_" + strconv.Itoa(user.ID) + "." + ext - headerVars.NoticeList = append(headerVars.NoticeList, common.GetNoticePhrase("account_avatar_updated")) - - pi := common.Page{"Edit Avatar", user, headerVars, tList, nil} - if common.RunPreRenderHook("pre_render_account_own_edit_avatar", w, r, &user, &pi) { - return nil - } - err = common.Templates.ExecuteTemplate(w, "account_own_edit_avatar.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil -} - -func routeAccountEditUsername(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - headerVars, ferr := common.UserCheck(w, r, &user) - if ferr != nil { - return ferr - } - - pi := common.Page{"Edit Username", user, headerVars, tList, user.Name} - if common.RunPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { - return nil - } - err := common.Templates.ExecuteTemplate(w, "account_own_edit_username.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil -} - -func routeAccountEditUsernameSubmit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { - headerVars, ferr := common.UserCheck(w, r, &user) - if ferr != nil { - return ferr - } - - newUsername := html.EscapeString(strings.Replace(r.PostFormValue("account-new-username"), "\n", "", -1)) - err := user.ChangeName(newUsername) - if err != nil { - return common.LocalError("Unable to change the username. Does someone else already have this name?", w, r, user) - } - user.Name = newUsername - - headerVars.NoticeList = append(headerVars.NoticeList, common.GetNoticePhrase("account_username_updated")) - pi := common.Page{"Edit Username", user, headerVars, tList, nil} - if common.RunPreRenderHook("pre_render_account_own_edit_username", w, r, &user, &pi) { - return nil - } - err = common.Templates.ExecuteTemplate(w, "account_own_edit_username.html", pi) - if err != nil { - return common.InternalError(err, w, r) - } - return nil -} - func routeAccountEditEmail(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError { headerVars, ferr := common.UserCheck(w, r, &user) if ferr != nil { diff --git a/patcher/main.go b/patcher/main.go index 4dc90ca3..91322a1e 100644 --- a/patcher/main.go +++ b/patcher/main.go @@ -9,6 +9,7 @@ import ( "log" "os" "runtime/debug" + "strconv" "../common" "../config" @@ -85,10 +86,19 @@ func patcher(scanner *bufio.Scanner) error { if err != nil { return err } - _ = schemaFile + dbVersion, err := strconv.Atoi(schemaFile.DBVersion) + if err != nil { + return err + } fmt.Println("Applying the patches") - return patch0(scanner) + if dbVersion < 1 { + err := patch0(scanner) + if err != nil { + return err + } + } + return patch1(scanner) } func execStmt(stmt *sql.Stmt, err error) error { diff --git a/patcher/patches.go b/patcher/patches.go index 0b896d5a..6fef4d26 100644 --- a/patcher/patches.go +++ b/patcher/patches.go @@ -120,5 +120,35 @@ func patch0(scanner *bufio.Scanner) (err error) { } func patch1(scanner *bufio.Scanner) error { + // ! Don't reuse this function blindly, it doesn't escape apostrophes + var replaceTextWhere = func(replaceThis string, withThis string) error { + return execStmt(qgen.Builder.SimpleUpdate("viewchunks", "route = '"+withThis+"'", "route = '"+replaceThis+"'")) + } + + err := replaceTextWhere("routeAccountEditCriticalSubmit", "routes.AccountEditCriticalSubmit") + if err != nil { + return err + } + + err = replaceTextWhere("routeAccountEditAvatar", "routes.AccountEditAvatar") + if err != nil { + return err + } + + err = replaceTextWhere("routeAccountEditAvatarSubmit", "routes.AccountEditAvatarSubmit") + if err != nil { + return err + } + + err = replaceTextWhere("routeAccountEditUsername", "routes.AccountEditUsername") + if err != nil { + return err + } + + err = replaceTextWhere("routeAccountEditUsernameSubmit", "routes.AccountEditUsernameSubmit") + if err != nil { + return err + } + return nil } diff --git a/public/global.js b/public/global.js index 130e6449..e75db775 100644 --- a/public/global.js +++ b/public/global.js @@ -49,9 +49,12 @@ function bindToAlerts() { }); } +var alertsInitted = false; // TODO: Add the ability for users to dismiss alerts function loadAlerts(menuAlerts) { + if(!alertsInitted) return; + var alertListNode = menuAlerts.getElementsByClassName("alertList")[0]; var alertCounterNode = menuAlerts.getElementsByClassName("alert_counter")[0]; alertCounterNode.textContent = "0"; @@ -59,7 +62,7 @@ function loadAlerts(menuAlerts) type: 'get', dataType: 'json', url:'/api/?action=get&module=alerts', - success: function(data) { + success: (data) => { if("errmsg" in data) { alertListNode.innerHTML = "