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.

183 lines
4.4 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. Files []*File `bson:"files"`
  24. }
  25. // AddObject adds the model into the appropriate array.
  26. func (change *Change) AddObject(object interface{}) bool {
  27. if v := reflect.ValueOf(object); v.Kind() == reflect.Struct {
  28. ptr := reflect.PtrTo(v.Type())
  29. ptrValue := reflect.New(ptr.Elem())
  30. ptrValue.Elem().Set(v)
  31. object = ptrValue.Interface()
  32. }
  33. switch object := object.(type) {
  34. case *Log:
  35. change.Logs = append(change.Logs, object)
  36. case []*Log:
  37. change.Logs = append(change.Logs, object...)
  38. case *Character:
  39. change.Characters = append(change.Characters, object)
  40. case []*Character:
  41. change.Characters = append(change.Characters, object...)
  42. case *Channel:
  43. change.Channels = append(change.Channels, object)
  44. case []*Channel:
  45. change.Channels = append(change.Channels, object...)
  46. case *Post:
  47. change.Posts = append(change.Posts, object)
  48. case []*Post:
  49. change.Posts = append(change.Posts, object...)
  50. case *Story:
  51. change.Stories = append(change.Stories, object)
  52. case []*Story:
  53. change.Stories = append(change.Stories, object...)
  54. case *Tag:
  55. change.Tags = append(change.Tags, object)
  56. case []*Tag:
  57. change.Tags = append(change.Tags, object...)
  58. case *Chapter:
  59. change.Chapters = append(change.Chapters, object)
  60. case []*Chapter:
  61. change.Chapters = append(change.Chapters, object...)
  62. case *Comment:
  63. change.Comments = append(change.Comments, object)
  64. case []*Comment:
  65. change.Comments = append(change.Comments, object...)
  66. case *File:
  67. change.Files = append(change.Files, object)
  68. case []*File:
  69. change.Files = append(change.Files, object...)
  70. default:
  71. return false
  72. }
  73. return true
  74. }
  75. // Objects makes a combined, mixed array of all the models stored in this change.
  76. func (change *Change) Objects() []interface{} {
  77. data := make([]interface{}, 0, 8)
  78. for _, log := range change.Logs {
  79. data = append(data, log)
  80. }
  81. for _, channel := range change.Channels {
  82. data = append(data, channel)
  83. }
  84. for _, character := range change.Characters {
  85. data = append(data, character)
  86. }
  87. for _, post := range change.Posts {
  88. data = append(data, post)
  89. }
  90. for _, story := range change.Stories {
  91. data = append(data, story)
  92. }
  93. for _, tag := range change.Tags {
  94. data = append(data, tag)
  95. }
  96. for _, chapter := range change.Chapters {
  97. data = append(data, chapter)
  98. }
  99. for _, comment := range change.Comments {
  100. data = append(data, comment)
  101. }
  102. for _, file := range change.Files {
  103. data = append(data, file)
  104. }
  105. return data
  106. }
  107. func (change *Change) PassesFilter(filter ChangeFilter) bool {
  108. if filter.Author != nil && change.Author != *filter.Author {
  109. return false
  110. }
  111. // For unlisted changes, pass it only if the filter refers to the specific index.
  112. if !change.Listed {
  113. hasSpecificKey := false
  114. KeyFindLoop:
  115. for _, key := range filter.Keys {
  116. if key.ID == "*" {
  117. continue
  118. }
  119. for _, changeKey := range change.Keys {
  120. if changeKey.Model == key.Model && changeKey.ID == key.ID {
  121. hasSpecificKey = true
  122. break KeyFindLoop
  123. }
  124. }
  125. }
  126. if !hasSpecificKey {
  127. return false
  128. }
  129. }
  130. if filter.EarliestDate != nil && filter.EarliestDate.Before(change.Date) {
  131. return false
  132. }
  133. if len(filter.Keys) > 0 {
  134. foundKey := false
  135. KeyFindLoop2:
  136. for _, key := range filter.Keys {
  137. for _, changeKey := range change.Keys {
  138. if changeKey == key {
  139. foundKey = true
  140. break KeyFindLoop2
  141. }
  142. }
  143. }
  144. if !foundKey {
  145. return false
  146. }
  147. }
  148. return true
  149. }
  150. // ChangeKey is a key for a change that can be used when subscribing to them.
  151. type ChangeKey struct {
  152. Model ChangeModel `bson:"model"`
  153. ID string `bson:"id"`
  154. }
  155. // ChangeFilter is a filter for listing changes.
  156. type ChangeFilter struct {
  157. Keys []ChangeKey
  158. EarliestDate *time.Time
  159. Author *string
  160. Limit *int
  161. }