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.

302 lines
7.6 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. package model
  2. import (
  3. "database/sql"
  4. "errors"
  5. "fmt"
  6. "time"
  7. "git.aiterp.net/AiteRP/aitestory/server"
  8. )
  9. // Header contains a subset of the page database
  10. // table needed for the front page. It's a read-only
  11. // model.
  12. type Header struct {
  13. ID string `json:"id"`
  14. Name string `json:"name"`
  15. Author string `json:"author"`
  16. Category string `json:"category"`
  17. FictionalDate time.Time `json:"fictionalDate"`
  18. PublishDate time.Time `json:"publishDate"`
  19. EditDate time.Time `json:"editDate"`
  20. PrimaryTag *Tag `json:"primaryTag"`
  21. }
  22. func (header *Header) Dated() bool {
  23. return !header.FictionalDate.IsZero()
  24. }
  25. // CategoryInfo gets information about the category
  26. func (header *Header) CategoryInfo() PageCategory {
  27. for _, category := range PageCategories {
  28. if category.Key == header.Category {
  29. return category
  30. }
  31. }
  32. return PageCategory{"Unknown", "Unknown", "?", "/", ""}
  33. }
  34. // Path returns the path for viewing the page
  35. func (header *Header) Path() string {
  36. return fmt.Sprintf("/page/%s", header.ID)
  37. }
  38. // ListHeaders grabs all the general pages from
  39. // the database to list them
  40. func ListHeaders() ([]Header, error) {
  41. const query = `
  42. SELECT page.id,page.name,author,category,fictional_date,publish_date,edit_date,tag.id,tag.type,tag.name
  43. FROM page
  44. LEFT JOIN page_tag ON (page.id = page_tag.page_id AND page_tag.primary = true)
  45. LEFT JOIN tag ON (tag.id = page_tag.tag_id)
  46. WHERE page.specific=false AND page.published=true AND page.unlisted=false
  47. ORDER BY page.publish_date DESC
  48. `
  49. db := server.Main.DB
  50. rows, err := db.Query(query)
  51. if err != nil {
  52. return nil, err
  53. }
  54. defer rows.Close()
  55. results := make([]Header, 0, 64)
  56. header := Header{}
  57. for rows.Next() {
  58. err := parseHeader(&header, rows)
  59. if err != nil {
  60. return nil, err
  61. }
  62. results = append(results, header)
  63. }
  64. return results, nil
  65. }
  66. // ListHeadersByCategory grabs all the pages in the given category
  67. func ListHeadersByCategory(category string) ([]Header, error) {
  68. const query = `
  69. SELECT page.id,page.name,author,category,fictional_date,publish_date,edit_date,tag.id,tag.type,tag.name
  70. FROM page
  71. LEFT JOIN page_tag ON (page.id = page_tag.page_id AND page_tag.primary = true)
  72. LEFT JOIN tag ON (tag.id = page_tag.tag_id)
  73. WHERE page.specific=false AND page.published=true AND page.unlisted=false AND page.category = ?
  74. ORDER BY page.publish_date DESC
  75. `
  76. db := server.Main.DB
  77. rows, err := db.Query(query, category)
  78. if err != nil {
  79. return nil, err
  80. }
  81. defer rows.Close()
  82. results := make([]Header, 0, 64)
  83. header := Header{}
  84. for rows.Next() {
  85. err := parseHeader(&header, rows)
  86. if err != nil {
  87. return nil, err
  88. }
  89. results = append(results, header)
  90. }
  91. return results, nil
  92. }
  93. // ListHeadersByAuthor grabs all the pages by the given author
  94. func ListHeadersByAuthor(author string) ([]Header, error) {
  95. const query = `
  96. SELECT page.id,page.name,author,category,fictional_date,publish_date,edit_date,tag.id,tag.type,tag.name
  97. FROM page
  98. LEFT JOIN page_tag ON (page.id = page_tag.page_id AND page_tag.primary = true)
  99. LEFT JOIN tag ON (tag.id = page_tag.tag_id)
  100. WHERE page.specific=false AND page.published=true AND page.unlisted=false AND page.author = ?
  101. ORDER BY page.publish_date DESC
  102. `
  103. db := server.Main.DB
  104. rows, err := db.Query(query, author)
  105. if err != nil {
  106. return nil, err
  107. }
  108. defer rows.Close()
  109. results := make([]Header, 0, 64)
  110. header := Header{}
  111. for rows.Next() {
  112. err := parseHeader(&header, rows)
  113. if err != nil {
  114. return nil, err
  115. }
  116. results = append(results, header)
  117. }
  118. return results, nil
  119. }
  120. // ListHeadersByMonth grabs all the pages within the given month
  121. func ListHeadersByMonth(year int, month int) ([]Header, error) {
  122. const query = `
  123. SELECT page.id,page.name,author,category,fictional_date,publish_date,edit_date,tag.id,tag.type,tag.name
  124. FROM page
  125. LEFT JOIN page_tag ON (page.id = page_tag.page_id AND page_tag.primary = true)
  126. LEFT JOIN tag ON (tag.id = page_tag.tag_id)
  127. WHERE page.specific=false AND page.published=true AND page.unlisted=false AND YEAR(fictional_date) = ? AND MONTH(fictional_date) = ?
  128. ORDER BY page.publish_date DESC
  129. `
  130. db := server.Main.DB
  131. rows, err := db.Query(query, year, month)
  132. if err != nil {
  133. return nil, err
  134. }
  135. defer rows.Close()
  136. results := make([]Header, 0, 64)
  137. header := Header{}
  138. for rows.Next() {
  139. err := parseHeader(&header, rows)
  140. if err != nil {
  141. return nil, err
  142. }
  143. results = append(results, header)
  144. }
  145. return results, nil
  146. }
  147. // ListHeadersByTag lists all headers that has the tag. Leave the category empty
  148. // to not filter by it
  149. func ListHeadersByTag(category string, tag *Tag) ([]Header, error) {
  150. const query1 = `
  151. SELECT page.id,page.name,page.author,page.category,page.fictional_date,page.publish_date,page.edit_date,tag.id,tag.type,tag.name
  152. FROM page_tag
  153. RIGHT JOIN page ON page.id = page_tag.page_id
  154. LEFT JOIN (page_tag AS pt2) ON (page.id = pt2.page_id AND pt2.primary = true)
  155. LEFT JOIN (tag AS tag) ON (tag.id = pt2.tag_id)
  156. WHERE page_tag.tag_id=? AND page.unlisted=false AND page.published=true
  157. ORDER BY page.publish_date DESC
  158. `
  159. const query2 = `
  160. SELECT page.id,page.name,page.author,page.category,page.fictional_date,page.publish_date,page.edit_date,tag.id,tag.type,tag.name
  161. FROM page_tag
  162. RIGHT JOIN page ON page.id = page_tag.page_id
  163. LEFT JOIN (page_tag AS pt2) ON (page.id = pt2.page_id AND pt2.primary = true)
  164. LEFT JOIN (tag AS tag) ON (tag.id = pt2.tag_id)
  165. WHERE page_tag.tag_id=? AND page.category=? AND page.unlisted=false AND page.published=true
  166. ORDER BY page.publish_date DESC
  167. `
  168. if tag == nil {
  169. return nil, errors.New("no tag")
  170. }
  171. db := server.Main.DB
  172. query := query1
  173. if category != "" {
  174. query = query2
  175. }
  176. rows, err := db.Query(query, tag.ID)
  177. if err != nil {
  178. return nil, err
  179. }
  180. defer rows.Close()
  181. results := make([]Header, 0, 64)
  182. header := Header{}
  183. for rows.Next() {
  184. err := parseHeader(&header, rows)
  185. if err != nil {
  186. return nil, err
  187. }
  188. results = append(results, header)
  189. }
  190. return results, nil
  191. }
  192. // ListHeadersByTags searches for the first tag, then filters the result based on the
  193. // others. There is room for improvement in this function, but I'll have to judge whether
  194. // there will be a need for that.
  195. func ListHeadersByTags(category string, tags []Tag) ([]Header, error) {
  196. if len(tags) == 0 {
  197. return nil, errors.New("no tags")
  198. }
  199. headers, err := ListHeadersByTag(category, &tags[0])
  200. if err != nil {
  201. return nil, err
  202. }
  203. if len(headers) == 0 {
  204. return headers, nil
  205. }
  206. for _, tag := range tags[1:] {
  207. headers2, err := ListHeadersByTag(category, &tag)
  208. if err != nil {
  209. return nil, err
  210. }
  211. results := make([]Header, 0, len(headers))
  212. for _, header := range headers {
  213. found := false
  214. for _, header2 := range headers2 {
  215. if header.ID == header2.ID {
  216. found = true
  217. break
  218. }
  219. }
  220. if found {
  221. results = append(results, header)
  222. }
  223. }
  224. headers = results
  225. }
  226. return headers, nil
  227. }
  228. func parseHeader(header *Header, rows *sql.Rows) error {
  229. var tagID, tagName, tagType string
  230. var fictionalDate, publishDate, editDate string
  231. var err error
  232. rows.Scan(&header.ID, &header.Name, &header.Author, &header.Category, &fictionalDate, &publishDate, &editDate, &tagID, &tagType, &tagName)
  233. if tagID != "" {
  234. header.PrimaryTag = &Tag{tagID, tagType, tagName}
  235. } else {
  236. header.PrimaryTag = nil
  237. }
  238. header.FictionalDate, err = time.Parse("2006-01-02 15:04:05", fictionalDate)
  239. if err != nil {
  240. header.FictionalDate = time.Time{}
  241. }
  242. header.PublishDate, err = time.Parse("2006-01-02 15:04:05", publishDate)
  243. if err != nil {
  244. return err
  245. }
  246. header.EditDate, err = time.Parse("2006-01-02 15:04:05", editDate)
  247. if err != nil {
  248. return err
  249. }
  250. return nil
  251. }