Dynamic.hs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. {-# LANGUAGE OverloadedStrings #-}
  2. {-|
  3. Module : Codec.ActivityStream.Dynamic
  4. Description : A (more dynamic) interface to Activity Streams
  5. Copyright : (c) Getty Ritter, 2014
  6. Maintainer : gdritter@galois.com
  7. This is an interface to ActivityStreams that simply wraps an underlying
  8. @aeson@ Object, and exposes a set of (convenient) lenses to access the
  9. values inside. If an @aeson@ object is wrapped in the respective wrapper,
  10. it will contain the obligatory values for that type (e.g. an @Activity@
  11. is guaranteed to have a @published@ date.)
  12. -}
  13. module Codec.ActivityStream.Dynamic
  14. ( Lens'
  15. -- * MediaLink
  16. , MediaLink
  17. , mlDuration
  18. , mlHeight
  19. , mlWidth
  20. , mlURL
  21. , mlRest
  22. , makeMediaLink
  23. -- * Object
  24. , Object
  25. , oAttachments
  26. , oAuthor
  27. , oContent
  28. , oDisplayName
  29. , oDownstreamDuplicates
  30. , oId
  31. , oImage
  32. , oObjectType
  33. , oPublished
  34. , oSummary
  35. , oUpdated
  36. , oUpstreamDuplicates
  37. , oURL
  38. , oRest
  39. , emptyObject
  40. -- * Activity
  41. , Activity
  42. , acActor
  43. , acContent
  44. , acGenerator
  45. , acIcon
  46. , acId
  47. , acObject
  48. , acPublished
  49. , acProvider
  50. , acTarget
  51. , acTitle
  52. , acUpdated
  53. , acURL
  54. , acVerb
  55. , acRest
  56. , makeActivity
  57. , asObject
  58. -- * Collection
  59. , Collection
  60. , cTotalItems
  61. , cItems
  62. , cURL
  63. , cRest
  64. , makeCollection
  65. ) where
  66. import Data.Aeson ( FromJSON(..)
  67. , ToJSON(..)
  68. , Result(..)
  69. , fromJSON
  70. )
  71. import qualified Data.Aeson as A
  72. import Data.DateTime (DateTime)
  73. import qualified Data.HashMap.Strict as HM
  74. import Data.Text (Text)
  75. import Codec.ActivityStream.LensInternal ( Lens'
  76. , makeLens
  77. , makeAesonLens
  78. , makeAesonLensMb
  79. )
  80. data MediaLink = MediaLink { fromMediaLink :: A.Object } deriving (Eq, Show)
  81. instance FromJSON MediaLink where
  82. parseJSON (A.Object o) | HM.member "url" o = return (MediaLink o)
  83. | otherwise = fail "..."
  84. parseJSON _ = fail "..."
  85. instance ToJSON MediaLink where
  86. toJSON (MediaLink o) = A.Object o
  87. mlRest :: Lens' MediaLink A.Object
  88. mlRest = makeLens fromMediaLink (\ o' m -> m { fromMediaLink = o' })
  89. mlDuration :: Lens' MediaLink (Maybe Int)
  90. mlDuration = makeAesonLensMb "duration" mlRest
  91. mlHeight :: Lens' MediaLink (Maybe Int)
  92. mlHeight = makeAesonLensMb "height" mlRest
  93. mlWidth :: Lens' MediaLink (Maybe Int)
  94. mlWidth = makeAesonLensMb "width" mlRest
  95. mlURL :: Lens' MediaLink Text
  96. mlURL = makeAesonLens "url" mlRest
  97. -- | Create a @MediaLink@ with just a @url@ property.
  98. makeMediaLink :: Text -> MediaLink
  99. makeMediaLink url = MediaLink (HM.insert "url" (toJSON url) HM.empty)
  100. -- | Object
  101. data Object = Object { fromObject :: A.Object } deriving (Eq, Show)
  102. instance FromJSON Object where
  103. parseJSON (A.Object o) = return (Object o)
  104. parseJSON _ = fail "..."
  105. instance ToJSON Object where
  106. toJSON (Object o) = A.Object o
  107. oRest :: Lens' Object A.Object
  108. oRest = makeLens fromObject (\ o' m -> m { fromObject = o' })
  109. oAttachments :: Lens' Object (Maybe [Object])
  110. oAttachments = makeAesonLensMb "attachments" oRest
  111. oAuthor :: Lens' Object (Maybe Object)
  112. oAuthor = makeAesonLensMb "author" oRest
  113. oContent :: Lens' Object (Maybe Text)
  114. oContent = makeAesonLensMb "content" oRest
  115. oDisplayName :: Lens' Object (Maybe Text)
  116. oDisplayName = makeAesonLensMb "displayName" oRest
  117. oDownstreamDuplicates :: Lens' Object (Maybe [Text])
  118. oDownstreamDuplicates = makeAesonLensMb "downstreamDuplicates" oRest
  119. oId :: Lens' Object (Maybe Text)
  120. oId = makeAesonLensMb "id" oRest
  121. oImage :: Lens' Object (Maybe MediaLink)
  122. oImage = makeAesonLensMb "image" oRest
  123. oObjectType :: (FromJSON o, ToJSON o) => Lens' Object (Maybe o)
  124. oObjectType = makeAesonLensMb "objectType" oRest
  125. oPublished :: Lens' Object (Maybe DateTime)
  126. oPublished = makeAesonLensMb "published" oRest
  127. oSummary :: Lens' Object (Maybe Text)
  128. oSummary = makeAesonLensMb "summary" oRest
  129. oUpdated :: Lens' Object (Maybe DateTime)
  130. oUpdated = makeAesonLensMb "updated" oRest
  131. oUpstreamDuplicates :: Lens' Object (Maybe [Text])
  132. oUpstreamDuplicates = makeAesonLensMb "upstreamDuplicates" oRest
  133. oURL :: Lens' Object (Maybe Text)
  134. oURL = makeAesonLensMb "url" oRest
  135. -- | Create an @Object@ with no fields.
  136. emptyObject :: Object
  137. emptyObject = Object HM.empty
  138. -- | Activity
  139. data Activity = Activity { fromActivity :: A.Object } deriving (Eq, Show)
  140. instance FromJSON Activity where
  141. parseJSON (A.Object o)
  142. | HM.member "published" o && HM.member "provider" o = return (Activity o)
  143. | otherwise = fail "..."
  144. parseJSON _ = fail "..."
  145. instance ToJSON Activity where
  146. toJSON (Activity o) = A.Object o
  147. acRest :: Lens' Activity A.Object
  148. acRest = makeLens fromActivity (\ o' m -> m { fromActivity = o' })
  149. acActor :: Lens' Activity Object
  150. acActor = makeAesonLens "actor" acRest
  151. acContent :: Lens' Activity (Maybe Text)
  152. acContent = makeAesonLensMb "content" acRest
  153. acGenerator :: Lens' Activity (Maybe Object)
  154. acGenerator = makeAesonLens "generator" acRest
  155. acIcon :: Lens' Activity (Maybe MediaLink)
  156. acIcon = makeAesonLensMb "icon" acRest
  157. acId :: Lens' Activity (Maybe Text)
  158. acId = makeAesonLensMb "id" acRest
  159. acObject :: Lens' Activity (Maybe Object)
  160. acObject = makeAesonLensMb "object" acRest
  161. acPublished :: Lens' Activity DateTime
  162. acPublished = makeAesonLens "published" acRest
  163. acProvider :: Lens' Activity (Maybe Object)
  164. acProvider = makeAesonLensMb "provider" acRest
  165. acTarget :: Lens' Activity (Maybe Object)
  166. acTarget = makeAesonLensMb "target" acRest
  167. acTitle :: Lens' Activity (Maybe Text)
  168. acTitle = makeAesonLensMb "title" acRest
  169. acUpdated :: Lens' Activity (Maybe DateTime)
  170. acUpdated = makeAesonLensMb "updated" acRest
  171. acURL :: Lens' Activity (Maybe Text)
  172. acURL = makeAesonLensMb "url" acRest
  173. acVerb :: (FromJSON v, ToJSON v) => Lens' Activity (Maybe v)
  174. acVerb = makeAesonLensMb "verb" acRest
  175. -- | Create an @Activity@ with an @actor@, @published@, and
  176. -- @provider@ property.
  177. makeActivity :: Object -> DateTime -> Activity
  178. makeActivity actor published = Activity
  179. $ HM.insert "actor" (toJSON actor)
  180. $ HM.insert "published" (toJSON published)
  181. $ HM.empty
  182. -- | JSON Activity Streams 1.0 specificies that an @Activity@ may be used as an
  183. -- @Object@. In such a case, the object may have fields permitted on either an
  184. -- @Activity@ or an @Object@
  185. asObject :: Activity -> Object
  186. asObject act = Object (fromActivity act)
  187. -- | Collection
  188. data Collection = Collection { fromCollection :: A.Object } deriving (Eq, Show)
  189. instance FromJSON Collection where
  190. parseJSON (A.Object o) = return (Collection o)
  191. parseJSON _ = fail "..."
  192. instance ToJSON Collection where
  193. toJSON (Collection o) = A.Object o
  194. cRest :: Lens' Collection A.Object
  195. cRest = makeLens fromCollection (\ o' m -> m { fromCollection = o' })
  196. cTotalItems :: Lens' Collection (Maybe Int)
  197. cTotalItems = makeAesonLensMb "totalItems" cRest
  198. cItems :: Lens' Collection (Maybe [Object])
  199. cItems = makeAesonLensMb "items" cRest
  200. cURL :: Lens' Collection (Maybe Text)
  201. cURL = makeAesonLensMb "url" cRest
  202. -- | Create a @Collection@ with an @items@ and a @url@ property
  203. -- and fill in the corresponding @totalItems@ field with the
  204. -- length of the @items@ array.
  205. makeCollection :: [Object] -> Text -> Collection
  206. makeCollection objs url = Collection
  207. $ HM.insert "totalItems" (toJSON (length objs))
  208. $ HM.insert "items" (toJSON objs)
  209. $ HM.insert "url" (toJSON url)
  210. $ HM.empty