admin.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. package main
  2. import (
  3. // "fmt"
  4. "html/template"
  5. "io/ioutil"
  6. "net/http"
  7. "os"
  8. "strings"
  9. )
  10. type Dir struct {
  11. Title string
  12. Body []os.FileInfo
  13. }
  14. // TODO need a way to lock this to current hugo-site dir
  15. func loadDir(title string) (*Dir, error) {
  16. dir := title
  17. body, err := ioutil.ReadDir(dir)
  18. if err != nil {
  19. return nil, err
  20. }
  21. return &Dir{Title: title, Body: body}, nil
  22. }
  23. // Might need a better name ; is a location pair where
  24. // Root = site root (ie /admin/)
  25. // Dir = relative file path (ie ./admin)
  26. type Location struct {
  27. Root string
  28. Dir string
  29. }
  30. func serveAdmin(root string, dir string) {
  31. // TODO some way to standardize roots / dirs (path is wonky)
  32. // TODO templates should read adminroot (instead of hardcoding /admin/...)
  33. admin := Location{root, dir}
  34. // serve admin
  35. http.HandleFunc(admin.Root, func(w http.ResponseWriter, r *http.Request) {
  36. adminHandler(w, r, admin)
  37. })
  38. // serve assets
  39. assetroot := admin.Root + "assets/"
  40. assetdir := admin.Dir + "/assets"
  41. http.Handle(assetroot, http.StripPrefix(assetroot, http.FileServer(http.Dir(assetdir))))
  42. // API
  43. http.HandleFunc(admin.Root+"edit/", func(w http.ResponseWriter, r *http.Request) {
  44. editHandler(w, r, admin)
  45. })
  46. http.HandleFunc(admin.Root+"save/", func(w http.ResponseWriter, r *http.Request) {
  47. saveHandler(w, r, admin)
  48. })
  49. http.HandleFunc(admin.Root+"login/", func(w http.ResponseWriter, r *http.Request) {
  50. loginHandler(w, r, admin)
  51. })
  52. http.HandleFunc(admin.Root+"logout/", func(w http.ResponseWriter, r *http.Request) {
  53. logoutHandler(w, r, admin)
  54. })
  55. http.HandleFunc(admin.Root+"manage-accounts/", func(w http.ResponseWriter, r *http.Request) {
  56. adminUsersHandler(w, r, admin)
  57. })
  58. }
  59. func adminHandler(w http.ResponseWriter, r *http.Request, admin Location) {
  60. isAuth(w, r, admin, "user")
  61. title := r.URL.Path[len(admin.Root):]
  62. if title == "" {
  63. title = "./"
  64. }
  65. p, err := loadDir(title)
  66. if err != nil {
  67. p = &Dir{Title: title}
  68. }
  69. renderTemplateDir(w, "view.html", p)
  70. }
  71. func editHandler(w http.ResponseWriter, r *http.Request, admin Location) {
  72. // TODO : pass in
  73. contentDir := getConfig("contentdir")
  74. isAuth(w, r, admin, "user")
  75. path := r.URL.Path[len(admin.Root+"edit/"):]
  76. if strings.HasPrefix(path, contentDir) {
  77. c, err := new(Page).contentRead(path)
  78. if err != nil {
  79. c = &Content{Path: path}
  80. }
  81. renderTemplateContent(w, "content-edit.html", c)
  82. } else {
  83. p, err := new(Page).Read(path)
  84. if err != nil {
  85. p = &Page{Path: path}
  86. }
  87. renderTemplatePage(w, "edit.html", p)
  88. }
  89. }
  90. func saveHandler(w http.ResponseWriter, r *http.Request, admin Location) {
  91. contentDir := getConfig("contentdir")
  92. isAuth(w, r, admin, "user")
  93. path := r.URL.Path[len(admin.Root+"save/"):]
  94. if strings.HasPrefix(path, contentDir) {
  95. var page Page
  96. r.ParseForm()
  97. fm := make(map[string]interface{})
  98. for key, values := range r.Form {
  99. for _, value := range values {
  100. if strings.HasPrefix(key, "fm.") {
  101. fm[key[3:]] = value
  102. }
  103. }
  104. }
  105. page.contentUpdate(path, fm, []byte(r.FormValue("body")))
  106. } else {
  107. page := &Page{
  108. Path: path,
  109. Body: r.FormValue("body"),
  110. }
  111. page.Update(path, []byte(r.FormValue("body")))
  112. }
  113. git(path) //this should probably only run if there have been changes
  114. buildSite()
  115. http.Redirect(w, r, admin.Root, http.StatusFound)
  116. }
  117. var templates = template.Must(template.ParseGlob("admin/templates/*"))
  118. func renderTemplatePage(w http.ResponseWriter, tmpl string, p *Page) {
  119. err := templates.ExecuteTemplate(w, tmpl, p)
  120. if err != nil {
  121. http.Error(w, err.Error(), http.StatusInternalServerError)
  122. }
  123. }
  124. func renderTemplateContent(w http.ResponseWriter, tmpl string, c *Content) {
  125. err := templates.ExecuteTemplate(w, tmpl, c)
  126. if err != nil {
  127. http.Error(w, err.Error(), http.StatusInternalServerError)
  128. }
  129. }
  130. func renderTemplateDir(w http.ResponseWriter, tmpl string, p *Dir) {
  131. err := templates.ExecuteTemplate(w, tmpl, p)
  132. if err != nil {
  133. http.Error(w, err.Error(), http.StatusInternalServerError)
  134. }
  135. }