package main import ( "fmt" "log" "net/http" "os" "text/template" "time" "github.com/gorilla/context" "github.com/gorilla/mux" "github.com/gorilla/sessions" ) // SiteData is the basic data needed for the site/pages type SiteData struct { Title string SubTitle string Port int SessionName string Stylesheets []string Scripts []string InlineScript string Flash flashMessage // Quick message at top of page Menu []menuItem // Top-aligned menu items BottomMenu []menuItem // Bottom-aligned menu items // Any other template data TemplateData interface{} } type flashMessage struct { Message string Status string } type menuItem struct { Text string Link string Active bool } var site SiteData var sessionStore = sessions.NewCookieStore([]byte("gostatbot secret cookie nobody will guess")) var r *mux.Router type webModule interface { GetName() string GetRoutes() map[string]func(http.ResponseWriter, *http.Request) Register() GetMenuEntries() []menuItem GetBottomMenuEntries() []menuItem } var webModules []webModule // This is the main function for the web server func statWebMain(slack *Slack) { site.Title = "stat_bot" site.SubTitle = "" site.Port = 3000 site.SessionName = "statbot" r = mux.NewRouter() r.StrictSlash(true) assetHandler := http.FileServer(http.Dir("./assets/")) http.Handle("/assets/", http.StripPrefix("/assets/", assetHandler)) registerWebModule(new(generalWebModule)) registerWebModule(new(levelUpWebModule)) registerWebModule(new(levelUpAchieveWebModule)) http.Handle("/", r) go func() { log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", site.Port), context.ClearHandler(http.DefaultServeMux))) }() } func initRequest(w http.ResponseWriter, req *http.Request) { writeToLog(" " + time.Now().Format(time.RFC3339) + " >> Web Request Received\n") site.SubTitle = "" site.Stylesheets = make([]string, 0, 0) site.Stylesheets = append(site.Stylesheets, "/assets/css/pure-min.css") site.Stylesheets = append(site.Stylesheets, "/assets/css/statbot.css") site.Stylesheets = append(site.Stylesheets, "https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css") site.Scripts = make([]string, 0, 0) site.Scripts = append(site.Scripts, "/assets/js/highcharts.js") site.Scripts = append(site.Scripts, "/assets/js/B.js") site.Scripts = append(site.Scripts, "/assets/js/B_purecss.js") site.Scripts = append(site.Scripts, "/assets/js/B_cookies.js") site.InlineScript = "" site.Menu = make([]menuItem, 0, 0) site.BottomMenu = make([]menuItem, 0, 0) site.BottomMenu = append(site.BottomMenu, menuItem{Text: "Admin", Link: "/admin/"}) for _, mod := range webModules { for _, m := range mod.GetMenuEntries() { site.Menu = append(site.Menu, m) } for _, m := range mod.GetBottomMenuEntries() { site.BottomMenu = append(site.BottomMenu, m) } } } func registerWebModule(b webModule) { // Register a web module // Make sure that we haven't already registered it (or another that has the same route) for _, mod := range webModules { if mod.GetName() == b.GetName() { panic(fmt.Errorf("Attempted to Re-register Web Module %s", b.GetName())) } else { for k := range mod.GetRoutes() { for nk := range b.GetRoutes() { if k == nk { panic(fmt.Errorf("Attempted to Re-register Web Route %s", k)) } } } } } b.Register() webModules = append(webModules, b) } // showPage // Load a template and all of the surrounding templates func showPage(tmplName string, tmplData interface{}, w http.ResponseWriter) error { for _, tmpl := range []string{ "htmlheader.html", "menu.html", "header.html", tmplName, "footer.html", "htmlfooter.html", } { if err := outputTemplate(tmpl, tmplData, w); err != nil { writeToLog(fmt.Sprintf("%s\n", err)) return err } } return nil } // outputTemplate // Spit out a template func outputTemplate(tmplName string, tmplData interface{}, w http.ResponseWriter) error { _, err := os.Stat("templates/" + tmplName) if err == nil { t := template.New(tmplName) t, _ = t.ParseFiles("templates/" + tmplName) return t.Execute(w, tmplData) } return fmt.Errorf("WebServer: Cannot load template (templates/%s): File not found", tmplName) } // setMenuItemActive // Sets a menu item to active, all others to inactive func setMenuItemActive(which string) { for i := range site.Menu { if site.Menu[i].Text == which { site.Menu[i].Active = true } else { site.Menu[i].Active = false } } } func getSessionStringValue(key string, w http.ResponseWriter, req *http.Request) (string, error) { session, err := sessionStore.Get(req, site.SessionName) if err != nil { return "", err } val := session.Values[key] var retVal string var ok bool if retVal, ok = val.(string); !ok { return "", fmt.Errorf("Unable to create string from %s", key) } return retVal, nil } func setFlashMessage(msg string, stat string) { site.Flash = flashMessage{Message: msg, Status: stat} } func addToInlineScript(s string) { site.InlineScript = fmt.Sprintf("%s%s", site.InlineScript, s) } func pageNotFound(err error, w http.ResponseWriter) { if err == nil { err = fmt.Errorf("Page Not Found") } http.Error(w, err.Error(), 404) } func assertError(err error, w http.ResponseWriter) bool { if err != nil { http.Error(w, err.Error(), 500) return true } return false }