main.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package main
  2. import (
  3. "errors"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "sort"
  8. "strings"
  9. log "github.com/Sirupsen/logrus"
  10. haikunator "github.com/atrox/haikunatorgo"
  11. "github.com/gin-contrib/sessions"
  12. "github.com/gin-gonic/gin"
  13. "github.com/msoedov/hacker-slides/auth"
  14. "github.com/msoedov/hacker-slides/files"
  15. )
  16. const sessionHeader = "slide-session"
  17. func SlidePath(name string) string {
  18. return fmt.Sprintf("slides/%s.md", name)
  19. }
  20. func NewApp() *gin.Engine {
  21. r := gin.Default()
  22. store := sessions.NewCookieStore([]byte("secret"))
  23. r.Use(sessions.Sessions(sessionHeader, store))
  24. r.Use(auth.BasicAuth())
  25. r.LoadHTMLGlob("templates/*.tmpl")
  26. r.Static("/static", "./static")
  27. r.Static("/images", "./slides/images")
  28. r.GET("/", func(c *gin.Context) {
  29. isNew := c.Query("new")
  30. latest := files.LatestFileIn("slides")
  31. log.WithFields(log.Fields{
  32. "name": latest,
  33. "isNew": isNew,
  34. }).Info("Restoring latest point")
  35. var path, name string
  36. if latest == "" || isNew != "" {
  37. haikunator := haikunator.New()
  38. haikunator.TokenLength = 0
  39. name = haikunator.Haikunate()
  40. } else {
  41. name = strings.Replace(latest, ".md", "", 1)
  42. }
  43. path = SlidePath(name)
  44. log.WithFields(log.Fields{
  45. "path": path,
  46. }).Info("A new session")
  47. session := sessions.Default(c)
  48. session.Set("name", path)
  49. session.Save()
  50. c.Writer.Header().Set("Location", fmt.Sprintf("/stash/edit/%s", name))
  51. c.HTML(302, "index.tmpl", gin.H{
  52. "pubTo": path,
  53. })
  54. })
  55. mustHaveSession := func(c *gin.Context) (string, error) {
  56. session := sessions.Default(c)
  57. val := session.Get("name")
  58. emptySession := errors.New("Emtpy session")
  59. if val == nil {
  60. c.String(400, "No context")
  61. return "", emptySession
  62. }
  63. log.WithFields(log.Fields{
  64. "path": val,
  65. }).Info("Got session")
  66. path, ok := val.(string)
  67. if !ok {
  68. c.String(400, "No context")
  69. return "", emptySession
  70. }
  71. return path, nil
  72. }
  73. r.GET("/slides.md", func(c *gin.Context) {
  74. path, err := mustHaveSession(c)
  75. if err != nil {
  76. return
  77. }
  78. if _, err := os.Stat(path); err != nil {
  79. // copy sample markdown file to the path
  80. body, err := ioutil.ReadFile("initial-slides.md")
  81. if err != nil {
  82. panic(err)
  83. }
  84. ioutil.WriteFile(path, body, 0644)
  85. c.String(200, string(body))
  86. return
  87. }
  88. body, err := ioutil.ReadFile(path)
  89. if err != nil {
  90. panic(err)
  91. }
  92. c.String(200, string(body))
  93. })
  94. r.PUT("/slides.md", func(c *gin.Context) {
  95. path, err := mustHaveSession(c)
  96. if err != nil {
  97. return
  98. }
  99. body, _ := ioutil.ReadAll(c.Request.Body)
  100. ioutil.WriteFile(path, body, 0644)
  101. log.WithFields(log.Fields{
  102. "size": len(body),
  103. "file": path,
  104. }).Info("Wrote to file")
  105. c.String(200, "")
  106. })
  107. r.GET("/stash", func(c *gin.Context) {
  108. files, err := ioutil.ReadDir("slides")
  109. if err != nil {
  110. log.Fatal(err)
  111. }
  112. sort.Slice(files, func(i, j int) bool {
  113. return files[i].ModTime().Unix() > files[j].ModTime().Unix()
  114. })
  115. var stash []string
  116. for _, file := range files {
  117. if file.IsDir() {
  118. continue
  119. }
  120. stash = append(stash, file.Name())
  121. }
  122. c.HTML(200, "stash.tmpl", gin.H{
  123. "stash": stash,
  124. })
  125. })
  126. r.GET("/stash/edit/:name", func(c *gin.Context) {
  127. name := c.Param("name")
  128. log.WithFields(log.Fields{
  129. "name": name,
  130. }).Info("Restore session?")
  131. if strings.HasSuffix(name, ".md") {
  132. name = name[0 : len(name)-3]
  133. }
  134. path := SlidePath(name)
  135. session := sessions.Default(c)
  136. session.Set("name", path)
  137. session.Save()
  138. c.HTML(200, "index.tmpl", gin.H{
  139. "pubTo": path,
  140. })
  141. })
  142. r.GET("/published/slides/:name", func(c *gin.Context) {
  143. name := c.Param("name")
  144. log.WithFields(log.Fields{
  145. "name": name,
  146. }).Info("Published")
  147. if strings.HasSuffix(name, ".md") {
  148. name = name[0 : len(name)-3]
  149. }
  150. path := SlidePath(name)
  151. session := sessions.Default(c)
  152. session.Set("name", path)
  153. session.Save()
  154. c.HTML(200, "slides.tmpl", gin.H{
  155. "pubTo": path,
  156. })
  157. })
  158. return r
  159. }
  160. func main() {
  161. r := NewApp()
  162. port := "8080"
  163. if len(os.Args) > 1 {
  164. port = os.Args[1]
  165. } else {
  166. envPort := os.Getenv("PORT")
  167. if len(envPort) > 0 {
  168. port = envPort
  169. }
  170. }
  171. log.Info("Started http://0.0.0.0:8080")
  172. r.Run(fmt.Sprintf(":%s", port))
  173. }