Added documentation by adapting descriptions from the RFC
Getty Ritter
9 years ago
1 | 1 | {-# LANGUAGE OverloadedStrings #-} |
2 | ||
2 | 3 | |
3 | 4 | {-| |
4 | 5 | Module : Codec.ActivityStream.Dynamic |
9 | 10 | This is an interface to ActivityStreams that simply wraps an underlying |
10 | 11 | @aeson@ Object, and exposes a set of (convenient) lenses to access the |
11 | 12 | values inside. If an @aeson@ object is wrapped in the respective wrapper, |
12 |
it will contain the obligatory values for that type (e.g. an |
|
13 | it will contain the obligatory values for that type (e.g. an 'Activity' | |
13 | 14 | is guaranteed to have a @published@ date.) |
15 | ||
16 | Most of the inline documentation is drawn directly from the | |
17 | <http://activitystrea.ms/specs/json/1.0/ JSON Activity Streams 1.0> | |
18 | specification, with minor modifications | |
19 | to refer to the corresponding data types in this module and to clarify | |
20 | certain aspects. | |
14 | 21 | -} |
15 | 22 | |
16 | 23 | module Codec.ActivityStream.Dynamic |
17 | 24 | ( Lens' |
18 | -- * MediaLink | |
19 | , MediaLink | |
20 | , mlDuration | |
21 | , mlHeight | |
22 | , mlWidth | |
23 | , mlURL | |
24 | , mlRest | |
25 | , makeMediaLink | |
26 | 25 | -- * Object |
27 | 26 | , Object |
27 | , emptyObject | |
28 | -- ** Object Lenses | |
28 | 29 | , oAttachments |
29 | 30 | , oAuthor |
30 | 31 | , oContent |
39 | 40 | , oUpstreamDuplicates |
40 | 41 | , oURL |
41 | 42 | , oRest |
42 | , emptyObject | |
43 | 43 | -- * Activity |
44 | 44 | , Activity |
45 | , makeActivity | |
46 | , asObject | |
47 | -- ** Activity Lenses | |
45 | 48 | , acActor |
46 | 49 | , acContent |
47 | 50 | , acGenerator |
56 | 59 | , acURL |
57 | 60 | , acVerb |
58 | 61 | , acRest |
59 | , makeActivity | |
60 | , asObject | |
62 | -- * MediaLink | |
63 | , MediaLink | |
64 | , makeMediaLink | |
65 | -- ** MediaLink Lenses | |
66 | , mlDuration | |
67 | , mlHeight | |
68 | , mlWidth | |
69 | , mlURL | |
70 | , mlRest | |
61 | 71 | -- * Collection |
62 | 72 | , Collection |
73 | , makeCollection | |
74 | -- ** Collection Lenses | |
63 | 75 | , cTotalItems |
64 | 76 | , cItems |
65 | 77 | , cURL |
66 | 78 | , cRest |
67 | , makeCollection | |
68 | 79 | ) where |
69 | 80 | |
70 | 81 | import Data.Aeson ( FromJSON(..) |
77 | 88 | import qualified Data.HashMap.Strict as HM |
78 | 89 | import Data.Text (Text) |
79 | 90 | |
80 | import Codec.ActivityStream.LensInternal ( Lens' | |
81 | , makeLens | |
82 | , makeAesonLens | |
83 | , makeAesonLensMb | |
84 | ) | |
85 | ||
91 | import Codec.ActivityStream.LensInternal | |
92 | ||
93 | -- | Some types of objects may have an alternative visual representation in | |
94 | -- the form of an image, video or embedded HTML fragments. A 'MediaLink' | |
95 | -- represents a hyperlink to such resources. | |
86 | 96 | data MediaLink = MediaLink { fromMediaLink :: A.Object } deriving (Eq, Show) |
87 | 97 | |
88 | 98 | instance FromJSON MediaLink where |
89 | parseJSON (A.Object o) | HM.member "url" o = return (MediaLink o) | |
90 | | otherwise = fail "..." | |
91 |
parseJSON |
|
99 | parseJSON (A.Object o) | |
100 | | HM.member "url" o = return (MediaLink o) | |
101 | | otherwise = fail "MediaLink object contains no \"url\" property" | |
102 | parseJSON _ = fail "MediaLink not an object" | |
92 | 103 | |
93 | 104 | instance ToJSON MediaLink where |
94 | 105 | toJSON (MediaLink o) = A.Object o |
95 | 106 | |
107 | -- | Access the underlying JSON object that represents a Media Link | |
96 | 108 | mlRest :: Lens' MediaLink A.Object |
97 | 109 | mlRest = makeLens fromMediaLink (\ o' m -> m { fromMediaLink = o' }) |
98 | 110 | |
111 | -- | A hint to the consumer about the length, in seconds, of the media | |
112 | -- resource identified by the url property. A media link MAY contain | |
113 | -- a "duration" property when the target resource is a time-based | |
114 | -- media item such as an audio or video. | |
99 | 115 | mlDuration :: Lens' MediaLink (Maybe Int) |
100 | 116 | mlDuration = makeAesonLensMb "duration" mlRest |
101 | 117 | |
118 | -- | A hint to the consumer about the height, in pixels, of the media | |
119 | -- resource identified by the url property. A media link MAY contain | |
120 | -- a @height@ property when the target resource is a visual media item | |
121 | -- such as an image, video or embeddable HTML page. | |
102 | 122 | mlHeight :: Lens' MediaLink (Maybe Int) |
103 | 123 | mlHeight = makeAesonLensMb "height" mlRest |
104 | 124 | |
125 | -- | A hint to the consumer about the width, in pixels, of the media | |
126 | -- resource identified by the url property. A media link MAY contain | |
127 | -- a @width@ property when the target resource is a visual media item | |
128 | -- such as an image, video or embeddable HTML page. | |
105 | 129 | mlWidth :: Lens' MediaLink (Maybe Int) |
106 | 130 | mlWidth = makeAesonLensMb "width" mlRest |
107 | 131 | |
132 | -- | The IRI of the media resource being linked. A media link MUST have a | |
133 | -- @url@ property. | |
108 | 134 | mlURL :: Lens' MediaLink Text |
109 | 135 | mlURL = makeAesonLens "url" mlRest |
110 | 136 | |
111 |
-- | Create a @MediaLink@ with just a @url@ property |
|
137 | -- | Create a @MediaLink@ with just a @url@ property, and all other | |
138 | -- properties undefined. | |
112 | 139 | makeMediaLink :: Text -> MediaLink |
113 | 140 | makeMediaLink url = MediaLink (HM.insert "url" (toJSON url) HM.empty) |
114 | 141 | |
115 |
-- | |
|
142 | -- | Within the specification, an 'Object' is a thing, real or | |
143 | -- imaginary, which participates in an activity. It may be the | |
144 | -- entity performing the activity, or the entity on which the | |
145 | -- activity was performed. An object consists of properties | |
146 | -- defined below. Certain object types may | |
147 | -- further refine the meaning of these properties, or they may | |
148 | -- define additional properties. | |
149 | -- | |
150 | -- To maintain this flexibility in the Haskell environment, an | |
151 | -- 'Object' is an opaque wrapper over an underlying JSON value, | |
152 | -- and the 'oRest' accessor can be used to access that underlying | |
153 | -- value. | |
116 | 154 | |
117 | 155 | data Object = Object { fromObject :: A.Object } deriving (Eq, Show) |
118 | 156 | |
119 | 157 | instance FromJSON Object where |
120 | 158 | parseJSON (A.Object o) = return (Object o) |
121 |
parseJSON _ = fail " |
|
159 | parseJSON _ = fail "Object not an object" | |
122 | 160 | |
123 | 161 | instance ToJSON Object where |
124 | 162 | toJSON (Object o) = A.Object o |
125 | 163 | |
164 | -- | Access the underlying JSON object that represents an 'Object' | |
126 | 165 | oRest :: Lens' Object A.Object |
127 | 166 | oRest = makeLens fromObject (\ o' m -> m { fromObject = o' }) |
128 | 167 | |
168 | -- | A collection of one or more additional, associated objects, similar | |
169 | -- to the concept of attached files in an email message. An object MAY | |
170 | -- have an attachments property whose value is a JSON Array of 'Object's. | |
129 | 171 | oAttachments :: Lens' Object (Maybe [Object]) |
130 | 172 | oAttachments = makeAesonLensMb "attachments" oRest |
131 | 173 | |
174 | -- | Describes the entity that created or authored the object. An object | |
175 | -- MAY contain a single author property whose value is an 'Object' of any | |
176 | -- type. Note that the author field identifies the entity that created | |
177 | -- the object and does not necessarily identify the entity that | |
178 | -- published the object. For instance, it may be the case that an | |
179 | -- object created by one person is posted and published to a system by | |
180 | -- an entirely different entity. | |
132 | 181 | oAuthor :: Lens' Object (Maybe Object) |
133 | 182 | oAuthor = makeAesonLensMb "author" oRest |
134 | 183 | |
184 | -- | Natural-language description of the object encoded as a single JSON | |
185 | -- String containing HTML markup. Visual elements such as thumbnail | |
186 | -- images MAY be included. An object MAY contain a @content@ property. | |
135 | 187 | oContent :: Lens' Object (Maybe Text) |
136 | 188 | oContent = makeAesonLensMb "content" oRest |
137 | 189 | |
190 | -- | A natural-language, human-readable and plain-text name for the | |
191 | -- object. HTML markup MUST NOT be included. An object MAY contain | |
192 | -- a @displayName@ property. If the object does not specify an @objectType@ | |
193 | -- property, the object SHOULD specify a @displayName@. | |
138 | 194 | oDisplayName :: Lens' Object (Maybe Text) |
139 | 195 | oDisplayName = makeAesonLensMb "displayName" oRest |
140 | 196 | |
197 | -- | A JSON Array of one or more absolute IRI's | |
198 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]> identifying | |
199 | -- objects that duplicate this object's content. An object SHOULD | |
200 | -- contain a @downstreamDuplicates@ property when there are known objects, | |
201 | -- possibly in a different system, that duplicate the content in this | |
202 | -- object. This MAY be used as a hint for consumers to use when | |
203 | -- resolving duplicates between objects received from different sources. | |
141 | 204 | oDownstreamDuplicates :: Lens' Object (Maybe [Text]) |
142 | 205 | oDownstreamDuplicates = makeAesonLensMb "downstreamDuplicates" oRest |
143 | 206 | |
207 | -- | Provides a permanent, universally unique identifier for the object in | |
208 | -- the form of an absolute IRI | |
209 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. An | |
210 | -- object SHOULD contain a single @id@ property. If an object does not | |
211 | -- contain an @id@ property, consumers MAY use the value of the @url@ | |
212 | -- property as a less-reliable, non-unique identifier. | |
213 | ||
144 | 214 | oId :: Lens' Object (Maybe Text) |
145 | 215 | oId = makeAesonLensMb "id" oRest |
146 | 216 | |
217 | -- | Description of a resource providing a visual representation of the | |
218 | -- object, intended for human consumption. An object MAY contain an | |
219 | -- @image@ property whose value is a 'MediaLink'. | |
147 | 220 | oImage :: Lens' Object (Maybe MediaLink) |
148 | 221 | oImage = makeAesonLensMb "image" oRest |
149 | 222 | |
223 | -- | Identifies the type of object. An object MAY contain an @objectType@ | |
224 | -- property whose value is a JSON String that is non-empty and matches | |
225 | -- either the "isegment-nz-nc" or the \"IRI\" production in | |
226 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. Note | |
227 | -- that the use of a relative reference other than a simple name is | |
228 | -- not allowed. If no @objectType@ property is contained, the object has | |
229 | -- no specific type. | |
150 | 230 | oObjectType :: (FromJSON o, ToJSON o) => Lens' Object (Maybe o) |
151 | 231 | oObjectType = makeAesonLensMb "objectType" oRest |
152 | 232 | |
233 | -- | The date and time at which the object was published. An object MAY | |
234 | -- contain a @published@ property. | |
153 | 235 | oPublished :: Lens' Object (Maybe DateTime) |
154 | 236 | oPublished = makeAesonLensMb "published" oRest |
155 | 237 | |
238 | -- | Natural-language summarization of the object encoded as a single | |
239 | -- JSON String containing HTML markup. Visual elements such as thumbnail | |
240 | -- images MAY be included. An activity MAY contain a @summary@ property. | |
156 | 241 | oSummary :: Lens' Object (Maybe Text) |
157 | 242 | oSummary = makeAesonLensMb "summary" oRest |
158 | 243 | |
244 | -- | The date and time at which a previously published object has been | |
245 | -- modified. An Object MAY contain an @updated@ property. | |
159 | 246 | oUpdated :: Lens' Object (Maybe DateTime) |
160 | 247 | oUpdated = makeAesonLensMb "updated" oRest |
161 | 248 | |
249 | -- | A JSON Array of one or more absolute IRI's | |
250 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]> identifying | |
251 | -- objects that duplicate this object's content. An object SHOULD contain | |
252 | -- an @upstreamDuplicates@ property when a publisher is knowingly | |
253 | -- duplicating with a new ID the content from another object. This MAY be | |
254 | -- used as a hint for consumers to use when resolving duplicates between | |
255 | -- objects received from different sources. | |
162 | 256 | oUpstreamDuplicates :: Lens' Object (Maybe [Text]) |
163 | 257 | oUpstreamDuplicates = makeAesonLensMb "upstreamDuplicates" oRest |
164 | 258 | |
259 | -- | An IRI <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]> | |
260 | -- identifying a resource providing an HTML representation of the | |
261 | -- object. An object MAY contain a url property | |
165 | 262 | oURL :: Lens' Object (Maybe Text) |
166 | 263 | oURL = makeAesonLensMb "url" oRest |
167 | 264 | |
169 | 266 | emptyObject :: Object |
170 | 267 | emptyObject = Object HM.empty |
171 | 268 | |
172 |
-- | |
|
269 | -- | In its simplest form, an 'Activity' consists of an @actor@, a @verb@, an | |
270 | -- @object@, and a @target@. It tells the story of a person performing an | |
271 | -- action on or with an object -- "Geraldine posted a photo to her | |
272 | -- album" or "John shared a video". In most cases these components | |
273 | -- will be explicit, but they may also be implied. | |
173 | 274 | |
174 | 275 | data Activity = Activity { fromActivity :: A.Object } deriving (Eq, Show) |
175 | 276 | |
182 | 283 | instance ToJSON Activity where |
183 | 284 | toJSON (Activity o) = A.Object o |
184 | 285 | |
286 | -- | Access the underlying JSON object that represents an 'Activity' | |
185 | 287 | acRest :: Lens' Activity A.Object |
186 | 288 | acRest = makeLens fromActivity (\ o' m -> m { fromActivity = o' }) |
187 | 289 | |
290 | -- | Describes the entity that performed the activity. An activity MUST | |
291 | -- contain one @actor@ property whose value is a single 'Object'. | |
188 | 292 | acActor :: Lens' Activity Object |
189 | 293 | acActor = makeAesonLens "actor" acRest |
190 | 294 | |
295 | -- | Natural-language description of the activity encoded as a single | |
296 | -- JSON String containing HTML markup. Visual elements such as | |
297 | -- thumbnail images MAY be included. An activity MAY contain a | |
298 | -- @content@ property. | |
191 | 299 | acContent :: Lens' Activity (Maybe Text) |
192 | 300 | acContent = makeAesonLensMb "content" acRest |
193 | 301 | |
302 | -- | Describes the application that generated the activity. An activity | |
303 | -- MAY contain a @generator@ property whose value is a single 'Object'. | |
194 | 304 | acGenerator :: Lens' Activity (Maybe Object) |
195 | 305 | acGenerator = makeAesonLens "generator" acRest |
196 | 306 | |
307 | -- | Description of a resource providing a visual representation of the | |
308 | -- object, intended for human consumption. The image SHOULD have an | |
309 | -- aspect ratio of one (horizontal) to one (vertical) and SHOULD be | |
310 | -- suitable for presentation at a small size. An activity MAY have | |
311 | -- an @icon@ property. | |
197 | 312 | acIcon :: Lens' Activity (Maybe MediaLink) |
198 | 313 | acIcon = makeAesonLensMb "icon" acRest |
199 | 314 | |
315 | -- | Provides a permanent, universally unique identifier for the activity | |
316 | -- in the form of an absolute IRI | |
317 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. An | |
318 | -- activity SHOULD contain a single @id@ property. If an activity does | |
319 | -- not contain an @id@ property, consumers MAY use the value of the | |
320 | -- @url@ property as a less-reliable, non-unique identifier. | |
200 | 321 | acId :: Lens' Activity (Maybe Text) |
201 | 322 | acId = makeAesonLensMb "id" acRest |
202 | 323 | |
324 | -- | Describes the primary object of the activity. For instance, in the | |
325 | -- activity, "John saved a movie to his wishlist", the object of the | |
326 | -- activity is "movie". An activity SHOULD contain an @object@ property | |
327 | -- whose value is a single 'Object'. If the @object@ property is not | |
328 | -- contained, the primary object of the activity MAY be implied by | |
329 | -- context. | |
203 | 330 | acObject :: Lens' Activity (Maybe Object) |
204 | 331 | acObject = makeAesonLensMb "object" acRest |
205 | 332 | |
333 | -- | The date and time at which the activity was published. An activity | |
334 | -- MUST contain a @published@ property. | |
206 | 335 | acPublished :: Lens' Activity DateTime |
207 | 336 | acPublished = makeAesonLens "published" acRest |
208 | 337 | |
338 | -- | Describes the application that published the activity. Note that this | |
339 | -- is not necessarily the same entity that generated the activity. An | |
340 | -- activity MAY contain a @provider@ property whose value is a | |
341 | -- single 'Object'. | |
209 | 342 | acProvider :: Lens' Activity (Maybe Object) |
210 | 343 | acProvider = makeAesonLensMb "provider" acRest |
211 | 344 | |
345 | -- | Describes the target of the activity. The precise meaning of the | |
346 | -- activity's target is dependent on the activities verb, but will | |
347 | -- often be the object the English preposition "to". For instance, in | |
348 | -- the activity, "John saved a movie to his wishlist", the target of | |
349 | -- the activity is "wishlist". The activity target MUST NOT be used | |
350 | -- to identity an indirect object that is not a target of the | |
351 | -- activity. An activity MAY contain a @target@ property whose value | |
352 | -- is a single 'Object'. | |
212 | 353 | acTarget :: Lens' Activity (Maybe Object) |
213 | 354 | acTarget = makeAesonLensMb "target" acRest |
214 | 355 | |
356 | -- | Natural-language title or headline for the activity encoded as a | |
357 | -- single JSON String containing HTML markup. An activity MAY contain | |
358 | -- a @title@ property. | |
215 | 359 | acTitle :: Lens' Activity (Maybe Text) |
216 | 360 | acTitle = makeAesonLensMb "title" acRest |
217 | 361 | |
362 | -- | The date and time at which a previously published activity has | |
363 | -- been modified. An Activity MAY contain an @updated@ property. | |
218 | 364 | acUpdated :: Lens' Activity (Maybe DateTime) |
219 | 365 | acUpdated = makeAesonLensMb "updated" acRest |
220 | 366 | |
367 | -- | An IRI <http://www.ietf.org/rfc/rfc3987.txt RFC3987> | |
368 | -- identifying a resource providing an HTML representation of the | |
369 | -- activity. An activity MAY contain a @url@ property. | |
221 | 370 | acURL :: Lens' Activity (Maybe Text) |
222 | 371 | acURL = makeAesonLensMb "url" acRest |
223 | 372 | |
373 | -- | Identifies the action that the activity describes. An activity SHOULD | |
374 | -- contain a verb property whose value is a JSON String that is | |
375 | -- non-empty and matches either the \"isegment-nz-nc\" or the | |
376 | -- \"IRI\" production in <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. | |
377 | -- Note that the use of a relative | |
378 | -- reference other than a simple name is not allowed. If the @verb@ is | |
379 | -- not specified, or if the value is null, the @verb@ is | |
380 | -- assumed to be \"post\". | |
224 | 381 | acVerb :: (FromJSON v, ToJSON v) => Lens' Activity (Maybe v) |
225 | 382 | acVerb = makeAesonLensMb "verb" acRest |
226 | 383 | |
238 | 395 | asObject :: Activity -> Object |
239 | 396 | asObject act = Object (fromActivity act) |
240 | 397 | |
241 |
-- | |
|
398 | -- | A "collection" is a generic list of 'Object's of any object type. | |
399 | -- The @objectType@ of each item in the collection MAY be omitted if | |
400 | -- the type of object can be established through context. The collection | |
401 | -- is used primarily as the root of an Activity Streams document as described | |
402 | -- in Section 4, | |
403 | -- but can be used as the value of extension properties in a variety of | |
404 | -- situations. | |
242 | 405 | |
243 | 406 | data Collection = Collection { fromCollection :: A.Object } deriving (Eq, Show) |
244 | 407 | |
249 | 412 | instance ToJSON Collection where |
250 | 413 | toJSON (Collection o) = A.Object o |
251 | 414 | |
415 | -- | Access the underlying JSON object that represents a 'Collection' | |
252 | 416 | cRest :: Lens' Collection A.Object |
253 | 417 | cRest = makeLens fromCollection (\ o' m -> m { fromCollection = o' }) |
254 | 418 | |
419 | -- | Non-negative integer specifying the total number of activities | |
420 | -- within the stream. The Stream serialization MAY contain a | |
421 | -- @totalItems@ property. (NOTE: there is a typo in the original | |
422 | -- specification, in which it inconsistently refers to this as | |
423 | -- either @totalItems@ or @count@.) | |
255 | 424 | cTotalItems :: Lens' Collection (Maybe Int) |
256 | 425 | cTotalItems = makeAesonLensMb "totalItems" cRest |
257 | 426 | |
427 | -- | An array containing a listing of 'Object's of any object type. | |
428 | -- If used in combination with the @url@ property, the @items@ array | |
429 | -- can be used to provide a subset of the objects that may be | |
430 | -- found in the resource identified by the @url@. | |
258 | 431 | cItems :: Lens' Collection (Maybe [Object]) |
259 | 432 | cItems = makeAesonLensMb "items" cRest |
260 | 433 | |
434 | -- | An IRI <http://activitystrea.ms/specs/json/1.0/#RFC3987 [RFC3987]> | |
435 | -- referencing a JSON document containing the full | |
436 | -- listing of objects in the collection. | |
261 | 437 | cURL :: Lens' Collection (Maybe Text) |
262 | 438 | cURL = makeAesonLensMb "url" cRest |
263 | 439 |