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.

171 lines
4.1 KiB

  1. package models
  2. import (
  3. "reflect"
  4. "time"
  5. )
  6. // Change represents a change in the rpdata history through the API.
  7. type Change struct {
  8. ID string `bson:"_id"`
  9. Model ChangeModel `bson:"model"`
  10. Op string `bson:"op"`
  11. Author string `bson:"author"`
  12. Listed bool `bson:"listed"`
  13. Keys []ChangeKey `bson:"keys"`
  14. Date time.Time `bson:"date"`
  15. Logs []*Log `bson:"logs"`
  16. Characters []*Character `bson:"characters"`
  17. Channels []*Channel `bson:"channels"`
  18. Posts []*Post `bson:"posts"`
  19. Stories []*Story `bson:"stories"`
  20. Tags []*Tag `bson:"tags"`
  21. Chapters []*Chapter `bson:"chapters"`
  22. Comments []*Comment `bson:"comments"`
  23. }
  24. // AddObject adds the model into the appropriate array.
  25. func (change *Change) AddObject(object interface{}) bool {
  26. if v := reflect.ValueOf(object); v.Kind() != reflect.Ptr && v.Kind() != reflect.Slice {
  27. return change.AddObject(v.Addr().Interface())
  28. }
  29. switch object := object.(type) {
  30. case *Log:
  31. change.Logs = append(change.Logs, object)
  32. case []*Log:
  33. change.Logs = append(change.Logs, object...)
  34. case *Character:
  35. change.Characters = append(change.Characters, object)
  36. case []*Character:
  37. change.Characters = append(change.Characters, object...)
  38. case *Channel:
  39. change.Channels = append(change.Channels, object)
  40. case []*Channel:
  41. change.Channels = append(change.Channels, object...)
  42. case *Post:
  43. change.Posts = append(change.Posts, object)
  44. case []*Post:
  45. change.Posts = append(change.Posts, object...)
  46. case *Story:
  47. change.Stories = append(change.Stories, object)
  48. case []*Story:
  49. change.Stories = append(change.Stories, object...)
  50. case *Tag:
  51. change.Tags = append(change.Tags, object)
  52. case []*Tag:
  53. change.Tags = append(change.Tags, object...)
  54. case *Chapter:
  55. change.Chapters = append(change.Chapters, object)
  56. case []*Chapter:
  57. change.Chapters = append(change.Chapters, object...)
  58. case *Comment:
  59. change.Comments = append(change.Comments, object)
  60. case []*Comment:
  61. change.Comments = append(change.Comments, object...)
  62. default:
  63. return false
  64. }
  65. return true
  66. }
  67. // Objects makes a combined, mixed array of all the models stored in this change.
  68. func (change *Change) Objects() []interface{} {
  69. data := make([]interface{}, 0, 8)
  70. for _, log := range change.Logs {
  71. data = append(data, log)
  72. }
  73. for _, channel := range change.Channels {
  74. data = append(data, channel)
  75. }
  76. for _, character := range change.Characters {
  77. data = append(data, character)
  78. }
  79. for _, post := range change.Posts {
  80. data = append(data, post)
  81. }
  82. for _, story := range change.Stories {
  83. data = append(data, story)
  84. }
  85. for _, tag := range change.Tags {
  86. data = append(data, tag)
  87. }
  88. for _, chapter := range change.Chapters {
  89. data = append(data, chapter)
  90. }
  91. for _, comment := range change.Comments {
  92. data = append(data, comment)
  93. }
  94. return data
  95. }
  96. func (change *Change) PassesFilter(filter ChangeFilter) bool {
  97. if filter.Author != nil && change.Author != *filter.Author {
  98. return false
  99. }
  100. // For unlisted changes, pass it only if the filter refers to the specific index.
  101. if !change.Listed {
  102. hasSpecificKey := false
  103. KeyFindLoop:
  104. for _, key := range filter.Keys {
  105. if key.ID == "*" {
  106. continue
  107. }
  108. for _, changeKey := range change.Keys {
  109. if changeKey.Model == key.Model && changeKey.ID == key.ID {
  110. hasSpecificKey = true
  111. break KeyFindLoop
  112. }
  113. }
  114. }
  115. if !hasSpecificKey {
  116. return false
  117. }
  118. }
  119. if filter.EarliestDate != nil && filter.EarliestDate.Before(change.Date) {
  120. return false
  121. }
  122. if len(filter.Keys) > 0 {
  123. foundKey := false
  124. KeyFindLoop2:
  125. for _, key := range filter.Keys {
  126. for _, changeKey := range change.Keys {
  127. if changeKey == key {
  128. foundKey = true
  129. break KeyFindLoop2
  130. }
  131. }
  132. }
  133. if !foundKey {
  134. return false
  135. }
  136. }
  137. return true
  138. }
  139. // ChangeKey is a key for a change that can be used when subscribing to them.
  140. type ChangeKey struct {
  141. Model ChangeModel `bson:"model"`
  142. ID string `bson:"id"`
  143. }
  144. // ChangeFilter is a filter for listing changes.
  145. type ChangeFilter struct {
  146. Keys []ChangeKey
  147. EarliestDate *time.Time
  148. Author *string
  149. Limit *int
  150. }