Publish HTML quickly. https://html.house
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

125 lines
3.1 KiB

  1. package htmlhouse
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "html/template"
  6. "io/ioutil"
  7. "net/http"
  8. "github.com/gorilla/mux"
  9. "github.com/writeas/impart"
  10. )
  11. type app struct {
  12. cfg *config
  13. router *mux.Router
  14. db *sql.DB
  15. session sessionManager
  16. templates map[string]*template.Template
  17. }
  18. func newApp() (*app, error) {
  19. var err error
  20. app := &app{}
  21. app.cfg, err = newConfig()
  22. if err != nil {
  23. return app, err
  24. }
  25. app.session, err = newSessionManager(app.cfg)
  26. if err != nil {
  27. return app, err
  28. }
  29. err = app.initDatabase()
  30. if err != nil {
  31. return app, err
  32. }
  33. app.initTemplates()
  34. app.initRouter()
  35. return app, nil
  36. }
  37. func (app *app) close() {
  38. app.db.Close()
  39. }
  40. func (app *app) initRouter() {
  41. app.router = mux.NewRouter()
  42. api := app.router.PathPrefix("/⌂/").Subrouter()
  43. api.HandleFunc("/create", app.handler(createHouse)).Methods("POST").Name("create")
  44. api.HandleFunc("/{house:[A-Za-z0-9.-]{8}}", app.handler(renovateHouse)).Methods("POST").Name("update")
  45. api.HandleFunc("/public", app.handler(getPublicHousesData)).Methods("GET").Name("browse-api")
  46. admin := app.router.PathPrefix("/admin/").Subrouter()
  47. admin.HandleFunc("/unpublish", app.handler(banHouse)).Methods("POST").Name("unpublish")
  48. admin.HandleFunc("/republish", app.handler(unbanHouse)).Methods("POST").Name("republish")
  49. app.router.HandleFunc("/", app.handler(getEditor)).Methods("GET").Name("index")
  50. app.router.HandleFunc("/edit/{house:[A-Za-z0-9.-]{8}}.html", app.handler(getEditor)).Methods("GET").Name("edit")
  51. app.router.HandleFunc("/stats/{house:[A-Za-z0-9.-]{8}}.html", app.handler(viewHouseStats)).Methods("GET").Name("stats")
  52. app.router.HandleFunc("/{house:[A-Za-z0-9.-]{8}}.html", app.handler(getHouse)).Methods("GET").Name("get")
  53. app.router.HandleFunc("/browse", app.handler(viewHouses)).Methods("GET").Name("browse")
  54. app.router.PathPrefix("/").Handler(http.FileServer(http.Dir(app.cfg.StaticDir)))
  55. }
  56. type EditorPage struct {
  57. ID string
  58. Content string
  59. Public bool
  60. }
  61. func getEditor(app *app, w http.ResponseWriter, r *http.Request) error {
  62. vars := mux.Vars(r)
  63. house := vars["house"]
  64. if house == "" {
  65. defaultPage, err := ioutil.ReadFile(app.cfg.StaticDir + "/default.html")
  66. if err != nil {
  67. fmt.Printf("\n%s\n", err)
  68. defaultPage = []byte("<!DOCTYPE html>\n<html>\n</html>")
  69. }
  70. app.templates["editor"].ExecuteTemplate(w, "editor", &EditorPage{"", string(defaultPage), false})
  71. return nil
  72. }
  73. html, err := getHouseHTML(app, house)
  74. if err != nil {
  75. return err
  76. }
  77. app.templates["editor"].ExecuteTemplate(w, "editor", &EditorPage{house, html, isHousePublic(app, house)})
  78. return nil
  79. }
  80. type handlerFunc func(app *app, w http.ResponseWriter, r *http.Request) error
  81. func (app *app) handler(h handlerFunc) http.HandlerFunc {
  82. return func(w http.ResponseWriter, r *http.Request) {
  83. handleError(w, r, func() error {
  84. return h(app, w, r)
  85. }())
  86. }
  87. }
  88. func handleError(w http.ResponseWriter, r *http.Request, err error) {
  89. if err == nil {
  90. return
  91. }
  92. if err, ok := err.(impart.HTTPError); ok {
  93. impart.WriteError(w, err)
  94. return
  95. }
  96. impart.WriteError(w, impart.HTTPError{http.StatusInternalServerError, "This is an unhelpful error message for a miscellaneous internal error."})
  97. }