The backend for the AiteStory website
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.

146 lines
4.1 KiB

7 years ago
  1. package model
  2. import (
  3. "fmt"
  4. "net/url"
  5. "time"
  6. "git.aiterp.net/AiteRP/aitestory/formparser"
  7. "git.aiterp.net/gisle/wrouter/generate"
  8. "github.com/microcosm-cc/bluemonday"
  9. "github.com/russross/blackfriday"
  10. )
  11. // PageCategories are used by the view model and page to enforce
  12. // a limited selection of categories. I may move it to a configuration
  13. var PageCategories = []string{
  14. "OoC",
  15. "Story",
  16. "Background",
  17. "Document",
  18. "News",
  19. "Item",
  20. "Info",
  21. }
  22. // PageTypes describes how the source is rendered. For now it's only markdown,
  23. // but who knows what the future holds.
  24. var PageTypes = []string{
  25. "Markdown",
  26. }
  27. // PageMinDate is the earliest date possible. Stories from Matriarch Eriana's childhood
  28. // are thus not going to happen.
  29. var PageMinDate, _ = time.Parse(time.RFC3339, "1753-01-01T00:00:00Z")
  30. // Page is the model describing the individual articles posted
  31. // by users.
  32. type Page struct {
  33. ID string `json:"id"`
  34. Name string `json:"name"`
  35. Author string `json:"author"`
  36. Category string `json:"category"`
  37. FictionalDate time.Time `json:"fictionalDate"`
  38. PublishDate time.Time `json:"publishDate"`
  39. EditDate time.Time `json:"editDate"`
  40. Dated bool `json:"dated"`
  41. Published bool `json:"published"`
  42. Unlisted bool `json:"unlisted"`
  43. Specific bool `json:"specific"`
  44. Indexed bool `json:"indexed"`
  45. BackgroundURL string `json:"backgroundUrl"`
  46. Type string `json:"type"`
  47. Source string `json:"source"`
  48. cachedOutput string
  49. }
  50. // Defaults fills in the default details for a page, suited for populating a form
  51. func (page *Page) Defaults() {
  52. page.Category = PageCategories[0]
  53. page.Dated = true
  54. page.Published = true
  55. page.Unlisted = false
  56. page.Specific = false
  57. page.Indexed = true
  58. page.BackgroundURL = ""
  59. page.Type = PageTypes[0]
  60. page.Source = ""
  61. }
  62. // Insert adds the page to the database
  63. func (page *Page) Insert() error {
  64. page.generateID()
  65. return nil
  66. }
  67. // Content parses the content of the page
  68. func (page *Page) Content() (string, error) {
  69. if page.cachedOutput != "" {
  70. return page.cachedOutput, nil
  71. }
  72. if page.Type == "Markdown" {
  73. // TODO: Convert [[Ehanis Tioran]] to [Ehanis Tioran](https://wiki.aiterp.net/index.php?title=Ehanis%20Tioran)
  74. unsafe := blackfriday.MarkdownCommon([]byte(page.Source))
  75. page.cachedOutput = string(bluemonday.UGCPolicy().SanitizeBytes(unsafe))
  76. return page.cachedOutput, nil
  77. }
  78. return "", fmt.Errorf("Page type '%s' is not supported", page.Type)
  79. }
  80. // ParseForm validates the values in a form and sets the page's values whenever possible regardless
  81. // so that it can be pushed to the viewmodel to allow the user to correct their mistakes without fear
  82. // of losing their hard work
  83. func (page *Page) ParseForm(form url.Values) []error {
  84. errors := make([]error, 0, 4)
  85. page.cachedOutput = ""
  86. err := formparser.Select(form.Get("category"), &page.Category, PageCategories, page.Category != "")
  87. if err != nil {
  88. errors = append(errors, fmt.Errorf("Category: %s", err))
  89. }
  90. err = formparser.Date(form.Get("fictionalDate"), &page.FictionalDate, !page.FictionalDate.IsZero())
  91. if err != nil {
  92. errors = append(errors, fmt.Errorf("Fictonal Date: %s", err))
  93. }
  94. page.Dated = form.Get("dated") != ""
  95. page.Published = form.Get("published") != ""
  96. page.Unlisted = form.Get("unlisted") != ""
  97. page.Specific = form.Get("specific") != ""
  98. page.Indexed = form.Get("indexed") != ""
  99. err = formparser.String(form.Get("backgroundUrl"), &page.BackgroundURL, 0, 255)
  100. if err != nil {
  101. errors = append(errors, fmt.Errorf("Background URL: %s", err))
  102. }
  103. err = formparser.Select(form.Get("type"), &page.Type, PageTypes, page.Type != "")
  104. if err != nil {
  105. errors = append(errors, fmt.Errorf("Category: %s", err))
  106. }
  107. err = formparser.String(form.Get("source"), &page.Source, 0, 102400)
  108. if err != nil {
  109. errors = append(errors, fmt.Errorf("Content is too long, max: 100 KB (~17,000 words)"))
  110. }
  111. if len(errors) > 0 {
  112. errors = nil
  113. }
  114. return errors
  115. }
  116. // Standardize page ID generation
  117. func (page *Page) generateID() {
  118. page.ID = generate.FriendlyID(16)
  119. }