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.

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