GraphQL API and utilities for the rpdata project
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.

111 lines
2.7 KiB

  1. package story
  2. import (
  3. "crypto/rand"
  4. "encoding/binary"
  5. "strconv"
  6. "time"
  7. "git.aiterp.net/rpdata/api/internal/store"
  8. "github.com/globalsign/mgo"
  9. "github.com/globalsign/mgo/bson"
  10. )
  11. var chapterCollection *mgo.Collection
  12. // A Chapter is a part of a story.
  13. type Chapter struct {
  14. ID string `bson:"_id"`
  15. StoryID string `bson:"storyId"`
  16. Title string `bson:"title"`
  17. Author string `bson:"author"`
  18. Source string `bson:"source"`
  19. CreatedDate time.Time `bson:"createdDate"`
  20. FictionalDate time.Time `bson:"fictionalDate,omitempty"`
  21. EditedDate time.Time `bson:"editedDate"`
  22. }
  23. // Edit edits a chapter, and updates EditedDate. While many Edit functions cheat if there's nothing to
  24. // change, this functill will due to EditedDate.
  25. func (chapter *Chapter) Edit(title, source *string, fictionalDate *time.Time) error {
  26. now := time.Now()
  27. changes := bson.M{"editedDate": now}
  28. changed := *chapter
  29. changed.EditedDate = now
  30. if title != nil && *title != chapter.Title {
  31. changes["title"] = *title
  32. changed.Title = *title
  33. }
  34. if source != nil && *source != chapter.Source {
  35. changes["source"] = *source
  36. changed.Source = *source
  37. }
  38. if fictionalDate != nil && !fictionalDate.Equal(chapter.FictionalDate) {
  39. changes["fictionalDate"] = *fictionalDate
  40. changed.FictionalDate = *fictionalDate
  41. }
  42. err := chapterCollection.UpdateId(chapter.ID, bson.M{"$set": changes})
  43. if err != nil {
  44. return err
  45. }
  46. *chapter = changed
  47. return nil
  48. }
  49. // Remove removes a chapter.
  50. func (chapter *Chapter) Remove() error {
  51. return chapterCollection.RemoveId(chapter.ID)
  52. }
  53. // FindChapterID finds a chapter by its own ID
  54. func FindChapterID(id string) (Chapter, error) {
  55. chapter := Chapter{}
  56. err := chapterCollection.FindId(id).One(&chapter)
  57. return chapter, err
  58. }
  59. // ListChapterStoryID lists all chapters for the story ID
  60. func ListChapterStoryID(storyID string) ([]Chapter, error) {
  61. chapters := make([]Chapter, 0, 8)
  62. err := chapterCollection.Find(bson.M{"storyId": storyID}).Sort("createdDate").All(&chapters)
  63. if err != nil {
  64. return nil, err
  65. }
  66. return chapters, nil
  67. }
  68. // makeChapterID makes a random chapter ID that's 24 characters long
  69. func makeChapterID() string {
  70. result := "SC"
  71. offset := 0
  72. data := make([]byte, 32)
  73. rand.Read(data)
  74. for len(result) < 24 {
  75. result += strconv.FormatUint(binary.LittleEndian.Uint64(data[offset:]), 36)
  76. offset += 8
  77. if offset >= 32 {
  78. rand.Read(data)
  79. offset = 0
  80. }
  81. }
  82. return result[:24]
  83. }
  84. func init() {
  85. store.HandleInit(func(db *mgo.Database) {
  86. chapterCollection = db.C("story.chapters")
  87. chapterCollection.EnsureIndexKey("storyId")
  88. chapterCollection.EnsureIndexKey("author")
  89. chapterCollection.EnsureIndexKey("createdDate")
  90. })
  91. }