common.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package pub
  2. import (
  3. "mimicry/object"
  4. "fmt"
  5. "errors"
  6. "net/url"
  7. )
  8. var (
  9. ErrWrongType = errors.New("item is the wrong type")
  10. )
  11. const (
  12. timeFormat = "3:04 pm on 2 Jan 2006"
  13. )
  14. /*
  15. This implements functions common to the different types.
  16. - getActors
  17. - getCollection
  18. - getActor
  19. - getPostOrActor
  20. - NewTangible
  21. // these will return an error on any problem
  22. - getBestLink, link impl will need the link, Rating(), mediatype, and be willing to take in Posts or Links
  23. - getFirstLinkShorthand
  24. - getBestLinkShorthand
  25. // used exclusively for attachments, honestly I
  26. // think it should probably return markup.
  27. // probably should actually be a function within
  28. // Post
  29. - getLinks
  30. */
  31. type TangibleWithName interface {
  32. Tangible
  33. Name() string
  34. }
  35. func getActors(o object.Object, key string, source *url.URL) []TangibleWithName {
  36. list, err := o.GetList(key)
  37. if errors.Is(err, object.ErrKeyNotPresent) {
  38. return []TangibleWithName{}
  39. } else if err != nil {
  40. return []TangibleWithName{NewFailure(err)}
  41. }
  42. // TODO: parallelize will probably require making fixed size
  43. // full width, swapping publics for nils, then later filtering
  44. // out the nils to reach a dynamic width
  45. output := []TangibleWithName{}
  46. for _, element := range list {
  47. if narrowed, ok := element.(string); ok {
  48. if narrowed == "https://www.w3.org/ns/activitystreams#Public" ||
  49. narrowed == "as:Public" ||
  50. narrowed == "Public" {
  51. continue
  52. }
  53. }
  54. fetched, err := NewActor(element, source)
  55. if err != nil {
  56. output = append(output, NewFailure(err))
  57. } else {
  58. output = append(output, fetched)
  59. }
  60. }
  61. return output
  62. }
  63. func getPostOrActor(o object.Object, key string, source *url.URL) Tangible {
  64. reference, err := o.GetAny(key)
  65. if err != nil {
  66. return NewFailure(err)
  67. }
  68. // TODO: add special case for lemmy where a json object with
  69. // type Create is automatically unwrapped right here
  70. var fetched Tangible
  71. fetched, err = NewActor(reference, source)
  72. if errors.Is(err, ErrWrongType) {
  73. fetched, err = NewPost(reference, source)
  74. }
  75. if err != nil {
  76. return NewFailure(err)
  77. }
  78. return fetched
  79. }
  80. func getCollection(o object.Object, key string, source *url.URL) (*Collection, error) {
  81. reference, err := o.GetAny(key)
  82. if err != nil {
  83. return nil, err
  84. }
  85. fetched, err := NewCollection(reference, source)
  86. if err != nil {
  87. return nil, err
  88. }
  89. return fetched, nil
  90. }
  91. func getActor(o object.Object, key string, source *url.URL) (*Actor, error) {
  92. reference, err := o.GetAny(key)
  93. if err != nil {
  94. return nil, err
  95. }
  96. fetched, err := NewActor(reference, source)
  97. if err != nil {
  98. return nil, err
  99. }
  100. return fetched, nil
  101. }
  102. func NewTangible(input any, source *url.URL) Tangible {
  103. var fetched Tangible
  104. fetched, err := NewPost(input, source)
  105. if errors.Is(err, ErrWrongType) {
  106. fetched, err = NewActor(input, source)
  107. }
  108. if errors.Is(err, ErrWrongType) {
  109. fetched, err = NewActivity(input, source)
  110. }
  111. if errors.Is(err, ErrWrongType) {
  112. return NewFailure(err)
  113. }
  114. if err != nil {
  115. return NewFailure(err)
  116. }
  117. return fetched
  118. }
  119. /*
  120. "Shorthand" just means individual strings are converted into Links
  121. */
  122. func getLinksShorthand(o object.Object, key string) ([]*Link, error) {
  123. list, err := o.GetList(key)
  124. if err != nil {
  125. return nil, err
  126. }
  127. output := make([]*Link, len(list))
  128. for i, element := range list {
  129. switch narrowed := element.(type) {
  130. case object.Object:
  131. link, err := NewLink(narrowed)
  132. if err != nil {
  133. return nil, err
  134. }
  135. output[i] = link
  136. case string:
  137. link, err := NewLink(object.Object {
  138. "type": "Link",
  139. "href": narrowed,
  140. })
  141. if err != nil {
  142. return nil, err
  143. }
  144. output[i] = link
  145. default:
  146. return nil, fmt.Errorf("can't convert a %T into a Link", element)
  147. }
  148. }
  149. return output, nil
  150. }
  151. func getBestLinkShorthand(o object.Object, key string, supertype string) (*Link, error) {
  152. links, err := getLinksShorthand(o, key)
  153. if err != nil {
  154. return nil, err
  155. }
  156. return SelectBestLink(links, supertype)
  157. }
  158. func getFirstLinkShorthand(o object.Object, key string) (*Link, error) {
  159. links, err := getLinksShorthand(o, key)
  160. if err != nil {
  161. return nil, err
  162. }
  163. return SelectFirstLink(links)
  164. }
  165. func getLinks(o object.Object, key string) ([]*Link, error) {
  166. list, err := o.GetList(key)
  167. if err != nil {
  168. return nil, err
  169. }
  170. links := make([]*Link, len(list))
  171. for i, element := range list {
  172. link, err := NewLink(element)
  173. if err != nil {
  174. return nil, err
  175. }
  176. links[i] = link
  177. }
  178. return links, nil
  179. }
  180. func getBestLink(o object.Object, key string, supertype string) (*Link, error) {
  181. links, err := getLinks(o, key)
  182. if err != nil { return nil, err }
  183. return SelectBestLink(links, supertype)
  184. }