Ticked version; removed non-Dynamic version of library
Getty Ritter
10 years ago
| 1 | {-# LANGUAGE Rank2Types #-} | |
| 2 | {-# LANGUAGE OverloadedStrings #-} | |
| 3 | ||
| 4 | {-| | |
| 5 | Module : Codec.ActivityStream.DynamicSchema | |
| 6 | Description : A (more dynamic) interface to the Activity Streams Base Schema | |
| 7 | Copyright : (c) Getty Ritter, 2014 | |
| 8 | Maintainer : gdritter@galois.com | |
| 9 | ||
| 10 | This is an interface to the extended ActivityStreams schema which defines | |
| 11 | an extensive set of @verb@ values, additional @objectType@ values, and a | |
| 12 | set of extended properties for 'Object's. | |
| 13 | ||
| 14 | Most of the inline documentation is drawn directly from the | |
| 15 | <https://github.com/activitystreams/activity-schema/blob/master/activity-schema.md Activity Base Schema draft> | |
| 16 | specification, with minor modifications | |
| 17 | to refer to the corresponding data types in this module and to clarify | |
| 18 | certain aspects. This is not an approved draft, and as such may be | |
| 19 | subject to changes which will be reflected in this module. In contrast to | |
| 20 | "Codec.ActivityStream", the API in this module makes __no guarantees about | |
| 21 | long-term stability__. | |
| 22 | -} | |
| 23 | ||
| 24 | module Codec.ActivityStream.DynamicSchema | |
| 25 | ( module Codec.ActivityStream.Dynamic | |
| 26 | -- * Verbs | |
| 27 | , SchemaVerb(..) | |
| 28 | -- * Object Types | |
| 29 | , SchemaObjectType(..) | |
| 30 | -- ** Audio/Video | |
| 31 | , avEmbedCode | |
| 32 | , avStream | |
| 33 | -- ** Binary | |
| 34 | , bnCompression | |
| 35 | , bnData | |
| 36 | , bnFileUrl | |
| 37 | , bnLength | |
| 38 | , bnMd5 | |
| 39 | , bnMimeType | |
| 40 | -- ** Event | |
| 41 | , evAttendedBy | |
| 42 | , evAttending | |
| 43 | , evEndTime | |
| 44 | , evInvited | |
| 45 | , evMaybeAttending | |
| 46 | , evNotAttendedBy | |
| 47 | , evNotAttending | |
| 48 | , evStartTime | |
| 49 | -- ** Issue | |
| 50 | , isTypes | |
| 51 | -- ** Permission | |
| 52 | , pmScope | |
| 53 | , pmActions | |
| 54 | -- ** Place | |
| 55 | , plPosition | |
| 56 | , plAddress | |
| 57 | -- *** PlacePosition | |
| 58 | , PlacePosition | |
| 59 | -- *** PlaceAddress | |
| 60 | , PlaceAddress | |
| 61 | -- ** Role/Group | |
| 62 | , rlMembers | |
| 63 | -- ** Task | |
| 64 | , tsActor | |
| 65 | , tsBy | |
| 66 | , tsObject | |
| 67 | , tsPrerequisites | |
| 68 | , tsRequired | |
| 69 | , tsSupersedes | |
| 70 | , tsVerb | |
| 71 | -- * Basic Extension Properties | |
| 72 | , acContext | |
| 73 | , getLocation | |
| 74 | , oMood | |
| 75 | , oRating | |
| 76 | , acResult | |
| 77 | , getSource | |
| 78 | , getStartTime | |
| 79 | , getEndTime | |
| 80 | , oTags | |
| 81 | -- * Mood | |
| 82 | , Mood | |
| 83 | , moodRest | |
| 84 | , moodDisplayName | |
| 85 | , moodImage | |
| 86 | ) where | |
| 87 | ||
| 88 | import qualified Data.Aeson as Aeson | |
| 89 | import Data.DateTime (DateTime) | |
| 90 | import Data.Aeson ( FromJSON(..), ToJSON(..) ) | |
| 91 | import qualified Data.HashMap.Strict as HM | |
| 92 | import Data.Text (Text) | |
| 93 | ||
| 94 | import Codec.ActivityStream.LensInternal | |
| 95 | import Codec.ActivityStream.Dynamic | |
| 96 | import Codec.ActivityStream.Schema (SchemaVerb(..), SchemaObjectType(..)) | |
| 97 | ||
| 98 | -- audio/video | |
| 99 | ||
| 100 | -- | A fragment of HTML markup that, when embedded within another HTML | |
| 101 | -- page, provides an interactive user-interface for viewing or listening | |
| 102 | -- to the video or audio stream. | |
| 103 | avEmbedCode :: Lens' Object (Maybe Text) | |
| 104 | avEmbedCode = makeAesonLensMb "embedCode" oRest | |
| 105 | ||
| 106 | -- | An Activity Streams Media Link to the video or audio content itself. | |
| 107 | avStream :: Lens' Object (Maybe MediaLink) | |
| 108 | avStream = makeAesonLensMb "stream" oRest | |
| 109 | ||
| 110 | -- binary | |
| 111 | ||
| 112 | -- | An optional token identifying a compression algorithm applied to | |
| 113 | -- the binary data prior to Base64-encoding. Possible algorithms | |
| 114 | -- are "deflate" and "gzip", respectively indicating the use of | |
| 115 | -- the compression mechanisms defined by RFC 1951 and RFC 1952. | |
| 116 | -- Additional compression algorithms MAY be used but are not defined | |
| 117 | -- by this specification. Note that previous versions of this | |
| 118 | -- specification allowed for multiple compression algorithms to be | |
| 119 | -- applied and listed using a comma-separated format. The use of | |
| 120 | -- multiple compressions is no longer permitted. | |
| 121 | bnCompression :: Lens' Object (Maybe Text) | |
| 122 | bnCompression = makeAesonLensMb "compression" oRest | |
| 123 | ||
| 124 | -- | The URL-Safe Base64-encoded representation of the binary data | |
| 125 | bnData :: Lens' Object (Maybe Text) | |
| 126 | bnData = makeAesonLensMb "data" oRest | |
| 127 | -- | An optional IRI for the binary data described by this object. | |
| 128 | bnFileUrl :: Lens' Object (Maybe Text) | |
| 129 | bnFileUrl = makeAesonLensMb "fileUrl" oRest | |
| 130 | ||
| 131 | -- | The total number of unencoded, uncompressed octets contained | |
| 132 | -- within the "data" field. | |
| 133 | bnLength :: Lens' Object (Maybe Text) | |
| 134 | bnLength = makeAesonLensMb "length" oRest | |
| 135 | ||
| 136 | -- | An optional MD5 checksum calculated over the unencoded, | |
| 137 | -- uncompressed octets contained within the "data" field | |
| 138 | bnMd5 :: Lens' Object (Maybe Text) | |
| 139 | bnMd5 = makeAesonLensMb "md5" oRest | |
| 140 | ||
| 141 | -- | The MIME Media Type of the binary data contained within the object. | |
| 142 | bnMimeType :: Lens' Object (Maybe Text) | |
| 143 | bnMimeType = makeAesonLensMb "mimeType" oRest | |
| 144 | ||
| 145 | -- event | |
| 146 | ||
| 147 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 148 | -- Activity Streams specification that provides information about | |
| 149 | -- entities that attended the event. | |
| 150 | evAttendedBy :: Lens' Object (Maybe Collection) | |
| 151 | evAttendedBy = makeAesonLensMb "attendedBy" oRest | |
| 152 | ||
| 153 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 154 | -- Activity Streams specification that provides information about | |
| 155 | -- entities that intend to attend the event. | |
| 156 | evAttending :: Lens' Object (Maybe Collection) | |
| 157 | evAttending = makeAesonLensMb "attending" oRest | |
| 158 | ||
| 159 | -- | The date and time that the event ends represented as a String | |
| 160 | -- conforming to the "date-time" production in [RFC3339]. | |
| 161 | evEndTime :: Lens' Object (Maybe DateTime) | |
| 162 | evEndTime = makeAesonLensMb "endTime" oRest | |
| 163 | ||
| 164 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 165 | -- Activity Streams specification that provides information about | |
| 166 | -- entities that have been invited to the event. | |
| 167 | evInvited :: Lens' Object (Maybe Collection) | |
| 168 | evInvited = makeAesonLensMb "invited" oRest | |
| 169 | ||
| 170 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 171 | -- Activity Streams specification that provides information about | |
| 172 | -- entities that possibly may attend the event. | |
| 173 | evMaybeAttending :: Lens' Object (Maybe Collection) | |
| 174 | evMaybeAttending = makeAesonLensMb "maybeAttending" oRest | |
| 175 | ||
| 176 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 177 | -- Activity Streams specification that provides information about | |
| 178 | -- entities that did not attend the event. | |
| 179 | evNotAttendedBy :: Lens' Object (Maybe Collection) | |
| 180 | evNotAttendedBy = makeAesonLensMb "notAttendedBy" oRest | |
| 181 | ||
| 182 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 183 | -- Activity Streams specification that provides information about | |
| 184 | -- entities that do not intend to attend the event. | |
| 185 | evNotAttending :: Lens' Object (Maybe Collection) | |
| 186 | evNotAttending = makeAesonLensMb "notAttending" oRest | |
| 187 | ||
| 188 | -- | The date and time that the event begins represented as a String | |
| 189 | -- confirming to the "date-time" production in RFC 3339. | |
| 190 | evStartTime :: Lens' Object (Maybe DateTime) | |
| 191 | evStartTime = makeAesonLensMb "startTime" oRest | |
| 192 | ||
| 193 | -- issue | |
| 194 | ||
| 195 | -- | An array of one or more absolute IRI's that describe the type of | |
| 196 | -- issue represented by the object. Note that the IRI's are intended | |
| 197 | -- for use as identifiers and MAY or MAY NOT be dereferenceable. | |
| 198 | isTypes :: Lens' Object (Maybe [Text]) | |
| 199 | isTypes = makeAesonLensMb "types" oRest | |
| 200 | ||
| 201 | -- permission | |
| 202 | ||
| 203 | -- | A single Activity Streams Object, of any objectType, that | |
| 204 | -- identifies the scope of the permission. For example, if the | |
| 205 | -- permission objects describes write permissions for a given file, | |
| 206 | -- the scope property would be a file object describing that file. | |
| 207 | pmScope :: Lens' Object (Maybe Object) | |
| 208 | pmScope = makeAesonLensMb "scope" oRest | |
| 209 | ||
| 210 | -- | An array of Strings that identify the specific actions associated | |
| 211 | -- with the permission. The actions are application and scope | |
| 212 | -- specific. No common, core set of actions is defined by this | |
| 213 | -- specification. | |
| 214 | pmActions :: Lens' Object (Maybe [Text]) | |
| 215 | pmActions = makeAesonLensMb "actions" oRest | |
| 216 | ||
| 217 | -- place | |
| 218 | ||
| 219 | -- | The latitude, longitude and altitude of the place as a point on | |
| 220 | -- Earth. Represented as a JSON Object as described below. | |
| 221 | plPosition :: Lens' Object (Maybe PlacePosition) | |
| 222 | plPosition = makeAesonLensMb "position" oRest | |
| 223 | ||
| 224 | -- | A physical address represented as a JSON object as described below. | |
| 225 | plAddress :: Lens' Object (Maybe PlaceAddress) | |
| 226 | plAddress = makeAesonLensMb "address" oRest | |
| 227 | ||
| 228 | data PlacePosition = PPO { fromPPO :: Aeson.Object } deriving (Eq, Show) | |
| 229 | ||
| 230 | instance FromJSON PlacePosition where | |
| 231 | parseJSON (Aeson.Object o) | |
| 232 | | HM.member "altitude" o | |
| 233 | && HM.member "latitude" o | |
| 234 | && HM.member "longitude" o = return (PPO o) | |
| 235 | | otherwise = fail "..." | |
| 236 | parseJSON _ = fail "..." | |
| 237 | ||
| 238 | instance ToJSON PlacePosition where | |
| 239 | toJSON = Aeson.Object . fromPPO | |
| 240 | ||
| 241 | data PlaceAddress = PAO { fromPAO :: Aeson.Object } deriving (Eq, Show) | |
| 242 | ||
| 243 | instance FromJSON PlaceAddress where | |
| 244 | parseJSON (Aeson.Object o) | |
| 245 | | HM.member "formatted" o | |
| 246 | && HM.member "streetAddress" o | |
| 247 | && HM.member "locality" o | |
| 248 | && HM.member "region" o | |
| 249 | && HM.member "postalCode" o | |
| 250 | && HM.member "country" o = return (PAO o) | |
| 251 | | otherwise = fail "..." | |
| 252 | parseJSON _ = fail "..." | |
| 253 | ||
| 254 | instance ToJSON PlaceAddress where | |
| 255 | toJSON = Aeson.Object . fromPAO | |
| 256 | ||
| 257 | -- role/group | |
| 258 | ||
| 259 | -- | An optional Activity Streams Collection object listing the | |
| 260 | -- members of a group, or listing the entities assigned to a | |
| 261 | -- particular role. | |
| 262 | rlMembers :: Lens' Object (Maybe [Object]) | |
| 263 | rlMembers = makeAesonLensMb "members" oRest | |
| 264 | ||
| 265 | -- Task | |
| 266 | ||
| 267 | -- | An Activity Streams Object that provides information about the | |
| 268 | -- actor that is expected to complete the task. | |
| 269 | tsActor :: Lens' Object (Maybe Object) | |
| 270 | tsActor = makeAesonLensMb "actor" oRest | |
| 271 | ||
| 272 | -- | A RFC 3339 date-time specifying the date and time by which the | |
| 273 | -- task is to be completed. | |
| 274 | tsBy :: Lens' Object (Maybe DateTime) | |
| 275 | tsBy = makeAesonLensMb "by" oRest | |
| 276 | ||
| 277 | -- | An Activity Streams object describing the object of the task. | |
| 278 | tsObject :: Lens' Object (Maybe Object) | |
| 279 | tsObject = makeAesonLensMb "object" oRest | |
| 280 | ||
| 281 | -- | An Array of other Task objects that are to be completed before | |
| 282 | -- this task can be completed. | |
| 283 | tsPrerequisites :: Lens' Object (Maybe [Object]) | |
| 284 | tsPrerequisites = makeAesonLensMb "prerequisites" oRest | |
| 285 | ||
| 286 | -- | A boolean value indicating whether completion of this task is | |
| 287 | -- considered to be mandatory. | |
| 288 | tsRequired :: Lens' Object (Maybe Bool) | |
| 289 | tsRequired = makeAesonLensMb "required" oRest | |
| 290 | ||
| 291 | -- | An Array of other Task objects that are superseded by this task object. | |
| 292 | tsSupersedes :: Lens' Object (Maybe [Object]) | |
| 293 | tsSupersedes = makeAesonLensMb "supersedes" oRest | |
| 294 | ||
| 295 | -- | A string indicating the verb for this task as defined in Section | |
| 296 | -- 3.2 of [activitystreams]. | |
| 297 | tsVerb :: Lens' Object (Maybe SchemaVerb) | |
| 298 | tsVerb = makeAesonLensMb "verb" oRest | |
| 299 | ||
| 300 | -- extra properties | |
| 301 | ||
| 302 | -- | The additional @context@ property allows an 'Activity' to further | |
| 303 | -- include information about why a particular action occurred by | |
| 304 | -- providing details about the context within which a particular | |
| 305 | -- Activity was performed. The value of the @context@ property is an | |
| 306 | -- 'Object' of any @objectType@. The meaning of the @context@ property is | |
| 307 | -- only defined when used within an 'Activity' object. | |
| 308 | acContext :: Lens' Activity (Maybe Object) | |
| 309 | acContext = makeAesonLensMb "context" acRest | |
| 310 | ||
| 311 | -- | When appearing within an activity, the location data indicates | |
| 312 | -- the location where the activity occurred. When appearing within an | |
| 313 | -- object, the location data indicates the location of that object at | |
| 314 | -- the time the activity occurred. | |
| 315 | getLocation :: Lens' a Aeson.Object -> Lens' a (Maybe Object) | |
| 316 | getLocation = makeAesonLensMb "location" | |
| 317 | ||
| 318 | -- | Mood describes the mood of the user when the activity was | |
| 319 | -- performed. This is usually collected via an extra field in the user | |
| 320 | -- interface used to perform the activity. For the purpose of the | |
| 321 | -- schema, a mood is a freeform, short mood keyword or phrase along | |
| 322 | -- with an optional mood icon image. | |
| 323 | oMood :: Lens' Object (Maybe Mood) | |
| 324 | oMood = makeAesonLensMb "mood" oRest | |
| 325 | ||
| 326 | -- | A rating given as a number between 1.0 and 5.0 inclusive with one | |
| 327 | -- decimal place of precision. Represented in JSON as a property | |
| 328 | -- called @rating@ whose value is a JSON number giving the rating. | |
| 329 | oRating :: Lens' Object (Maybe Double) | |
| 330 | oRating = makeAesonLensMb "rating" oRest | |
| 331 | ||
| 332 | -- | The @result@ provides a description of the result of any particular | |
| 333 | -- activity. The value of the @result@ property is an Object of any | |
| 334 | -- objectType. The meaning of the @result@ property is only defined when | |
| 335 | -- used within an 'Activity' object. | |
| 336 | acResult :: Lens' Activity (Maybe Object) | |
| 337 | acResult = makeAesonLensMb "result" acRest | |
| 338 | ||
| 339 | -- | The @source@ property provides a reference to the original source of | |
| 340 | -- an object or activity. The value of the @source@ property is an | |
| 341 | -- Object of any objectType. | |
| 342 | -- | |
| 343 | -- The @source@ property is closely related to | |
| 344 | -- the @generator@ and @provider@ properties but serves the distinct | |
| 345 | -- purpose of identifying where the activity or object was originally | |
| 346 | -- published as opposed to identifying the applications that generated | |
| 347 | -- or published it. | |
| 348 | getSource :: Lens' a Aeson.Object -> Lens' a (Maybe Object) | |
| 349 | getSource = makeAesonLensMb "source" | |
| 350 | ||
| 351 | -- | When an long running Activity occurs over a distinct period of | |
| 352 | -- time, or when an Object represents a long-running process or event, | |
| 353 | -- the @startTime@ propertiy can be used to specify the | |
| 354 | -- date and time at which the activity or object begins. | |
| 355 | -- The values for each are represented as JSON Strings | |
| 356 | -- conforming to the "date-time" production in RFC3339. | |
| 357 | getStartTime :: Lens' a Aeson.Object -> Lens' a (Maybe Text) | |
| 358 | getStartTime = makeAesonLensMb "startTime" | |
| 359 | ||
| 360 | -- | When an long running Activity occurs over a distinct period of | |
| 361 | -- time, or when an Object represents a long-running process or event, | |
| 362 | -- the @endTime@ propertiy can be used to specify the | |
| 363 | -- date and time at which the activity or object concludes. | |
| 364 | -- The values for each are represented as JSON Strings | |
| 365 | -- conforming to the "date-time" production in RFC3339. | |
| 366 | getEndTime :: Lens' a Aeson.Object -> Lens' a (Maybe Text) | |
| 367 | getEndTime = makeAesonLensMb "endTime" | |
| 368 | ||
| 369 | -- | A listing of the objects that have been associated with a | |
| 370 | -- particular object. Represented in JSON using a property named @tags@ | |
| 371 | -- whose value is an Array of objects. | |
| 372 | oTags :: Lens' Object (Maybe [Object]) | |
| 373 | oTags = makeAesonLensMb "tags" oRest | |
| 374 | ||
| 375 | -- mood | |
| 376 | ||
| 377 | -- | Mood describes the mood of the user when the activity was | |
| 378 | -- performed. This is usually collected via an extra field in the user | |
| 379 | -- interface used to perform the activity. For the purpose of this | |
| 380 | -- schema, a mood is a freeform, short mood keyword or phrase along | |
| 381 | -- with an optional mood icon image. | |
| 382 | data Mood = Mood { fromMood :: Aeson.Object } deriving (Eq, Show) | |
| 383 | ||
| 384 | instance FromJSON Mood where | |
| 385 | parseJSON (Aeson.Object o) | |
| 386 | | HM.member "displayName" o | |
| 387 | && HM.member "image" o = return (Mood o) | |
| 388 | | otherwise = fail "..." | |
| 389 | parseJSON _ = fail "..." | |
| 390 | ||
| 391 | instance ToJSON Mood where | |
| 392 | toJSON = Aeson.Object . fromMood | |
| 393 | ||
| 394 | -- | Access to the underlying JSON object of a 'Mood' | |
| 395 | moodRest :: Lens' Mood Aeson.Object | |
| 396 | moodRest = makeLens fromMood (\ o' m -> m { fromMood = o' }) | |
| 397 | ||
| 398 | -- | The natural-language, human-readable and plain-text keyword or | |
| 399 | -- phrase describing the mood. HTML markup MUST NOT be included. | |
| 400 | moodDisplayName :: Lens' Mood Text | |
| 401 | moodDisplayName = makeAesonLens "displayName" moodRest | |
| 402 | ||
| 403 | -- | An optional image that provides a visual representation of the mood. | |
| 404 | moodImage :: Lens' Mood MediaLink | |
| 405 | moodImage = makeAesonLens "image" moodRest |
| 1 | 1 | {-# LANGUAGE ViewPatterns #-} |
| 2 | 2 | |
| 3 |
module Codec.ActivityStream.Internal (commonOpts, commonOptsCC |
|
| 3 | module Codec.ActivityStream.Internal (commonOpts, commonOptsCC, ensure) where | |
| 4 | 4 | |
| 5 | 5 | import Control.Monad (mzero) |
| 6 | 6 | import Data.Aeson |
| 7 | 7 | import Data.Aeson.TH |
| 8 | 8 | import Data.Char |
| 9 | import Data.Text (pack, unpack) | |
| 10 | import Network.URI (URI, parseURI) | |
| 9 | import Data.HashMap.Strict (HashMap, member) | |
| 10 | import Data.Monoid ((<>)) | |
| 11 | import Data.Text (Text, pack, unpack) | |
| 11 | 12 | |
| 12 | instance FromJSON URI where | |
| 13 | parseJSON (String ((parseURI . unpack) -> Just u)) = return u | |
| 14 | parseJSON _ = mzero | |
| 15 | ||
| 16 | instance ToJSON URI where | |
| 17 | toJSON = String . pack . show | |
| 13 | ensure :: Monad m => String -> HashMap Text Value -> [Text] -> m () | |
| 14 | ensure objName obj keys = mapM_ go keys | |
| 15 | where go k | |
| 16 | | member k obj = return () | |
| 17 | | otherwise = fail ("Object \"" <> objName <> | |
| 18 | "\" does not contain property \"" <> | |
| 19 | unpack k <> "\"") | |
| 18 | 20 | |
| 19 | 21 | toCamelCaseUpper :: String -> String |
| 20 | 22 | toCamelCaseUpper = toCamelCase True |
| 50 | 52 | { fieldLabelModifier = fromCamelCase . drop (length prefix) |
| 51 | 53 | , constructorTagModifier = fromCamelCase |
| 52 | 54 | , omitNothingFields = True |
| 55 | ||
| 53 | 56 | } |
| 1 | 1 | {-# LANGUAGE OverloadedStrings #-} |
| 2 | {-# LANGUAGE TemplateHaskell #-} | |
| 3 | ||
| 4 | module Codec.ActivityStream.Representation where | |
| 5 | ||
| 6 | import Control.Applicative | |
| 7 | import Control.Lens hiding ((.=)) | |
| 2 | ||
| 3 | ||
| 4 | {-| | |
| 5 | Module : Codec.ActivityStream.Representation | |
| 6 | Description : A (more dynamic) interface to Activity Streams | |
| 7 | Copyright : (c) Getty Ritter, 2014 | |
| 8 | Maintainer : gdritter@galois.com | |
| 9 | ||
| 10 | This is an interface to ActivityStreams that simply wraps an underlying | |
| 11 | @aeson@ Object, and exposes a set of (convenient) lenses to access the | |
| 12 | values inside. If an @aeson@ object is wrapped in the respective wrapper, | |
| 13 | it will contain the obligatory values for that type (e.g. an 'Activity' | |
| 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. | |
| 21 | -} | |
| 22 | ||
| 23 | module Codec.ActivityStream.Representation | |
| 24 | ( Lens' | |
| 25 | -- * Object | |
| 26 | , Object | |
| 27 | , emptyObject | |
| 28 | -- ** Object Lenses | |
| 29 | , oAttachments | |
| 30 | , oAuthor | |
| 31 | , oContent | |
| 32 | , oDisplayName | |
| 33 | , oDownstreamDuplicates | |
| 34 | , oId | |
| 35 | , oImage | |
| 36 | , oObjectType | |
| 37 | , oPublished | |
| 38 | , oSummary | |
| 39 | , oUpdated | |
| 40 | , oUpstreamDuplicates | |
| 41 | , oURL | |
| 42 | , oRest | |
| 43 | -- * Activity | |
| 44 | , Activity | |
| 45 | , makeActivity | |
| 46 | , asObject | |
| 47 | -- ** Activity Lenses | |
| 48 | , acActor | |
| 49 | , acContent | |
| 50 | , acGenerator | |
| 51 | , acIcon | |
| 52 | , acId | |
| 53 | , acObject | |
| 54 | , acPublished | |
| 55 | , acProvider | |
| 56 | , acTarget | |
| 57 | , acTitle | |
| 58 | , acUpdated | |
| 59 | , acURL | |
| 60 | , acVerb | |
| 61 | , acRest | |
| 62 | -- * MediaLink | |
| 63 | , MediaLink | |
| 64 | , makeMediaLink | |
| 65 | -- ** MediaLink Lenses | |
| 66 | , mlDuration | |
| 67 | , mlHeight | |
| 68 | , mlWidth | |
| 69 | , mlURL | |
| 70 | , mlRest | |
| 71 | -- * Collection | |
| 72 | , Collection | |
| 73 | , makeCollection | |
| 74 | -- ** Collection Lenses | |
| 75 | , cTotalItems | |
| 76 | , cItems | |
| 77 | , cURL | |
| 78 | , cRest | |
| 79 | ) where | |
| 80 | ||
| 8 | 81 | import Data.Aeson ( FromJSON(..) |
| 9 | 82 | , ToJSON(..) |
| 10 |
, |
|
| 83 | , Result(..) | |
| 11 | 84 | , fromJSON |
| 12 | , object | |
| 13 | , (.=) | |
| 14 | , (.:) | |
| 15 | , (.:?) | |
| 16 | 85 | ) |
| 17 | import qualified Data.Aeson as Ae | |
| 18 | import Data.Aeson.TH | |
| 19 |
import |
|
| 86 | import qualified Data.Aeson as A | |
| 87 | import Data.DateTime (DateTime) | |
| 20 | 88 | import qualified Data.HashMap.Strict as HM |
| 21 | import Data.Maybe (catMaybes) | |
| 22 | 89 | import Data.Text (Text) |
| 23 | import Network.URI | |
| 24 | ||
| 25 | import Codec.ActivityStream.Internal | |
| 26 | ||
| 27 | data Verb ext | |
| 28 | = Post | |
| 29 | | VerbExt ext | |
| 30 | deriving (Eq, Show) | |
| 31 | ||
| 32 | instance FromJSON ext => FromJSON (Verb ext) where | |
| 33 | parseJSON (Ae.String "post") = return Post | |
| 34 | parseJSON ext = VerbExt `fmap` parseJSON ext | |
| 35 | ||
| 36 | instance ToJSON ext => ToJSON (Verb ext) where | |
| 37 | toJSON Post = Ae.String "post" | |
| 38 | toJSON (VerbExt ext) = toJSON ext | |
| 39 | ||
| 40 | data MediaLink = MediaLink | |
| 41 | { _mlDuration :: Maybe Int | |
| 42 | , _mlHeight :: Maybe Int | |
| 43 | , _mlURL :: Text | |
| 44 | , _mlWidth :: Maybe Int | |
| 45 | } deriving (Eq, Show) | |
| 46 | ||
| 47 | makeLenses ''MediaLink | |
| 48 | deriveJSON (commonOpts "_ml") ''MediaLink | |
| 49 | ||
| 50 | data Object objType = Object | |
| 51 | { _oAttachments :: [Object objType] | |
| 52 | , _oAuthor :: Maybe (Object objType) | |
| 53 | , _oContent :: Maybe Text | |
| 54 | , _oDisplayName :: Maybe Text | |
| 55 | , _oDownstreamDuplicates :: [URI] | |
| 56 | , _oId :: Maybe URI | |
| 57 | , _oImage :: Maybe MediaLink | |
| 58 | , _oObjectType :: Maybe objType | |
| 59 | , _oPublished :: Maybe DateTime | |
| 60 | , _oSummary :: Maybe Text | |
| 61 | , _oUpdated :: Maybe DateTime | |
| 62 | , _oUpstreamDuplicates :: [URI] | |
| 63 | , _oURL :: Maybe URI | |
| 64 | , _oRest :: [(Text, Value)] | |
| 65 | } deriving (Eq, Show) | |
| 66 | ||
| 67 | makeLenses ''Object | |
| 68 | ||
| 69 | objectFields :: [Text] | |
| 70 | objectFields = | |
| 71 | [ "attachments" | |
| 72 | , "author" | |
| 73 | , "content" | |
| 74 | , "displayName" | |
| 75 | , "downstreamDuplicates" | |
| 76 | , "id" | |
| 77 | , "image" | |
| 78 | , "objectType" | |
| 79 | , "published" | |
| 80 | , "summary" | |
| 81 | , "updated" | |
| 82 | , "upstreamDuplicates" | |
| 83 | , "url" | |
| 84 | ] | |
| 85 | ||
| 86 | instance FromJSON objType => FromJSON (Object objType) where | |
| 87 | parseJSON (Ae.Object o) = | |
| 88 | Object <$> fmap go (o .:? "attachments") | |
| 89 | <*> o .:? "author" | |
| 90 | <*> o .:? "content" | |
| 91 | <*> o .:? "displayName" | |
| 92 | <*> fmap go (o .:? "downstreamDuplicates") | |
| 93 | <*> o .:? "id" | |
| 94 | <*> o .:? "image" | |
| 95 | <*> o .:? "objectType" | |
| 96 | <*> o .:? "published" | |
| 97 | <*> o .:? "summary" | |
| 98 | <*> o .:? "updated" | |
| 99 | <*> fmap go (o .:? "upstreamDuplicates") | |
| 100 | <*> o .:? "url" | |
| 101 | <*> pure rest | |
| 102 | where rest = HM.toList (foldr HM.delete o objectFields) | |
| 103 | go :: Maybe [a] -> [a] | |
| 104 | go Nothing = [] | |
| 105 | go (Just xs) = xs | |
| 106 | ||
| 107 | instance ToJSON objType => ToJSON (Object objType) where | |
| 108 | toJSON obj = object (attrs ++ _oRest obj) | |
| 109 | where attrs = catMaybes | |
| 110 | [ "attachments" .=! _oAttachments obj | |
| 111 | , "author" .=? _oAuthor obj | |
| 112 | , "content" .=? _oContent obj | |
| 113 | , "displayName" .=? _oDisplayName obj | |
| 114 | , "downstreamDuplicates" .=! _oDownstreamDuplicates obj | |
| 115 | , "id" .=? _oId obj | |
| 116 | , "image" .=? _oImage obj | |
| 117 | , "objectType" .=? _oObjectType obj | |
| 118 | , "published" .=? _oPublished obj | |
| 119 | , "summary" .=? _oSummary obj | |
| 120 | , "updated" .=? _oUpdated obj | |
| 121 | , "upstreamDuplicates" .=! _oUpstreamDuplicates obj | |
| 122 | , "url" .=? _oURL obj | |
| 123 | ] | |
| 124 | (.=?) :: ToJSON a => Text -> Maybe a -> Maybe (Text, Value) | |
| 125 | x .=? Just y = Just (x, toJSON y) | |
| 126 | _ .=? Nothing = Nothing | |
| 127 | infix 1 .=? | |
| 128 | (.=!) :: ToJSON a => Text -> [a] -> Maybe (Text, Value) | |
| 129 | _ .=! [] = Nothing | |
| 130 | x .=! ys = Just (x, toJSON ys) | |
| 131 | infix 1 .=! | |
| 132 | ||
| 133 | emptyObject :: Object objType | |
| 134 | emptyObject = Object | |
| 135 | { _oAttachments = [] | |
| 136 | , _oAuthor = Nothing | |
| 137 | , _oContent = Nothing | |
| 138 | , _oDisplayName = Nothing | |
| 139 | , _oDownstreamDuplicates = [] | |
| 140 | , _oId = Nothing | |
| 141 | , _oImage = Nothing | |
| 142 | , _oObjectType = Nothing | |
| 143 | , _oPublished = Nothing | |
| 144 | , _oSummary = Nothing | |
| 145 | , _oUpdated = Nothing | |
| 146 | , _oUpstreamDuplicates = [] | |
| 147 | , _oURL = Nothing | |
| 148 | , _oRest = [] | |
| 149 | } | |
| 150 | ||
| 151 | data Activity verb objType = Activity | |
| 152 | { _acActor :: Object objType | |
| 153 | , _acContent :: Maybe Text | |
| 154 | , _acGenerator :: Maybe (Object objType) | |
| 155 | , _acIcon :: Maybe MediaLink | |
| 156 | , _acId :: Maybe URI | |
| 157 | , _acPublished :: DateTime | |
| 158 | , _acProvider :: Object objType | |
| 159 | , _acTarget :: Maybe (Object objType) | |
| 160 | , _acTitle :: Maybe Text | |
| 161 | , _acUpdated :: Maybe DateTime | |
| 162 | , _acURL :: Maybe URI | |
| 163 | , _acVerb :: Maybe verb | |
| 164 | } deriving (Eq, Show) | |
| 165 | ||
| 166 | makeLenses ''Activity | |
| 167 | deriveJSON (commonOpts "_ac") ''Activity | |
| 168 | ||
| 169 | makeMinimalActivity :: Object objType -> DateTime -> Object objType | |
| 170 | -> Activity verb objType | |
| 171 | makeMinimalActivity actor published provider = Activity | |
| 172 | { _acActor = actor | |
| 173 | , _acContent = Nothing | |
| 174 | , _acGenerator = Nothing | |
| 175 | , _acIcon = Nothing | |
| 176 | , _acId = Nothing | |
| 177 | , _acPublished = published | |
| 178 | , _acProvider = provider | |
| 179 | , _acTarget = Nothing | |
| 180 | , _acTitle = Nothing | |
| 181 | , _acUpdated = Nothing | |
| 182 | , _acURL = Nothing | |
| 183 | , _acVerb = Nothing | |
| 184 | } | |
| 185 | ||
| 186 | data Collection objType = Collection | |
| 187 | { _cTotalItems :: Maybe Int | |
| 188 | , _cItems :: [Object objType] | |
| 189 | , _cURL :: Maybe URI | |
| 190 | } deriving (Eq, Show) | |
| 191 | ||
| 192 | makeLenses ''Collection | |
| 193 | deriveJSON (commonOpts "_c") ''Collection | |
| 194 | ||
| 195 | makeCollection :: [Object objType] -> Maybe URI -> Collection objType | |
| 90 | ||
| 91 | import Codec.ActivityStream.Internal (ensure) | |
| 92 | import Codec.ActivityStream.LensInternal | |
| 93 | ||
| 94 | -- | Some types of objects may have an alternative visual representation in | |
| 95 | -- the form of an image, video or embedded HTML fragments. A 'MediaLink' | |
| 96 | -- represents a hyperlink to such resources. | |
| 97 | newtype MediaLink = MediaLink { fromMediaLink :: A.Object } deriving (Eq, Show) | |
| 98 | ||
| 99 | instance FromJSON MediaLink where | |
| 100 | parseJSON (A.Object o) = do | |
| 101 | ensure "MediaLink" o ["url"] | |
| 102 | return (MediaLink o) | |
| 103 | parseJSON _ = fail "MediaLink not an object" | |
| 104 | ||
| 105 | instance ToJSON MediaLink where | |
| 106 | toJSON (MediaLink o) = A.Object o | |
| 107 | ||
| 108 | -- | Access the underlying JSON object that represents a Media Link | |
| 109 | mlRest :: Lens' MediaLink A.Object | |
| 110 | mlRest = makeLens fromMediaLink (\ o' m -> m { fromMediaLink = o' }) | |
| 111 | ||
| 112 | -- | A hint to the consumer about the length, in seconds, of the media | |
| 113 | -- resource identified by the url property. A media link MAY contain | |
| 114 | -- a "duration" property when the target resource is a time-based | |
| 115 | -- media item such as an audio or video. | |
| 116 | mlDuration :: Lens' MediaLink (Maybe Int) | |
| 117 | mlDuration = makeAesonLensMb "duration" mlRest | |
| 118 | ||
| 119 | -- | A hint to the consumer about the height, in pixels, of the media | |
| 120 | -- resource identified by the url property. A media link MAY contain | |
| 121 | -- a @height@ property when the target resource is a visual media item | |
| 122 | -- such as an image, video or embeddable HTML page. | |
| 123 | mlHeight :: Lens' MediaLink (Maybe Int) | |
| 124 | mlHeight = makeAesonLensMb "height" mlRest | |
| 125 | ||
| 126 | -- | A hint to the consumer about the width, in pixels, of the media | |
| 127 | -- resource identified by the url property. A media link MAY contain | |
| 128 | -- a @width@ property when the target resource is a visual media item | |
| 129 | -- such as an image, video or embeddable HTML page. | |
| 130 | mlWidth :: Lens' MediaLink (Maybe Int) | |
| 131 | mlWidth = makeAesonLensMb "width" mlRest | |
| 132 | ||
| 133 | -- | The IRI of the media resource being linked. A media link MUST have a | |
| 134 | -- @url@ property. | |
| 135 | mlURL :: Lens' MediaLink Text | |
| 136 | mlURL = makeAesonLens "url" mlRest | |
| 137 | ||
| 138 | -- | Create a @MediaLink@ with just a @url@ property, and all other | |
| 139 | -- properties undefined. | |
| 140 | makeMediaLink :: Text -> MediaLink | |
| 141 | makeMediaLink url = MediaLink (HM.insert "url" (toJSON url) HM.empty) | |
| 142 | ||
| 143 | -- | Within the specification, an 'Object' is a thing, real or | |
| 144 | -- imaginary, which participates in an activity. It may be the | |
| 145 | -- entity performing the activity, or the entity on which the | |
| 146 | -- activity was performed. An object consists of properties | |
| 147 | -- defined below. Certain object types may | |
| 148 | -- further refine the meaning of these properties, or they may | |
| 149 | -- define additional properties. | |
| 150 | -- | |
| 151 | -- To maintain this flexibility in the Haskell environment, an | |
| 152 | -- 'Object' is an opaque wrapper over an underlying JSON value, | |
| 153 | -- and the 'oRest' accessor can be used to access that underlying | |
| 154 | -- value. | |
| 155 | ||
| 156 | newtype Object = Object { fromObject :: A.Object } deriving (Eq, Show) | |
| 157 | ||
| 158 | instance FromJSON Object where | |
| 159 | parseJSON (A.Object o) = return (Object o) | |
| 160 | parseJSON _ = fail "Object not an object" | |
| 161 | ||
| 162 | instance ToJSON Object where | |
| 163 | toJSON (Object o) = A.Object o | |
| 164 | ||
| 165 | -- | Access the underlying JSON object that represents an 'Object' | |
| 166 | oRest :: Lens' Object A.Object | |
| 167 | oRest = makeLens fromObject (\ o' m -> m { fromObject = o' }) | |
| 168 | ||
| 169 | -- | A collection of one or more additional, associated objects, similar | |
| 170 | -- to the concept of attached files in an email message. An object MAY | |
| 171 | -- have an attachments property whose value is a JSON Array of 'Object's. | |
| 172 | oAttachments :: Lens' Object (Maybe [Object]) | |
| 173 | oAttachments = makeAesonLensMb "attachments" oRest | |
| 174 | ||
| 175 | -- | Describes the entity that created or authored the object. An object | |
| 176 | -- MAY contain a single author property whose value is an 'Object' of any | |
| 177 | -- type. Note that the author field identifies the entity that created | |
| 178 | -- the object and does not necessarily identify the entity that | |
| 179 | -- published the object. For instance, it may be the case that an | |
| 180 | -- object created by one person is posted and published to a system by | |
| 181 | -- an entirely different entity. | |
| 182 | oAuthor :: Lens' Object (Maybe Object) | |
| 183 | oAuthor = makeAesonLensMb "author" oRest | |
| 184 | ||
| 185 | -- | Natural-language description of the object encoded as a single JSON | |
| 186 | -- String containing HTML markup. Visual elements such as thumbnail | |
| 187 | -- images MAY be included. An object MAY contain a @content@ property. | |
| 188 | oContent :: Lens' Object (Maybe Text) | |
| 189 | oContent = makeAesonLensMb "content" oRest | |
| 190 | ||
| 191 | -- | A natural-language, human-readable and plain-text name for the | |
| 192 | -- object. HTML markup MUST NOT be included. An object MAY contain | |
| 193 | -- a @displayName@ property. If the object does not specify an @objectType@ | |
| 194 | -- property, the object SHOULD specify a @displayName@. | |
| 195 | oDisplayName :: Lens' Object (Maybe Text) | |
| 196 | oDisplayName = makeAesonLensMb "displayName" oRest | |
| 197 | ||
| 198 | -- | A JSON Array of one or more absolute IRI's | |
| 199 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]> identifying | |
| 200 | -- objects that duplicate this object's content. An object SHOULD | |
| 201 | -- contain a @downstreamDuplicates@ property when there are known objects, | |
| 202 | -- possibly in a different system, that duplicate the content in this | |
| 203 | -- object. This MAY be used as a hint for consumers to use when | |
| 204 | -- resolving duplicates between objects received from different sources. | |
| 205 | oDownstreamDuplicates :: Lens' Object (Maybe [Text]) | |
| 206 | oDownstreamDuplicates = makeAesonLensMb "downstreamDuplicates" oRest | |
| 207 | ||
| 208 | -- | Provides a permanent, universally unique identifier for the object in | |
| 209 | -- the form of an absolute IRI | |
| 210 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. An | |
| 211 | -- object SHOULD contain a single @id@ property. If an object does not | |
| 212 | -- contain an @id@ property, consumers MAY use the value of the @url@ | |
| 213 | -- property as a less-reliable, non-unique identifier. | |
| 214 | ||
| 215 | oId :: Lens' Object (Maybe Text) | |
| 216 | oId = makeAesonLensMb "id" oRest | |
| 217 | ||
| 218 | -- | Description of a resource providing a visual representation of the | |
| 219 | -- object, intended for human consumption. An object MAY contain an | |
| 220 | -- @image@ property whose value is a 'MediaLink'. | |
| 221 | oImage :: Lens' Object (Maybe MediaLink) | |
| 222 | oImage = makeAesonLensMb "image" oRest | |
| 223 | ||
| 224 | -- | Identifies the type of object. An object MAY contain an @objectType@ | |
| 225 | -- property whose value is a JSON String that is non-empty and matches | |
| 226 | -- either the "isegment-nz-nc" or the \"IRI\" production in | |
| 227 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. Note | |
| 228 | -- that the use of a relative reference other than a simple name is | |
| 229 | -- not allowed. If no @objectType@ property is contained, the object has | |
| 230 | -- no specific type. | |
| 231 | oObjectType :: (FromJSON o, ToJSON o) => Lens' Object (Maybe o) | |
| 232 | oObjectType = makeAesonLensMb "objectType" oRest | |
| 233 | ||
| 234 | -- | The date and time at which the object was published. An object MAY | |
| 235 | -- contain a @published@ property. | |
| 236 | oPublished :: Lens' Object (Maybe DateTime) | |
| 237 | oPublished = makeAesonLensMb "published" oRest | |
| 238 | ||
| 239 | -- | Natural-language summarization of the object encoded as a single | |
| 240 | -- JSON String containing HTML markup. Visual elements such as thumbnail | |
| 241 | -- images MAY be included. An activity MAY contain a @summary@ property. | |
| 242 | oSummary :: Lens' Object (Maybe Text) | |
| 243 | oSummary = makeAesonLensMb "summary" oRest | |
| 244 | ||
| 245 | -- | The date and time at which a previously published object has been | |
| 246 | -- modified. An Object MAY contain an @updated@ property. | |
| 247 | oUpdated :: Lens' Object (Maybe DateTime) | |
| 248 | oUpdated = makeAesonLensMb "updated" oRest | |
| 249 | ||
| 250 | -- | A JSON Array of one or more absolute IRI's | |
| 251 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]> identifying | |
| 252 | -- objects that duplicate this object's content. An object SHOULD contain | |
| 253 | -- an @upstreamDuplicates@ property when a publisher is knowingly | |
| 254 | -- duplicating with a new ID the content from another object. This MAY be | |
| 255 | -- used as a hint for consumers to use when resolving duplicates between | |
| 256 | -- objects received from different sources. | |
| 257 | oUpstreamDuplicates :: Lens' Object (Maybe [Text]) | |
| 258 | oUpstreamDuplicates = makeAesonLensMb "upstreamDuplicates" oRest | |
| 259 | ||
| 260 | -- | An IRI <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]> | |
| 261 | -- identifying a resource providing an HTML representation of the | |
| 262 | -- object. An object MAY contain a url property | |
| 263 | oURL :: Lens' Object (Maybe Text) | |
| 264 | oURL = makeAesonLensMb "url" oRest | |
| 265 | ||
| 266 | -- | Create an @Object@ with no fields. | |
| 267 | emptyObject :: Object | |
| 268 | emptyObject = Object HM.empty | |
| 269 | ||
| 270 | -- | In its simplest form, an 'Activity' consists of an @actor@, a @verb@, an | |
| 271 | -- @object@, and a @target@. It tells the story of a person performing an | |
| 272 | -- action on or with an object -- "Geraldine posted a photo to her | |
| 273 | -- album" or "John shared a video". In most cases these components | |
| 274 | -- will be explicit, but they may also be implied. | |
| 275 | ||
| 276 | newtype Activity = Activity { fromActivity :: A.Object } deriving (Eq, Show) | |
| 277 | ||
| 278 | instance FromJSON Activity where | |
| 279 | parseJSON (A.Object o) = do | |
| 280 | ensure "Activity" o ["published", "provider"] | |
| 281 | return (Activity o) | |
| 282 | parseJSON _ = fail "\"Activity\" not an object" | |
| 283 | ||
| 284 | instance ToJSON Activity where | |
| 285 | toJSON (Activity o) = A.Object o | |
| 286 | ||
| 287 | -- | Access the underlying JSON object that represents an 'Activity' | |
| 288 | acRest :: Lens' Activity A.Object | |
| 289 | acRest = makeLens fromActivity (\ o' m -> m { fromActivity = o' }) | |
| 290 | ||
| 291 | -- | Describes the entity that performed the activity. An activity MUST | |
| 292 | -- contain one @actor@ property whose value is a single 'Object'. | |
| 293 | acActor :: Lens' Activity Object | |
| 294 | acActor = makeAesonLens "actor" acRest | |
| 295 | ||
| 296 | -- | Natural-language description of the activity encoded as a single | |
| 297 | -- JSON String containing HTML markup. Visual elements such as | |
| 298 | -- thumbnail images MAY be included. An activity MAY contain a | |
| 299 | -- @content@ property. | |
| 300 | acContent :: Lens' Activity (Maybe Text) | |
| 301 | acContent = makeAesonLensMb "content" acRest | |
| 302 | ||
| 303 | -- | Describes the application that generated the activity. An activity | |
| 304 | -- MAY contain a @generator@ property whose value is a single 'Object'. | |
| 305 | acGenerator :: Lens' Activity (Maybe Object) | |
| 306 | acGenerator = makeAesonLens "generator" acRest | |
| 307 | ||
| 308 | -- | Description of a resource providing a visual representation of the | |
| 309 | -- object, intended for human consumption. The image SHOULD have an | |
| 310 | -- aspect ratio of one (horizontal) to one (vertical) and SHOULD be | |
| 311 | -- suitable for presentation at a small size. An activity MAY have | |
| 312 | -- an @icon@ property. | |
| 313 | acIcon :: Lens' Activity (Maybe MediaLink) | |
| 314 | acIcon = makeAesonLensMb "icon" acRest | |
| 315 | ||
| 316 | -- | Provides a permanent, universally unique identifier for the activity | |
| 317 | -- in the form of an absolute IRI | |
| 318 | -- <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. An | |
| 319 | -- activity SHOULD contain a single @id@ property. If an activity does | |
| 320 | -- not contain an @id@ property, consumers MAY use the value of the | |
| 321 | -- @url@ property as a less-reliable, non-unique identifier. | |
| 322 | acId :: Lens' Activity (Maybe Text) | |
| 323 | acId = makeAesonLensMb "id" acRest | |
| 324 | ||
| 325 | -- | Describes the primary object of the activity. For instance, in the | |
| 326 | -- activity, "John saved a movie to his wishlist", the object of the | |
| 327 | -- activity is "movie". An activity SHOULD contain an @object@ property | |
| 328 | -- whose value is a single 'Object'. If the @object@ property is not | |
| 329 | -- contained, the primary object of the activity MAY be implied by | |
| 330 | -- context. | |
| 331 | acObject :: Lens' Activity (Maybe Object) | |
| 332 | acObject = makeAesonLensMb "object" acRest | |
| 333 | ||
| 334 | -- | The date and time at which the activity was published. An activity | |
| 335 | -- MUST contain a @published@ property. | |
| 336 | acPublished :: Lens' Activity DateTime | |
| 337 | acPublished = makeAesonLens "published" acRest | |
| 338 | ||
| 339 | -- | Describes the application that published the activity. Note that this | |
| 340 | -- is not necessarily the same entity that generated the activity. An | |
| 341 | -- activity MAY contain a @provider@ property whose value is a | |
| 342 | -- single 'Object'. | |
| 343 | acProvider :: Lens' Activity (Maybe Object) | |
| 344 | acProvider = makeAesonLensMb "provider" acRest | |
| 345 | ||
| 346 | -- | Describes the target of the activity. The precise meaning of the | |
| 347 | -- activity's target is dependent on the activities verb, but will | |
| 348 | -- often be the object the English preposition "to". For instance, in | |
| 349 | -- the activity, "John saved a movie to his wishlist", the target of | |
| 350 | -- the activity is "wishlist". The activity target MUST NOT be used | |
| 351 | -- to identity an indirect object that is not a target of the | |
| 352 | -- activity. An activity MAY contain a @target@ property whose value | |
| 353 | -- is a single 'Object'. | |
| 354 | acTarget :: Lens' Activity (Maybe Object) | |
| 355 | acTarget = makeAesonLensMb "target" acRest | |
| 356 | ||
| 357 | -- | Natural-language title or headline for the activity encoded as a | |
| 358 | -- single JSON String containing HTML markup. An activity MAY contain | |
| 359 | -- a @title@ property. | |
| 360 | acTitle :: Lens' Activity (Maybe Text) | |
| 361 | acTitle = makeAesonLensMb "title" acRest | |
| 362 | ||
| 363 | -- | The date and time at which a previously published activity has | |
| 364 | -- been modified. An Activity MAY contain an @updated@ property. | |
| 365 | acUpdated :: Lens' Activity (Maybe DateTime) | |
| 366 | acUpdated = makeAesonLensMb "updated" acRest | |
| 367 | ||
| 368 | -- | An IRI <http://www.ietf.org/rfc/rfc3987.txt RFC3987> | |
| 369 | -- identifying a resource providing an HTML representation of the | |
| 370 | -- activity. An activity MAY contain a @url@ property. | |
| 371 | acURL :: Lens' Activity (Maybe Text) | |
| 372 | acURL = makeAesonLensMb "url" acRest | |
| 373 | ||
| 374 | -- | Identifies the action that the activity describes. An activity SHOULD | |
| 375 | -- contain a verb property whose value is a JSON String that is | |
| 376 | -- non-empty and matches either the \"isegment-nz-nc\" or the | |
| 377 | -- \"IRI\" production in <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. | |
| 378 | -- Note that the use of a relative | |
| 379 | -- reference other than a simple name is not allowed. If the @verb@ is | |
| 380 | -- not specified, or if the value is null, the @verb@ is | |
| 381 | -- assumed to be \"post\". | |
| 382 | acVerb :: (FromJSON v, ToJSON v) => Lens' Activity (Maybe v) | |
| 383 | acVerb = makeAesonLensMb "verb" acRest | |
| 384 | ||
| 385 | -- | Create an @Activity@ with an @actor@, @published@, and | |
| 386 | -- @provider@ property. | |
| 387 | makeActivity :: Object -> DateTime -> Activity | |
| 388 | makeActivity actor published = Activity | |
| 389 | $ HM.insert "actor" (toJSON actor) | |
| 390 | $ HM.insert "published" (toJSON published) | |
| 391 | $ HM.empty | |
| 392 | ||
| 393 | -- | JSON Activity Streams 1.0 specificies that an @Activity@ may be used as an | |
| 394 | -- @Object@. In such a case, the object may have fields permitted on either an | |
| 395 | -- @Activity@ or an @Object@ | |
| 396 | asObject :: Activity -> Object | |
| 397 | asObject act = Object (fromActivity act) | |
| 398 | ||
| 399 | -- | A "collection" is a generic list of 'Object's of any object type. | |
| 400 | -- The @objectType@ of each item in the collection MAY be omitted if | |
| 401 | -- the type of object can be established through context. The collection | |
| 402 | -- is used primarily as the root of an Activity Streams document as described | |
| 403 | -- in Section 4, | |
| 404 | -- but can be used as the value of extension properties in a variety of | |
| 405 | -- situations. | |
| 406 | ||
| 407 | newtype Collection = Collection { fromCollection :: A.Object } deriving (Eq, Show) | |
| 408 | ||
| 409 | instance FromJSON Collection where | |
| 410 | parseJSON (A.Object o) = return (Collection o) | |
| 411 | parseJSON _ = fail "\"Collection\" not an object" | |
| 412 | ||
| 413 | instance ToJSON Collection where | |
| 414 | toJSON (Collection o) = A.Object o | |
| 415 | ||
| 416 | -- | Access the underlying JSON object that represents a 'Collection' | |
| 417 | cRest :: Lens' Collection A.Object | |
| 418 | cRest = makeLens fromCollection (\ o' m -> m { fromCollection = o' }) | |
| 419 | ||
| 420 | -- | Non-negative integer specifying the total number of activities | |
| 421 | -- within the stream. The Stream serialization MAY contain a | |
| 422 | -- @totalItems@ property. (NOTE: there is a typo in the original | |
| 423 | -- specification, in which it inconsistently refers to this as | |
| 424 | -- either @totalItems@ or @count@.) | |
| 425 | cTotalItems :: Lens' Collection (Maybe Int) | |
| 426 | cTotalItems = makeAesonLensMb "totalItems" cRest | |
| 427 | ||
| 428 | -- | An array containing a listing of 'Object's of any object type. | |
| 429 | -- If used in combination with the @url@ property, the @items@ array | |
| 430 | -- can be used to provide a subset of the objects that may be | |
| 431 | -- found in the resource identified by the @url@. | |
| 432 | cItems :: Lens' Collection (Maybe [Object]) | |
| 433 | cItems = makeAesonLensMb "items" cRest | |
| 434 | ||
| 435 | -- | An IRI <http://activitystrea.ms/specs/json/1.0/#RFC3987 [RFC3987]> | |
| 436 | -- referencing a JSON document containing the full | |
| 437 | -- listing of objects in the collection. | |
| 438 | cURL :: Lens' Collection (Maybe Text) | |
| 439 | cURL = makeAesonLensMb "url" cRest | |
| 440 | ||
| 441 | -- | Create a @Collection@ with an @items@ and a @url@ property | |
| 442 | -- and fill in the corresponding @totalItems@ field with the | |
| 443 | -- length of the @items@ array. | |
| 444 | makeCollection :: [Object] -> Text -> Collection | |
| 196 | 445 | makeCollection objs url = Collection |
| 197 | { _cTotalItems = Just (length objs) | |
| 198 | , _cItems = objs | |
| 199 | , _cURL = url | |
| 200 | } | |
| 446 | $ HM.insert "totalItems" (toJSON (length objs)) | |
| 447 | $ HM.insert "items" (toJSON objs) | |
| 448 | $ HM.insert "url" (toJSON url) | |
| 449 | $ HM.empty |
| 1 | {-# LANGUAGE Rank2Types #-} | |
| 2 | {-# LANGUAGE OverloadedStrings #-} | |
| 1 | 3 | {-# LANGUAGE TemplateHaskell #-} |
| 2 | 4 | |
| 3 | module Codec.ActivityStream.Schema where | |
| 4 | ||
| 5 | import Data.Aeson hiding (Object) | |
| 6 | import Data.Aeson.TH | |
| 7 | import Data.DateTime | |
| 8 | import Data.Text (Text) | |
| 5 | {-| | |
| 6 | Module : Codec.ActivityStream.Schema | |
| 7 | Description : An interface to the Activity Streams Base Schema | |
| 8 | Copyright : (c) Getty Ritter, 2014 | |
| 9 | Maintainer : gdritter@galois.com | |
| 10 | ||
| 11 | This is an interface to the extended ActivityStreams schema which defines | |
| 12 | an extensive set of @verb@ values, additional @objectType@ values, and a | |
| 13 | set of extended properties for 'Object's. | |
| 14 | ||
| 15 | Most of the inline documentation is drawn directly from the | |
| 16 | <https://github.com/activitystreams/activity-schema/blob/master/activity-schema.md Activity Base Schema draft> | |
| 17 | specification, with minor modifications | |
| 18 | to refer to the corresponding data types in this module and to clarify | |
| 19 | certain aspects. This is not an approved draft, and as such may be | |
| 20 | subject to changes which will be reflected in this module. In contrast to | |
| 21 | "Codec.ActivityStream", the API in this module makes | |
| 22 | __no guarantees about long-term stability__. | |
| 23 | -} | |
| 24 | ||
| 25 | module Codec.ActivityStream.Schema | |
| 26 | ( module Codec.ActivityStream | |
| 27 | -- * Verbs | |
| 28 | , SchemaVerb(..) | |
| 29 | -- * Object Types | |
| 30 | , SchemaObjectType(..) | |
| 31 | -- ** Audio/Video | |
| 32 | , avEmbedCode | |
| 33 | , avStream | |
| 34 | -- ** Binary | |
| 35 | , bnCompression | |
| 36 | , bnData | |
| 37 | , bnFileUrl | |
| 38 | , bnLength | |
| 39 | , bnMd5 | |
| 40 | , bnMimeType | |
| 41 | -- ** Event | |
| 42 | , evAttendedBy | |
| 43 | , evAttending | |
| 44 | , evEndTime | |
| 45 | , evInvited | |
| 46 | , evMaybeAttending | |
| 47 | , evNotAttendedBy | |
| 48 | , evNotAttending | |
| 49 | , evStartTime | |
| 50 | -- ** Issue | |
| 51 | , isTypes | |
| 52 | -- ** Permission | |
| 53 | , pmScope | |
| 54 | , pmActions | |
| 55 | -- ** Place | |
| 56 | , plPosition | |
| 57 | , plAddress | |
| 58 | -- *** PlacePosition | |
| 59 | , PlacePosition | |
| 60 | -- *** PlaceAddress | |
| 61 | , PlaceAddress | |
| 62 | -- ** Role/Group | |
| 63 | , rlMembers | |
| 64 | -- ** Task | |
| 65 | , tsActor | |
| 66 | , tsBy | |
| 67 | , tsObject | |
| 68 | , tsPrerequisites | |
| 69 | , tsRequired | |
| 70 | , tsSupersedes | |
| 71 | , tsVerb | |
| 72 | -- * Basic Extension Properties | |
| 73 | , acContext | |
| 74 | , getLocation | |
| 75 | , oMood | |
| 76 | , oRating | |
| 77 | , acResult | |
| 78 | , getSource | |
| 79 | , getStartTime | |
| 80 | , getEndTime | |
| 81 | , oTags | |
| 82 | -- * Mood | |
| 83 | , Mood | |
| 84 | , moodRest | |
| 85 | , moodDisplayName | |
| 86 | , moodImage | |
| 87 | ) where | |
| 88 | ||
| 89 | import qualified Data.Aeson as Aeson | |
| 90 | import Data.Aeson.TH (deriveJSON) | |
| 91 | import Data.DateTime (DateTime) | |
| 92 | import Data.Aeson ( FromJSON(..), ToJSON(..) ) | |
| 93 | import qualified Data.HashMap.Strict as HM | |
| 94 | import Data.Text (Text) | |
| 9 | 95 | |
| 10 | 96 | import Codec.ActivityStream.Internal |
| 11 |
import Codec.ActivityStream. |
|
| 97 | import Codec.ActivityStream.LensInternal | |
| 98 | import Codec.ActivityStream | |
| 12 | 99 | |
| 13 | 100 | -- | The ActivityStreams Base Schema specification defines the |
| 14 | 101 | -- following core verbs in addition to the default post verb that is |
| 547 | 634 | |
| 548 | 635 | deriveJSON (commonOptsCC "") ''SchemaObjectType |
| 549 | 636 | |
| 550 | type SchemaObject = Object SchemaObjectType | |
| 551 | type SchemaCollection = Collection SchemaObjectType | |
| 552 | ||
| 553 | data AVObj = AVObj | |
| 554 | { avEmbedCode :: Maybe Text | |
| 555 | , avStream :: Maybe MediaLink | |
| 556 | , avRest :: SchemaObject | |
| 557 | } deriving (Eq, Show) | |
| 558 | ||
| 559 | data BinaryObj = BinaryObj | |
| 560 | { bnCompression :: Maybe Text | |
| 561 | , bnData :: Maybe Text | |
| 562 | , bnFileUrl :: Maybe Text | |
| 563 | , bnLength :: Maybe Int | |
| 564 | , bnMd5 :: Maybe Text | |
| 565 | , bnMimeType :: Maybe Text | |
| 566 | , bnRest :: SchemaObject | |
| 567 | } deriving (Eq, Show) | |
| 568 | ||
| 569 | data EventObj = EventObj | |
| 570 | { evAttendedBy :: Maybe SchemaCollection | |
| 571 | , evAttending :: Maybe SchemaCollection | |
| 572 | , evEndTime :: Maybe DateTime | |
| 573 | , evInvited :: Maybe SchemaCollection | |
| 574 | , evMaybeAttending :: Maybe SchemaCollection | |
| 575 | , evNotAttendedBy :: Maybe SchemaCollection | |
| 576 | , evNotAttending :: Maybe SchemaCollection | |
| 577 | , evStartTime :: Maybe DateTime | |
| 578 | , evRest :: SchemaObject | |
| 579 | } deriving (Eq, Show) | |
| 580 | ||
| 581 | data IssueObj = IssueObj | |
| 582 | { isTypes :: Maybe [Text] | |
| 583 | , isRest :: SchemaObject | |
| 584 | } deriving (Eq, Show) | |
| 585 | ||
| 586 | data PlaceObj = PlaceObj | |
| 587 | { plPosition :: Maybe PlacePositionObj | |
| 588 | , plAddress :: Maybe PlaceAddressObj | |
| 589 | , plRest :: SchemaObject | |
| 590 | } deriving (Eq, Show) | |
| 591 | ||
| 592 | data PlacePositionObj = PlacePositionObj | |
| 593 | { ppAltitude :: Integer | |
| 594 | , ppLatitude :: Integer | |
| 595 | , ppLongitude :: Integer | |
| 596 | } deriving (Eq, Show) | |
| 597 | ||
| 598 | data PlaceAddressObj = PlaceAddressObj | |
| 599 | { paFormatted :: Text | |
| 600 | , paStreetAddress :: Text | |
| 601 | , paLocality :: Text | |
| 602 | , paRegion :: Text | |
| 603 | , paPostalCode :: Text | |
| 604 | , paCountry :: Text | |
| 605 | } deriving (Eq, Show) | |
| 606 | ||
| 607 | data TaskObj = TaskObj | |
| 608 | { tsActor :: Maybe SchemaObject | |
| 609 | , tsBy :: Maybe DateTime | |
| 610 | , tsObject :: Maybe SchemaObject | |
| 611 | , tsPrerequisites :: Maybe [TaskObj] | |
| 612 | , tsRequired :: Maybe Bool | |
| 613 | , tsSupersedes :: Maybe [TaskObj] | |
| 614 | , tsVerb :: Maybe SchemaVerb | |
| 615 | , tsRest :: SchemaObject | |
| 616 | } deriving (Eq, Show) | |
| 637 | ||
| 638 | -- audio/video | |
| 639 | ||
| 640 | -- | A fragment of HTML markup that, when embedded within another HTML | |
| 641 | -- page, provides an interactive user-interface for viewing or listening | |
| 642 | -- to the video or audio stream. | |
| 643 | avEmbedCode :: Lens' Object (Maybe Text) | |
| 644 | avEmbedCode = makeAesonLensMb "embedCode" oRest | |
| 645 | ||
| 646 | -- | An Activity Streams Media Link to the video or audio content itself. | |
| 647 | avStream :: Lens' Object (Maybe MediaLink) | |
| 648 | avStream = makeAesonLensMb "stream" oRest | |
| 649 | ||
| 650 | -- binary | |
| 651 | ||
| 652 | -- | An optional token identifying a compression algorithm applied to | |
| 653 | -- the binary data prior to Base64-encoding. Possible algorithms | |
| 654 | -- are "deflate" and "gzip", respectively indicating the use of | |
| 655 | -- the compression mechanisms defined by RFC 1951 and RFC 1952. | |
| 656 | -- Additional compression algorithms MAY be used but are not defined | |
| 657 | -- by this specification. Note that previous versions of this | |
| 658 | -- specification allowed for multiple compression algorithms to be | |
| 659 | -- applied and listed using a comma-separated format. The use of | |
| 660 | -- multiple compressions is no longer permitted. | |
| 661 | bnCompression :: Lens' Object (Maybe Text) | |
| 662 | bnCompression = makeAesonLensMb "compression" oRest | |
| 663 | ||
| 664 | -- | The URL-Safe Base64-encoded representation of the binary data | |
| 665 | bnData :: Lens' Object (Maybe Text) | |
| 666 | bnData = makeAesonLensMb "data" oRest | |
| 667 | -- | An optional IRI for the binary data described by this object. | |
| 668 | bnFileUrl :: Lens' Object (Maybe Text) | |
| 669 | bnFileUrl = makeAesonLensMb "fileUrl" oRest | |
| 670 | ||
| 671 | -- | The total number of unencoded, uncompressed octets contained | |
| 672 | -- within the "data" field. | |
| 673 | bnLength :: Lens' Object (Maybe Text) | |
| 674 | bnLength = makeAesonLensMb "length" oRest | |
| 675 | ||
| 676 | -- | An optional MD5 checksum calculated over the unencoded, | |
| 677 | -- uncompressed octets contained within the "data" field | |
| 678 | bnMd5 :: Lens' Object (Maybe Text) | |
| 679 | bnMd5 = makeAesonLensMb "md5" oRest | |
| 680 | ||
| 681 | -- | The MIME Media Type of the binary data contained within the object. | |
| 682 | bnMimeType :: Lens' Object (Maybe Text) | |
| 683 | bnMimeType = makeAesonLensMb "mimeType" oRest | |
| 684 | ||
| 685 | -- event | |
| 686 | ||
| 687 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 688 | -- Activity Streams specification that provides information about | |
| 689 | -- entities that attended the event. | |
| 690 | evAttendedBy :: Lens' Object (Maybe Collection) | |
| 691 | evAttendedBy = makeAesonLensMb "attendedBy" oRest | |
| 692 | ||
| 693 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 694 | -- Activity Streams specification that provides information about | |
| 695 | -- entities that intend to attend the event. | |
| 696 | evAttending :: Lens' Object (Maybe Collection) | |
| 697 | evAttending = makeAesonLensMb "attending" oRest | |
| 698 | ||
| 699 | -- | The date and time that the event ends represented as a String | |
| 700 | -- conforming to the "date-time" production in [RFC3339]. | |
| 701 | evEndTime :: Lens' Object (Maybe DateTime) | |
| 702 | evEndTime = makeAesonLensMb "endTime" oRest | |
| 703 | ||
| 704 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 705 | -- Activity Streams specification that provides information about | |
| 706 | -- entities that have been invited to the event. | |
| 707 | evInvited :: Lens' Object (Maybe Collection) | |
| 708 | evInvited = makeAesonLensMb "invited" oRest | |
| 709 | ||
| 710 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 711 | -- Activity Streams specification that provides information about | |
| 712 | -- entities that possibly may attend the event. | |
| 713 | evMaybeAttending :: Lens' Object (Maybe Collection) | |
| 714 | evMaybeAttending = makeAesonLensMb "maybeAttending" oRest | |
| 715 | ||
| 716 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 717 | -- Activity Streams specification that provides information about | |
| 718 | -- entities that did not attend the event. | |
| 719 | evNotAttendedBy :: Lens' Object (Maybe Collection) | |
| 720 | evNotAttendedBy = makeAesonLensMb "notAttendedBy" oRest | |
| 721 | ||
| 722 | -- | A collection object as defined in Section 3.5 of the JSON | |
| 723 | -- Activity Streams specification that provides information about | |
| 724 | -- entities that do not intend to attend the event. | |
| 725 | evNotAttending :: Lens' Object (Maybe Collection) | |
| 726 | evNotAttending = makeAesonLensMb "notAttending" oRest | |
| 727 | ||
| 728 | -- | The date and time that the event begins represented as a String | |
| 729 | -- confirming to the "date-time" production in RFC 3339. | |
| 730 | evStartTime :: Lens' Object (Maybe DateTime) | |
| 731 | evStartTime = makeAesonLensMb "startTime" oRest | |
| 732 | ||
| 733 | -- issue | |
| 734 | ||
| 735 | -- | An array of one or more absolute IRI's that describe the type of | |
| 736 | -- issue represented by the object. Note that the IRI's are intended | |
| 737 | -- for use as identifiers and MAY or MAY NOT be dereferenceable. | |
| 738 | isTypes :: Lens' Object (Maybe [Text]) | |
| 739 | isTypes = makeAesonLensMb "types" oRest | |
| 740 | ||
| 741 | -- permission | |
| 742 | ||
| 743 | -- | A single Activity Streams Object, of any objectType, that | |
| 744 | -- identifies the scope of the permission. For example, if the | |
| 745 | -- permission objects describes write permissions for a given file, | |
| 746 | -- the scope property would be a file object describing that file. | |
| 747 | pmScope :: Lens' Object (Maybe Object) | |
| 748 | pmScope = makeAesonLensMb "scope" oRest | |
| 749 | ||
| 750 | -- | An array of Strings that identify the specific actions associated | |
| 751 | -- with the permission. The actions are application and scope | |
| 752 | -- specific. No common, core set of actions is defined by this | |
| 753 | -- specification. | |
| 754 | pmActions :: Lens' Object (Maybe [Text]) | |
| 755 | pmActions = makeAesonLensMb "actions" oRest | |
| 756 | ||
| 757 | -- place | |
| 758 | ||
| 759 | -- | The latitude, longitude and altitude of the place as a point on | |
| 760 | -- Earth. Represented as a JSON Object as described below. | |
| 761 | plPosition :: Lens' Object (Maybe PlacePosition) | |
| 762 | plPosition = makeAesonLensMb "position" oRest | |
| 763 | ||
| 764 | -- | A physical address represented as a JSON object as described below. | |
| 765 | plAddress :: Lens' Object (Maybe PlaceAddress) | |
| 766 | plAddress = makeAesonLensMb "address" oRest | |
| 767 | ||
| 768 | newtype PlacePosition = PPO { fromPPO :: Aeson.Object } deriving (Eq, Show) | |
| 769 | ||
| 770 | instance FromJSON PlacePosition where | |
| 771 | parseJSON (Aeson.Object o) = do | |
| 772 | ensure "Position" o | |
| 773 | ["altitude", "latitude", "longitude"] | |
| 774 | return (PPO o) | |
| 775 | parseJSON _ = fail "\"Position\" not an object" | |
| 776 | ||
| 777 | instance ToJSON PlacePosition where | |
| 778 | toJSON = Aeson.Object . fromPPO | |
| 779 | ||
| 780 | newtype PlaceAddress = PAO { fromPAO :: Aeson.Object } deriving (Eq, Show) | |
| 781 | ||
| 782 | instance FromJSON PlaceAddress where | |
| 783 | parseJSON (Aeson.Object o) = do | |
| 784 | ensure "Address" o | |
| 785 | [ "formatted" | |
| 786 | , "streetAddress" | |
| 787 | , "locality" | |
| 788 | , "postalCode" | |
| 789 | , "country" | |
| 790 | ] | |
| 791 | return (PAO o) | |
| 792 | parseJSON _ = fail "Address not an object" | |
| 793 | ||
| 794 | instance ToJSON PlaceAddress where | |
| 795 | toJSON = Aeson.Object . fromPAO | |
| 796 | ||
| 797 | -- role/group | |
| 798 | ||
| 799 | -- | An optional Activity Streams Collection object listing the | |
| 800 | -- members of a group, or listing the entities assigned to a | |
| 801 | -- particular role. | |
| 802 | rlMembers :: Lens' Object (Maybe [Object]) | |
| 803 | rlMembers = makeAesonLensMb "members" oRest | |
| 804 | ||
| 805 | -- Task | |
| 806 | ||
| 807 | -- | An Activity Streams Object that provides information about the | |
| 808 | -- actor that is expected to complete the task. | |
| 809 | tsActor :: Lens' Object (Maybe Object) | |
| 810 | tsActor = makeAesonLensMb "actor" oRest | |
| 811 | ||
| 812 | -- | A RFC 3339 date-time specifying the date and time by which the | |
| 813 | -- task is to be completed. | |
| 814 | tsBy :: Lens' Object (Maybe DateTime) | |
| 815 | tsBy = makeAesonLensMb "by" oRest | |
| 816 | ||
| 817 | -- | An Activity Streams object describing the object of the task. | |
| 818 | tsObject :: Lens' Object (Maybe Object) | |
| 819 | tsObject = makeAesonLensMb "object" oRest | |
| 820 | ||
| 821 | -- | An Array of other Task objects that are to be completed before | |
| 822 | -- this task can be completed. | |
| 823 | tsPrerequisites :: Lens' Object (Maybe [Object]) | |
| 824 | tsPrerequisites = makeAesonLensMb "prerequisites" oRest | |
| 825 | ||
| 826 | -- | A boolean value indicating whether completion of this task is | |
| 827 | -- considered to be mandatory. | |
| 828 | tsRequired :: Lens' Object (Maybe Bool) | |
| 829 | tsRequired = makeAesonLensMb "required" oRest | |
| 830 | ||
| 831 | -- | An Array of other Task objects that are superseded by this task object. | |
| 832 | tsSupersedes :: Lens' Object (Maybe [Object]) | |
| 833 | tsSupersedes = makeAesonLensMb "supersedes" oRest | |
| 834 | ||
| 835 | -- | A string indicating the verb for this task as defined in Section | |
| 836 | -- 3.2 of [activitystreams]. | |
| 837 | tsVerb :: Lens' Object (Maybe SchemaVerb) | |
| 838 | tsVerb = makeAesonLensMb "verb" oRest | |
| 839 | ||
| 840 | -- extra properties | |
| 841 | ||
| 842 | -- | The additional @context@ property allows an 'Activity' to further | |
| 843 | -- include information about why a particular action occurred by | |
| 844 | -- providing details about the context within which a particular | |
| 845 | -- Activity was performed. The value of the @context@ property is an | |
| 846 | -- 'Object' of any @objectType@. The meaning of the @context@ property is | |
| 847 | -- only defined when used within an 'Activity' object. | |
| 848 | acContext :: Lens' Activity (Maybe Object) | |
| 849 | acContext = makeAesonLensMb "context" acRest | |
| 850 | ||
| 851 | -- | When appearing within an activity, the location data indicates | |
| 852 | -- the location where the activity occurred. When appearing within an | |
| 853 | -- object, the location data indicates the location of that object at | |
| 854 | -- the time the activity occurred. | |
| 855 | getLocation :: Lens' a Aeson.Object -> Lens' a (Maybe Object) | |
| 856 | getLocation = makeAesonLensMb "location" | |
| 857 | ||
| 858 | -- | Mood describes the mood of the user when the activity was | |
| 859 | -- performed. This is usually collected via an extra field in the user | |
| 860 | -- interface used to perform the activity. For the purpose of the | |
| 861 | -- schema, a mood is a freeform, short mood keyword or phrase along | |
| 862 | -- with an optional mood icon image. | |
| 863 | oMood :: Lens' Object (Maybe Mood) | |
| 864 | oMood = makeAesonLensMb "mood" oRest | |
| 865 | ||
| 866 | -- | A rating given as a number between 1.0 and 5.0 inclusive with one | |
| 867 | -- decimal place of precision. Represented in JSON as a property | |
| 868 | -- called @rating@ whose value is a JSON number giving the rating. | |
| 869 | oRating :: Lens' Object (Maybe Double) | |
| 870 | oRating = makeAesonLensMb "rating" oRest | |
| 871 | ||
| 872 | -- | The @result@ provides a description of the result of any particular | |
| 873 | -- activity. The value of the @result@ property is an Object of any | |
| 874 | -- objectType. The meaning of the @result@ property is only defined when | |
| 875 | -- used within an 'Activity' object. | |
| 876 | acResult :: Lens' Activity (Maybe Object) | |
| 877 | acResult = makeAesonLensMb "result" acRest | |
| 878 | ||
| 879 | -- | The @source@ property provides a reference to the original source of | |
| 880 | -- an object or activity. The value of the @source@ property is an | |
| 881 | -- Object of any objectType. | |
| 882 | -- | |
| 883 | -- The @source@ property is closely related to | |
| 884 | -- the @generator@ and @provider@ properties but serves the distinct | |
| 885 | -- purpose of identifying where the activity or object was originally | |
| 886 | -- published as opposed to identifying the applications that generated | |
| 887 | -- or published it. | |
| 888 | getSource :: Lens' a Aeson.Object -> Lens' a (Maybe Object) | |
| 889 | getSource = makeAesonLensMb "source" | |
| 890 | ||
| 891 | -- | When an long running Activity occurs over a distinct period of | |
| 892 | -- time, or when an Object represents a long-running process or event, | |
| 893 | -- the @startTime@ propertiy can be used to specify the | |
| 894 | -- date and time at which the activity or object begins. | |
| 895 | -- The values for each are represented as JSON Strings | |
| 896 | -- conforming to the "date-time" production in RFC3339. | |
| 897 | getStartTime :: Lens' a Aeson.Object -> Lens' a (Maybe Text) | |
| 898 | getStartTime = makeAesonLensMb "startTime" | |
| 899 | ||
| 900 | -- | When an long running Activity occurs over a distinct period of | |
| 901 | -- time, or when an Object represents a long-running process or event, | |
| 902 | -- the @endTime@ propertiy can be used to specify the | |
| 903 | -- date and time at which the activity or object concludes. | |
| 904 | -- The values for each are represented as JSON Strings | |
| 905 | -- conforming to the "date-time" production in RFC3339. | |
| 906 | getEndTime :: Lens' a Aeson.Object -> Lens' a (Maybe Text) | |
| 907 | getEndTime = makeAesonLensMb "endTime" | |
| 908 | ||
| 909 | -- | A listing of the objects that have been associated with a | |
| 910 | -- particular object. Represented in JSON using a property named @tags@ | |
| 911 | -- whose value is an Array of objects. | |
| 912 | oTags :: Lens' Object (Maybe [Object]) | |
| 913 | oTags = makeAesonLensMb "tags" oRest | |
| 914 | ||
| 915 | -- mood | |
| 916 | ||
| 917 | -- | Mood describes the mood of the user when the activity was | |
| 918 | -- performed. This is usually collected via an extra field in the user | |
| 919 | -- interface used to perform the activity. For the purpose of this | |
| 920 | -- schema, a mood is a freeform, short mood keyword or phrase along | |
| 921 | -- with an optional mood icon image. | |
| 922 | newtype Mood = Mood { fromMood :: Aeson.Object } deriving (Eq, Show) | |
| 923 | ||
| 924 | instance FromJSON Mood where | |
| 925 | parseJSON (Aeson.Object o) = do | |
| 926 | ensure "Mood" o ["displayname", "image"] | |
| 927 | return (Mood o) | |
| 928 | parseJSON _ = fail "Mood not an object" | |
| 929 | ||
| 930 | instance ToJSON Mood where | |
| 931 | toJSON = Aeson.Object . fromMood | |
| 932 | ||
| 933 | -- | Access to the underlying JSON object of a 'Mood' | |
| 934 | moodRest :: Lens' Mood Aeson.Object | |
| 935 | moodRest = makeLens fromMood (\ o' m -> m { fromMood = o' }) | |
| 936 | ||
| 937 | -- | The natural-language, human-readable and plain-text keyword or | |
| 938 | -- phrase describing the mood. HTML markup MUST NOT be included. | |
| 939 | moodDisplayName :: Lens' Mood Text | |
| 940 | moodDisplayName = makeAesonLens "displayName" moodRest | |
| 941 | ||
| 942 | -- | An optional image that provides a visual representation of the mood. | |
| 943 | moodImage :: Lens' Mood MediaLink | |
| 944 | moodImage = makeAesonLens "image" moodRest | |
| 1 | 1 | {-# LANGUAGE TemplateHaskell #-} |
| 2 | ||
| 3 | {-| | |
| 4 | Module : Codec.ActivityStream | |
| 5 | Description : The basic Activity Streams structures | |
| 6 | Copyright : (c) Getty Ritter, 2014 | |
| 7 | Maintainer : gdritter@galois.com | |
| 8 | ||
| 9 | This is an interface to ActivityStreams that simply wraps an underlying | |
| 10 | @aeson@ Object, and exposes a set of convenient lenses to access the | |
| 11 | values inside. If an @aeson@ object appears wrapped in some respective wrapper, | |
| 12 | it will necessarily contain the obligatory values for that type | |
| 13 | (e.g. an 'Activity' is guaranteed to have a @published@ date.) | |
| 14 | ||
| 15 | Most of the inline documentation is drawn directly from the | |
| 16 | <http://activitystrea.ms/specs/json/1.0/ JSON Activity Streams 1.0> | |
| 17 | specification, with minor modifications | |
| 18 | to refer to the corresponding data types in this module and to clarify | |
| 19 | certain aspects. | |
| 20 | -} | |
| 2 | 21 | |
| 3 | 22 | module Codec.ActivityStream |
| 4 | 23 | ( module Codec.ActivityStream.Representation |
| 1 | -- Initial activitystreams-aeson.cabal generated by cabal init. For | |
| 2 | -- further documentation, see http://haskell.org/cabal/users-guide/ | |
| 1 | name: activitystreams-aeson | |
| 2 | version: 0.2.0.0 | |
| 3 | synopsis: An interface to the ActivityStreams specification | |
| 4 | description: An interface to the | |
| 5 | <http://activitystrea.ms/ Activity Streams> | |
| 6 | specifications, using an @aeson@-based representation | |
| 7 | of the underlying ActivityStream structures. | |
| 3 | 8 | |
| 4 | name: activitystreams-aeson | |
| 5 | version: 0.1.0.0 | |
| 6 | -- synopsis: | |
| 7 | -- description: | |
| 9 | An ActivityStream is a representation of social | |
| 10 | activities in JSON format, using a standard set of | |
| 11 | structures. The specification is very flexible in | |
| 12 | allowing most fields to be omitted, while also | |
| 13 | allowing arbitrary new fields to be created when | |
| 14 | necessary. This library attempts to maximize | |
| 15 | type safety while retaining the flexibility present | |
| 16 | in the specification. | |
| 8 | 17 | license: BSD3 |
| 9 | 18 | license-file: LICENSE |
| 10 | 19 | author: Getty Ritter |
| 11 | 20 | maintainer: gettylefou@gmail.com |
| 12 | -- copyright: | |
| 21 | copyright: (c) 2014 Getty Ritter | |
| 13 | 22 | category: Codec |
| 14 | 23 | build-type: Simple |
| 15 | -- extra-source-files: | |
| 16 | 24 | cabal-version: >=1.10 |
| 17 | 25 | |
| 18 | 26 | library |
| 19 | exposed-modules: Codec.ActivityStream.Dynamic, | |
| 20 | Codec.ActivityStream.DynamicSchema, | |
| 27 | exposed-modules: Codec.ActivityStream | |
| 28 | Codec.ActivityStream.Schema | |
| 29 | other-modules: Codec.ActivityStream.Internal, | |
| 21 | 30 | Codec.ActivityStream.Representation, |
| 22 | Codec.ActivityStream.Schema, | |
| 23 | Codec.ActivityStream | |
| 24 | other-modules: Codec.ActivityStream.Internal, | |
| 25 | 31 | Codec.ActivityStream.LensInternal |
| 26 | build-depends: base >=4.7 && <4.8, | |
| 27 | aeson, | |
| 28 | text, | |
| 29 | url, | |
| 30 | lens, | |
| 31 | datetime, | |
| 32 | unordered-containers, | |
| 33 | network-uri | |
| 32 | build-depends: base >=4.7 && <4.8, | |
| 33 | aeson ==0.8.*, | |
| 34 | text >=1.1, | |
| 35 | datetime ==0.2.*, | |
| 36 | unordered-containers >=0.2.5 | |
| 34 | 37 | default-language: Haskell2010 |