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.

177 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 {
  27. return change.AddObject(v.Elem().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.PassAll {
  98. return true
  99. }
  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. PassAll bool // DO NOT EXPOSE
  154. }