Refactored the error handlers.

The static files for themes are now automatically reloaded without having to restart Gosora.
Added the Get and Set methods to the SFileList type.
Static files can now be updated during execution in a thread-safe way.

Removed Riot as a dependency.
Began work on making Cosora responsive like the other themes.
This commit is contained in:
Azareal 2017-12-01 02:04:29 +00:00
parent 0e9cebfa47
commit 9eae8da180
16 changed files with 183 additions and 173 deletions

View File

@ -86,7 +86,7 @@ Several important features for saving memory in the templates system may have to
# Advanced Installation
An example of running the commands directly on Windows.
An example of running the commands directly on Windows. We're looking into reducing the number of commands you need to type, for instance, you could invoke the update-deps batch or shell files to install / update all of the dependencies instead of typing each `get get -u`
Linux is similar, however you might need to use cd and mv a bit more like in the shell files due to the differences in go build across platforms. Additionally, Linux doesn't require `StackExchange/wmi` or ``/x/sys/windows`
@ -168,7 +168,7 @@ We're looking for ways to clean-up the plugin system so that all of them (except
More images in the /images/ folder. Beware though, some of them are *really* outdated.
# Dependencies (a few of these like Riot aren't currently in use, but we anticipate that we'll need some sort of search engine library in the very immediate future)
# Dependencies (a few of these like Rez aren't currently in use, but we anticipate that we'll need some sort of search engine library in the very immediate future)
* Go 1.9
@ -194,8 +194,6 @@ More images in the /images/ folder. Beware though, some of them are *really* out
* ithub.com/denisenkom/go-mssqldb For interfacing with MSSQL. You will be able to pick this instead of MSSQL soon.
* github.com/go-ego/riot A search engine library.
* github.com/bamiaux/rez An image resizer (e.g. for spitting out thumbnails)
* github.com/fsnotify/fsnotify A library for watching events on the file system.

View File

@ -1,7 +1,6 @@
package common
import "log"
import "sync"
import "net/http"
import "runtime/debug"
@ -32,10 +31,6 @@ type RouteErrorImpl struct {
handled bool
}
/*func NewRouteError(msg string, system bool, json bool) RouteError {
return &RouteErrorImpl{msg, system, json, false}
}*/
func (err *RouteErrorImpl) Type() string {
// System errors may contain sensitive information we don't want the user to see
if err.system {
@ -80,21 +75,9 @@ func LogWarning(err error) {
// InternalError is the main function for handling internal errors, while simultaneously printing out a page for the end-user to let them know that *something* has gone wrong
// ? - Add a user parameter?
func InternalError(err error, w http.ResponseWriter, r *http.Request) RouteError {
log.Print(err)
debug.PrintStack()
// TODO: Centralise the user struct somewhere else
user := User{0, "guest", "Guest", "", 0, false, false, false, false, false, false, GuestPerms, nil, "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0}
pi := Page{"Internal Server Error", user, DefaultHeaderVar(), tList, "A problem has occurred in the system."}
err = Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
log.Print(err)
}
errorBufferMutex.Lock()
defer errorBufferMutex.Unlock()
errorBuffer = append(errorBuffer, err)
log.Fatal("")
pi := Page{"Internal Server Error", GuestUser, DefaultHeaderVar(), tList, "A problem has occurred in the system."}
handleErrorTemplate(w, r, pi)
LogError(err)
return HandledRouteError()
}
@ -112,26 +95,14 @@ func InternalErrorJSQ(err error, w http.ResponseWriter, r *http.Request, isJs bo
func InternalErrorJS(err error, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500)
_, _ = w.Write([]byte(`{"errmsg":"A problem has occurred in the system."}`))
errorBufferMutex.Lock()
defer errorBufferMutex.Unlock()
errorBuffer = append(errorBuffer, err)
log.Fatal(err)
LogError(err)
return HandledRouteError()
}
func PreError(errmsg string, w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(500)
user := User{ID: 0, Group: 6, Perms: GuestPerms}
pi := Page{"Error", user, DefaultHeaderVar(), tList, errmsg}
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
pi := Page{"Error", GuestUser, DefaultHeaderVar(), tList, errmsg}
handleErrorTemplate(w, r, pi)
return HandledRouteError()
}
@ -152,15 +123,7 @@ func PreErrorJSQ(errmsg string, w http.ResponseWriter, r *http.Request, isJs boo
func LocalError(errmsg string, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(500)
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, errmsg}
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
handleErrorTemplate(w, r, pi)
return HandledRouteError()
}
@ -182,16 +145,7 @@ func LocalErrorJS(errmsg string, w http.ResponseWriter, r *http.Request) RouteEr
func NoPermissions(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403)
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You don't have permission to do that."}
// TODO: What to do about this hook?
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
handleErrorTemplate(w, r, pi)
return HandledRouteError()
}
@ -212,15 +166,7 @@ func NoPermissionsJS(w http.ResponseWriter, r *http.Request, user User) RouteErr
func Banned(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(403)
pi := Page{"Banned", user, DefaultHeaderVar(), tList, "You have been banned from this site."}
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
handleErrorTemplate(w, r, pi)
return HandledRouteError()
}
@ -252,15 +198,7 @@ func LoginRequiredJSQ(w http.ResponseWriter, r *http.Request, user User, isJs bo
func LoginRequired(w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(401)
pi := Page{"Local Error", user, DefaultHeaderVar(), tList, "You need to login to do that."}
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
handleErrorTemplate(w, r, pi)
return HandledRouteError()
}
@ -292,30 +230,14 @@ func SecurityError(w http.ResponseWriter, r *http.Request, user User) RouteError
// ? - Add a JSQ and JS version of this?
// ? - Add a user parameter?
func NotFound(w http.ResponseWriter, r *http.Request) RouteError {
w.WriteHeader(404)
// TODO: Centralise the user struct somewhere else
user := User{0, "guest", "Guest", "", 0, false, false, false, false, false, false, GuestPerms, nil, "", false, "", "", "", "", "", 0, 0, "0.0.0.0.0", 0}
pi := Page{"Not Found", user, DefaultHeaderVar(), tList, "The requested page doesn't exist."}
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
return HandledRouteError()
return CustomError("The requested page doesn't exist.", 404, "Not Found", w, r, GuestUser)
}
// CustomError lets us make custom error types which aren't covered by the generic functions above
func CustomError(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(errcode)
pi := Page{errtitle, user, DefaultHeaderVar(), tList, errmsg}
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &user, &pi) {
return nil
}
}
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
handleErrorTemplate(w, r, pi)
return HandledRouteError()
}
@ -324,12 +246,25 @@ func CustomErrorJSQ(errmsg string, errcode int, errtitle string, w http.Response
if !isJs {
return CustomError(errmsg, errcode, errtitle, w, r, user)
}
return CustomErrorJS(errmsg, errcode, errtitle, w, r, user)
return CustomErrorJS(errmsg, errcode, w, r, user)
}
// CustomErrorJS is the pure JSON version of CustomError
func CustomErrorJS(errmsg string, errcode int, errtitle string, w http.ResponseWriter, r *http.Request, user User) RouteError {
func CustomErrorJS(errmsg string, errcode int, w http.ResponseWriter, r *http.Request, user User) RouteError {
w.WriteHeader(errcode)
_, _ = w.Write([]byte(`{"errmsg":"` + errmsg + `"}`))
return HandledRouteError()
}
func handleErrorTemplate(w http.ResponseWriter, r *http.Request, pi Page) {
// TODO: What to do about this hook?
if PreRenderHooks["pre_render_error"] != nil {
if RunPreRenderHook("pre_render_error", w, r, &pi.CurrentUser, &pi) {
return
}
}
err := Templates.ExecuteTemplate(w, "error.html", pi)
if err != nil {
LogError(err)
}
}

View File

@ -2,9 +2,9 @@ package common
import (
"bytes"
"log"
"mime"
"strings"
"sync"
//"errors"
"compress/gzip"
"io/ioutil"
@ -16,6 +16,7 @@ import (
type SFileList map[string]SFile
var StaticFiles SFileList = make(map[string]SFile)
var staticFileMutex sync.RWMutex
type SFile struct {
Data []byte
@ -48,11 +49,9 @@ func (list SFileList) Init() error {
var ext = filepath.Ext("/public/" + path)
gzipData := compressBytesGzip(data)
list["/static/"+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}
list.Set("/static/"+path, SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
if Dev.DebugMode {
log.Print("Added the '" + path + "' static file.")
}
debugLogf("Added the '%s' static file.", path)
return nil
})
}
@ -75,14 +74,25 @@ func (list SFileList) Add(path string, prefix string) error {
path = strings.TrimPrefix(path, prefix)
gzipData := compressBytesGzip(data)
list["/static"+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}
list.Set("/static"+path, SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
if Dev.DebugMode {
log.Printf("Added the '%s' static file", path)
}
debugLogf("Added the '%s' static file", path)
return nil
}
func (list SFileList) Get(name string) (file SFile, exists bool) {
staticFileMutex.RLock()
defer staticFileMutex.RUnlock()
file, exists = list[name]
return file, exists
}
func (list SFileList) Set(name string, data SFile) {
staticFileMutex.Lock()
defer staticFileMutex.Unlock()
list[name] = data
}
func compressBytesGzip(in []byte) []byte {
var buff bytes.Buffer
gz := gzip.NewWriter(&buff)

View File

@ -14,8 +14,8 @@ type HeaderVars struct {
Widgets PageWidgets
Site *site
Settings SettingMap
Themes map[string]Theme // TODO: Use a slice containing every theme instead of the main map for speed?
Theme Theme
Themes map[string]*Theme // TODO: Use a slice containing every theme instead of the main map for speed?
Theme *Theme
//TemplateName string // TODO: Use this to move template calls to the router rather than duplicating them over and over and over?
Zone string
Writer http.ResponseWriter
@ -151,8 +151,8 @@ type PanelThemesPage struct {
CurrentUser User
Header *HeaderVars
Stats PanelStats
PrimaryThemes []Theme
VariantThemes []Theme
PrimaryThemes []*Theme
VariantThemes []*Theme
}
type PanelUserPage struct {

View File

@ -97,7 +97,7 @@ func cascadeForumPerms(fperms *ForumPerms, user *User) {
// Even if they have the right permissions, the control panel is only open to supermods+. There are many areas without subpermissions which assume that the current user is a supermod+ and admins are extremely unlikely to give these permissions to someone who isn't at-least a supermod to begin with
// TODO: Do a panel specific theme?
func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, stats PanelStats, rerr RouteError) {
var theme Theme
var theme = &Theme{Name: ""}
cookie, err := r.Cookie("current_theme")
if err == nil {
@ -116,6 +116,7 @@ func panelUserCheck(w http.ResponseWriter, r *http.Request, user *User) (headerV
Themes: Themes,
Theme: theme,
Zone: "panel",
Writer: w,
}
// TODO: We should probably initialise headerVars.ExtData
@ -189,7 +190,7 @@ func simpleUserCheck(w http.ResponseWriter, r *http.Request, user *User) (header
// TODO: Add the ability for admins to restrict certain themes to certain groups?
func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *HeaderVars, rerr RouteError) {
var theme Theme
var theme = &Theme{Name: ""}
cookie, err := r.Cookie("current_theme")
if err == nil {
@ -208,6 +209,7 @@ func userCheck(w http.ResponseWriter, r *http.Request, user *User) (headerVars *
Themes: Themes,
Theme: theme,
Zone: "frontend",
Writer: w,
}
if user.IsBanned {

View File

@ -22,9 +22,9 @@ import (
"../query_gen/lib"
)
type ThemeList map[string]Theme // ? Use pointers instead?
type ThemeList map[string]*Theme
var Themes ThemeList = make(map[string]Theme)
var Themes ThemeList = make(map[string]*Theme)
var DefaultThemeBox atomic.Value
var ChangeDefaultThemeMutex sync.Mutex
@ -45,7 +45,6 @@ type Theme struct {
Tag string
URL string
Docks []string // Allowed Values: leftSidebar, rightSidebar, footer
AboutSegment bool // ? - Should this be a theme var instead?
Settings map[string]ThemeSetting
Templates []TemplateMapping
TemplatesMap map[string]string
@ -117,7 +116,7 @@ func (themes ThemeList) LoadActiveStatus() error {
log.Printf("Loading the default theme '%s'", theme.Name)
theme.Active = true
DefaultThemeBox.Store(theme.Name)
MapThemeTemplates(theme)
theme.MapTemplates()
} else {
log.Printf("Loading the theme '%s'", theme.Name)
theme.Active = false
@ -147,8 +146,8 @@ func InitThemes() error {
return err
}
var theme Theme
err = json.Unmarshal(themeFile, &theme)
var theme = &Theme{Name: ""}
err = json.Unmarshal(themeFile, theme)
if err != nil {
return err
}
@ -185,21 +184,25 @@ func InitThemes() error {
}
}
theme.ResourceTemplates = template.New("")
template.Must(theme.ResourceTemplates.ParseGlob("./themes/" + theme.Name + "/public/*.css"))
// It should be safe for us to load the files for all the themes in memory, as-long as the admin hasn't setup a ridiculous number of themes
err = AddThemeStaticFiles(theme)
err = theme.LoadStaticFiles()
if err != nil {
return err
}
Themes[theme.Name] = theme
}
return nil
}
func AddThemeStaticFiles(theme Theme) error {
// TODO: It might be unsafe to call the template parsing functions with fsnotify, do something more concurrent
func (theme *Theme) LoadStaticFiles() error {
theme.ResourceTemplates = template.New("")
template.Must(theme.ResourceTemplates.ParseGlob("./themes/" + theme.Name + "/public/*.css"))
// It should be safe for us to load the files for all the themes in memory, as-long as the admin hasn't setup a ridiculous number of themes
return theme.AddThemeStaticFiles()
}
func (theme *Theme) AddThemeStaticFiles() error {
// TODO: Use a function instead of a closure to make this more testable? What about a function call inside the closure to take the theme variable into account?
return filepath.Walk("./themes/"+theme.Name+"/public", func(path string, f os.FileInfo, err error) error {
debugLog("Attempting to add static file '" + path + "' for default theme '" + theme.Name + "'")
@ -230,14 +233,14 @@ func AddThemeStaticFiles(theme Theme) error {
path = strings.TrimPrefix(path, "themes/"+theme.Name+"/public")
gzipData := compressBytesGzip(data)
StaticFiles["/static/"+theme.Name+path] = SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)}
StaticFiles.Set("/static/"+theme.Name+path, SFile{data, gzipData, 0, int64(len(data)), int64(len(gzipData)), mime.TypeByExtension(ext), f, f.ModTime().UTC().Format(http.TimeFormat)})
debugLog("Added the '/" + theme.Name + path + "' static file for theme " + theme.Name + ".")
return nil
})
}
func MapThemeTemplates(theme Theme) {
func (theme *Theme) MapTemplates() {
if theme.Templates != nil {
for _, themeTmpl := range theme.Templates {
if themeTmpl.Name == "" {

View File

@ -22,9 +22,6 @@ go get -u gopkg.in/sourcemap.v1
echo "Installing OttoJS"
go get -u github.com/robertkrimen/otto
echo "Installing the Riot Search Engine"
go get -u github.com/robertkrimen/otto
echo "Installing the Rez Image Resizer"
go get -u github.com/bamiaux/rez

View File

@ -71,13 +71,6 @@ if %errorlevel% neq 0 (
exit /b %errorlevel%
)
echo Installing the Riot Search Engine
go get -u github.com/go-ego/riot
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Installing the Rez Image Resizer
go get -u github.com/bamiaux/rez
if %errorlevel% neq 0 (

65
main.go
View File

@ -13,10 +13,12 @@ import (
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
//"runtime/pprof"
"./common"
"github.com/fsnotify/fsnotify"
)
var version = common.Version{Major: 0, Minor: 1, Patch: 0, Tag: "dev"}
@ -55,13 +57,11 @@ func afterDBInit() (err error) {
if err != nil {
return err
}
log.Print("Initialising the widgets")
err = common.InitWidgets()
if err != nil {
return err
}
log.Print("Initialising the authentication system")
common.Auth, err = common.NewDefaultAuth()
if err != nil {
@ -72,12 +72,10 @@ func afterDBInit() (err error) {
if err != nil {
return err
}
common.ModLogs, err = common.NewModLogStore()
if err != nil {
return err
}
common.AdminLogs, err = common.NewAdminLogStore()
if err != nil {
return err
@ -158,6 +156,65 @@ func main() {
log.Fatal(err)
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
defer watcher.Close()
go func() {
for {
select {
case event := <-watcher.Events:
log.Println("event:", event)
if event.Op&fsnotify.Write == fsnotify.Write {
log.Println("modified file:", event.Name)
var pathBits = strings.Split(event.Name, "\\")
if len(pathBits) > 0 {
if pathBits[0] == "themes" {
var themeName string
if len(pathBits) >= 1 {
themeName = pathBits[1]
}
if len(pathBits) >= 2 && pathBits[2] == "public" {
// TODO: Handle new themes freshly plopped into the folder?
theme, ok := common.Themes[themeName]
if ok {
err = theme.LoadStaticFiles()
if err != nil {
common.LogError(err)
}
}
}
}
}
} else if event.Op&fsnotify.Create == fsnotify.Create {
log.Println("new file:", event.Name)
}
case err := <-watcher.Errors:
log.Println("error:", err)
}
}
}()
// TODO: Keep tabs on the theme stuff, and the langpacks
err = watcher.Add("./public")
if err != nil {
log.Fatal(err)
}
err = watcher.Add("./templates")
if err != nil {
log.Fatal(err)
}
for _, theme := range common.Themes {
err = watcher.Add("./themes/" + theme.Name + "/public")
if err != nil {
log.Fatal(err)
}
}
// Run this goroutine once a second
secondTicker := time.NewTicker(1 * time.Second)
fifteenMinuteTicker := time.NewTicker(15 * time.Minute)

View File

@ -42,7 +42,6 @@ func routeTopicCreate(w http.ResponseWriter, r *http.Request, user common.User,
return common.NoPermissions(w, r, user)
}
headerVars.Zone = "create_topic"
headerVars.Writer = w
// Lock this to the forum being linked?
// Should we always put it in strictmode when it's linked from another forum? Well, the user might end up changing their mind on what forum they want to post in and it would be a hassle, if they had to switch pages, even if it is a single click for many (exc. mobile)

View File

@ -1473,7 +1473,7 @@ func routePanelThemes(w http.ResponseWriter, r *http.Request, user common.User)
return common.NoPermissions(w, r, user)
}
var pThemeList, vThemeList []common.Theme
var pThemeList, vThemeList []*common.Theme
for _, theme := range common.Themes {
if theme.HideFromThemes {
continue
@ -1557,7 +1557,7 @@ func routePanelThemesSetDefault(w http.ResponseWriter, r *http.Request, user com
common.DefaultThemeBox.Store(uname)
common.ResetTemplateOverrides()
common.MapThemeTemplates(theme)
theme.MapTemplates()
common.ChangeDefaultThemeMutex.Unlock()
http.Redirect(w, r, "/panel/themes/", http.StatusSeeOther)

View File

@ -42,8 +42,7 @@ func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// GET functions
func routeStatic(w http.ResponseWriter, r *http.Request) {
//log.Print("Outputting static file '" + r.URL.Path + "'")
file, ok := common.StaticFiles[r.URL.Path]
file, ok := common.StaticFiles.Get(r.URL.Path)
if !ok {
if common.Dev.DebugMode {
log.Printf("Failed to find '%s'", r.URL.Path)
@ -61,11 +60,8 @@ func routeStatic(w http.ResponseWriter, r *http.Request) {
}
h.Set("Last-Modified", file.FormattedModTime)
h.Set("Content-Type", file.Mimetype)
//Cache-Control: max-age=31536000
h.Set("Cache-Control", cacheControlMaxAge)
h.Set("Cache-Control", cacheControlMaxAge) //Cache-Control: max-age=31536000
h.Set("Vary", "Accept-Encoding")
//http.ServeContent(w,r,r.URL.Path,file.Info.ModTime(),file)
//w.Write(file.Data)
if strings.Contains(h.Get("Accept-Encoding"), "gzip") {
h.Set("Content-Encoding", "gzip")
h.Set("Content-Length", strconv.FormatInt(file.GzipLength, 10))
@ -74,15 +70,9 @@ func routeStatic(w http.ResponseWriter, r *http.Request) {
h.Set("Content-Length", strconv.FormatInt(file.Length, 10)) // Avoid doing a type conversion every time?
io.Copy(w, bytes.NewReader(file.Data))
}
//io.CopyN(w, bytes.NewReader(file.Data), staticFiles[r.URL.Path].Length)
// Other options instead of io.Copy: io.CopyN(), w.Write(), http.ServeContent()
}
// Deprecated: Test route for stopping the server during a performance analysis
/*func routeExit(w http.ResponseWriter, r *http.Request, user common.User) common.RouteError{
db.Close()
os.Exit(0)
}*/
// TODO: Make this a static file somehow? Is it possible for us to put this file somewhere else?
// TODO: Add a sitemap
// TODO: Add an API so that plugins can register disallowed areas. E.g. /guilds/join for plugin_guilds
@ -102,7 +92,6 @@ func routeOverview(w http.ResponseWriter, r *http.Request, user common.User) com
return ferr
}
headerVars.Zone = "overview"
headerVars.Writer = w
pi := common.Page{common.GetTitlePhrase("overview"), user, headerVars, tList, nil}
if common.PreRenderHooks["pre_render_overview"] != nil {
@ -129,7 +118,6 @@ func routeCustomPage(w http.ResponseWriter, r *http.Request, user common.User) c
return common.NotFound(w, r)
}
headerVars.Zone = "custom_page"
headerVars.Writer = w
pi := common.Page{common.GetTitlePhrase("page"), user, headerVars, tList, nil}
if common.PreRenderHooks["pre_render_custom_page"] != nil {
@ -151,7 +139,6 @@ func routeTopics(w http.ResponseWriter, r *http.Request, user common.User) commo
return ferr
}
headerVars.Zone = "topics"
headerVars.Writer = w
// TODO: Add a function for the qlist stuff
var qlist string
@ -337,7 +324,6 @@ func routeForum(w http.ResponseWriter, r *http.Request, user common.User, sfid s
return common.InternalError(err, w, r)
}
headerVars.Zone = "view_forum"
headerVars.Writer = w
// Calculate the offset
var offset int
@ -424,7 +410,6 @@ func routeForums(w http.ResponseWriter, r *http.Request, user common.User) commo
return ferr
}
headerVars.Zone = "forums"
headerVars.Writer = w
var err error
var forumList []common.Forum
@ -514,7 +499,6 @@ func routeTopicID(w http.ResponseWriter, r *http.Request, user common.User) comm
return common.NoPermissions(w, r, user)
}
headerVars.Zone = "view_topic"
headerVars.Writer = w
topic.ContentHTML = common.ParseMessage(topic.Content, topic.ParentID, "forums")
topic.ContentLines = strings.Count(topic.Content, "\n")

View File

@ -495,6 +495,12 @@ select, input, textarea, button {
background-color: var(--element-background-color);
padding: 12px;
}
/* TODO: Refactor bgavatars to make the avatars rounded */
.rowlist.bgavatars .rowitem {
background-repeat: no-repeat;
background-size: 40px;
padding-left: 46px;
}
.topic_list .rowtopic {
font-size: 17px;
@ -960,3 +966,40 @@ select, input, textarea, button {
display: none;
}
}
@media(max-width: 520px) {
.topic_list {
display: flex;
flex-wrap: wrap;
}
.topic_list .topic_row {
display: block;
width: calc(50% - 6px);
float: left;
}
.topic_list .topic_row:nth-child(odd) {
margin-right: 12px;
}
.topic_left {
margin-bottom: 0px;
border-bottom: none;
border-right: 1px solid var(--element-border-color);
}
.topic_left .parent_forum {
display: none;
}
.topic_right.rowitem {
border-top: none;
border-left: 1px solid var(--element-border-color);
background-color: hsl(0,0%,90%);
}
.topic_right br, .topic_right img {
display: none;
}
.topic_right.topic_sticky {
border-bottom: 2px solid var(--element-border-color);
}
.topic_right > span {
margin-top: 6px;
margin-bottom: 6px;
}
}

View File

@ -6,7 +6,6 @@
"URL": "github.com/Azareal/Gosora",
"Tag": "WIP",
"Docks":["rightSidebar","footer"],
"AboutSegment":true,
"Templates": [
{
"Name": "topic",

View File

@ -22,9 +22,6 @@ go get -u gopkg.in/sourcemap.v1
echo "Updating OttoJS"
go get -u github.com/robertkrimen/otto
echo "Updating the Riot Search Engine"
go get -u github.com/go-ego/riot
echo "Updating the Rez Image Resizer"
go get -u github.com/bamiaux/rez

View File

@ -68,13 +68,6 @@ if %errorlevel% neq 0 (
exit /b %errorlevel%
)
echo Updating the Riot Search Engine
go get -u github.com/go-ego/riot
if %errorlevel% neq 0 (
pause
exit /b %errorlevel%
)
echo Updating the Rez Image Resizer
go get -u github.com/bamiaux/rez
if %errorlevel% neq 0 (