A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
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.
 
 
 
 
 

168 lines
3.8 KiB

  1. /*
  2. * Copyright © 2020 Musing Studio LLC.
  3. *
  4. * This file is part of WriteFreely.
  5. *
  6. * WriteFreely is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License, included
  8. * in the LICENSE file in this source code package.
  9. */
  10. package writefreely
  11. import (
  12. "bytes"
  13. "fmt"
  14. "io"
  15. "net/url"
  16. "regexp"
  17. "strings"
  18. "github.com/writeas/web-core/log"
  19. "github.com/writefreely/go-gopher"
  20. )
  21. func initGopher(apper Apper) {
  22. handler := NewWFHandler(apper)
  23. gopher.HandleFunc("/", handler.Gopher(handleGopher))
  24. log.Info("Serving on gopher://localhost:%d", apper.App().Config().Server.GopherPort)
  25. gopher.ListenAndServe(fmt.Sprintf(":%d", apper.App().Config().Server.GopherPort), nil)
  26. }
  27. // Utility function to strip the URL from the hostname provided by app.cfg.App.Host
  28. func stripHostProtocol(app *App) string {
  29. u, err := url.Parse(app.cfg.App.Host)
  30. if err != nil {
  31. // Fall back to host, with scheme stripped
  32. return string(regexp.MustCompile("^.*://").ReplaceAll([]byte(app.cfg.App.Host), []byte("")))
  33. }
  34. return u.Hostname()
  35. }
  36. func handleGopher(app *App, w gopher.ResponseWriter, r *gopher.Request) error {
  37. parts := strings.Split(r.Selector, "/")
  38. if app.cfg.App.SingleUser {
  39. if parts[1] != "" {
  40. return handleGopherCollectionPost(app, w, r)
  41. }
  42. return handleGopherCollection(app, w, r)
  43. }
  44. // Show all public collections (a gopher Reader view, essentially)
  45. if len(parts) == 3 {
  46. return handleGopherCollection(app, w, r)
  47. }
  48. w.WriteInfo(fmt.Sprintf("Welcome to %s", app.cfg.App.SiteName))
  49. colls, err := app.db.GetPublicCollections(app.cfg.App.Host)
  50. if err != nil {
  51. return err
  52. }
  53. for _, c := range *colls {
  54. w.WriteItem(&gopher.Item{
  55. Host: stripHostProtocol(app),
  56. Port: app.cfg.Server.GopherPort,
  57. Type: gopher.DIRECTORY,
  58. Description: c.DisplayTitle(),
  59. Selector: "/" + c.Alias + "/",
  60. })
  61. }
  62. return w.End()
  63. }
  64. func handleGopherCollection(app *App, w gopher.ResponseWriter, r *gopher.Request) error {
  65. var collAlias, slug string
  66. var c *Collection
  67. var err error
  68. var baseSel = "/"
  69. parts := strings.Split(r.Selector, "/")
  70. if app.cfg.App.SingleUser {
  71. // sanity check
  72. slug = parts[1]
  73. if slug != "" {
  74. return handleGopherCollectionPost(app, w, r)
  75. }
  76. c, err = app.db.GetCollectionByID(1)
  77. if err != nil {
  78. return err
  79. }
  80. } else {
  81. collAlias = parts[1]
  82. slug = parts[2]
  83. if slug != "" {
  84. return handleGopherCollectionPost(app, w, r)
  85. }
  86. c, err = app.db.GetCollection(collAlias)
  87. if err != nil {
  88. return err
  89. }
  90. baseSel = "/" + c.Alias + "/"
  91. }
  92. c.hostName = app.cfg.App.Host
  93. w.WriteInfo(c.DisplayTitle())
  94. if c.Description != "" {
  95. w.WriteInfo(c.Description)
  96. }
  97. posts, err := app.db.GetPosts(app.cfg, c, 0, false, false, false)
  98. if err != nil {
  99. return err
  100. }
  101. for _, p := range *posts {
  102. w.WriteItem(&gopher.Item{
  103. Port: app.cfg.Server.GopherPort,
  104. Host: stripHostProtocol(app),
  105. Type: gopher.FILE,
  106. Description: p.CreatedDate() + " - " + p.DisplayTitle(),
  107. Selector: baseSel + p.Slug.String,
  108. })
  109. }
  110. return w.End()
  111. }
  112. func handleGopherCollectionPost(app *App, w gopher.ResponseWriter, r *gopher.Request) error {
  113. var collAlias, slug string
  114. var c *Collection
  115. var err error
  116. parts := strings.Split(r.Selector, "/")
  117. if app.cfg.App.SingleUser {
  118. slug = parts[1]
  119. c, err = app.db.GetCollectionByID(1)
  120. if err != nil {
  121. return err
  122. }
  123. } else {
  124. collAlias = parts[1]
  125. slug = parts[2]
  126. c, err = app.db.GetCollection(collAlias)
  127. if err != nil {
  128. return err
  129. }
  130. }
  131. c.hostName = app.cfg.App.Host
  132. p, err := app.db.GetPost(slug, c.ID)
  133. if err != nil {
  134. return err
  135. }
  136. b := bytes.Buffer{}
  137. if p.Title.String != "" {
  138. b.WriteString(p.Title.String + "\n")
  139. }
  140. b.WriteString(p.DisplayDate + "\n\n")
  141. b.WriteString(p.Content)
  142. io.Copy(w, &b)
  143. return w.End()
  144. }