| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 | {-# LANGUAGE OverloadedStrings #-}{-|Module      : Codec.ActivityStream.RepresentationDescription : A (more dynamic) interface to Activity StreamsCopyright   : (c) Getty Ritter, 2014Maintainer  : gdritter@galois.comThis is an interface to ActivityStreams that simply wraps an underlying@aeson@ Object, and exposes a set of (convenient) lenses to access thevalues inside. If an @aeson@ object is wrapped in the respective wrapper,it will contain the obligatory values for that type (e.g. an 'Activity'is guaranteed to have a @published@ date.)Most of the inline documentation is drawn directly from the<http://activitystrea.ms/specs/json/1.0/ JSON Activity Streams 1.0>specification, with minor modificationsto refer to the corresponding data types in this module and to clarifycertain aspects.-}module Codec.ActivityStream.Representation       ( Lens'         -- * Object       , Object       , emptyObject         -- ** Object Lenses       , oAttachments       , oAuthor       , oContent       , oDisplayName       , oDownstreamDuplicates       , oId       , oImage       , oObjectType       , oPublished       , oSummary       , oUpdated       , oUpstreamDuplicates       , oURL       , oRest         -- * Activity       , Activity       , makeActivity       , asObject         -- ** Activity Lenses       , acActor       , acContent       , acGenerator       , acIcon       , acId       , acObject       , acPublished       , acProvider       , acTarget       , acTitle       , acUpdated       , acURL       , acVerb       , acRest         -- * MediaLink       , MediaLink       , makeMediaLink         -- ** MediaLink Lenses       , mlDuration       , mlHeight       , mlWidth       , mlURL       , mlRest         -- * Collection       , Collection       , makeCollection         -- ** Collection Lenses       , cTotalItems       , cItems       , cURL       , cRest       ) whereimport           Data.Aeson ( FromJSON(..)                            , ToJSON(..)                            , Result(..)                            , fromJSON                            )import qualified Data.Aeson as Aimport           Data.Time.Clock (UTCTime)import qualified Data.HashMap.Strict as HMimport           Data.Text (Text)import Codec.ActivityStream.Internal (ensure)import Codec.ActivityStream.LensInternal-- | Some types of objects may have an alternative visual representation in--   the form of an image, video or embedded HTML fragments. A 'MediaLink'--   represents a hyperlink to such resources.newtype MediaLink = MediaLink { fromMediaLink :: A.Object } deriving (Eq, Show)instance FromJSON MediaLink where  parseJSON (A.Object o) = do    ensure "MediaLink" o ["url"]    return (MediaLink o)  parseJSON _ = fail "MediaLink not an object"instance ToJSON MediaLink where  toJSON (MediaLink o) = A.Object o-- | Access the underlying JSON object that represents a Media LinkmlRest :: Lens' MediaLink A.ObjectmlRest = makeLens fromMediaLink (\ o' m -> m { fromMediaLink = o' })-- | A hint to the consumer about the length, in seconds, of the media--   resource identified by the url property. A media link MAY contain--   a "duration" property when the target resource is a time-based--   media item such as an audio or video.mlDuration :: Lens' MediaLink (Maybe Int)mlDuration = makeAesonLensMb "duration" mlRest-- | A hint to the consumer about the height, in pixels, of the media--   resource identified by the url property. A media link MAY contain--   a @height@ property when the target resource is a visual media item--   such as an image, video or embeddable HTML page.mlHeight :: Lens' MediaLink (Maybe Int)mlHeight = makeAesonLensMb "height" mlRest-- | A hint to the consumer about the width, in pixels, of the media--   resource identified by the url property. A media link MAY contain--   a @width@ property when the target resource is a visual media item--   such as an image, video or embeddable HTML page.mlWidth :: Lens' MediaLink (Maybe Int)mlWidth = makeAesonLensMb "width" mlRest-- | The IRI of the media resource being linked. A media link MUST have a--   @url@ property.mlURL :: Lens' MediaLink TextmlURL = makeAesonLens "url" mlRest-- | Create a @MediaLink@ with just a @url@ property, and all other--   properties undefined.makeMediaLink :: Text -> MediaLinkmakeMediaLink url = MediaLink (HM.insert "url" (toJSON url) HM.empty)-- | Within the specification, an 'Object' is a thing, real or--   imaginary, which participates in an activity. It may be the--   entity performing the activity, or the entity on which the--   activity was performed. An object consists of properties--   defined below. Certain object types may--   further refine the meaning of these properties, or they may--   define additional properties.----   To maintain this flexibility in the Haskell environment, an--   'Object' is an opaque wrapper over an underlying JSON value,--   and the 'oRest' accessor can be used to access that underlying--   value.newtype Object = Object { fromObject :: A.Object } deriving (Eq, Show)instance FromJSON Object where  parseJSON (A.Object o) = return (Object o)  parseJSON _            = fail "Object not an object"instance ToJSON Object where  toJSON (Object o) = A.Object o-- | Access the underlying JSON object that represents an 'Object'oRest :: Lens' Object A.ObjectoRest = makeLens fromObject (\ o' m -> m { fromObject = o' })-- | A collection of one or more additional, associated objects, similar--   to the concept of attached files in an email message. An object MAY--   have an attachments property whose value is a JSON Array of 'Object's.oAttachments :: Lens' Object (Maybe [Object])oAttachments = makeAesonLensMb "attachments" oRest-- | Describes the entity that created or authored the object. An object--   MAY contain a single author property whose value is an 'Object' of any--   type. Note that the author field identifies the entity that created--   the object and does not necessarily identify the entity that--   published the object. For instance, it may be the case that an--   object created by one person is posted and published to a system by--   an entirely different entity.oAuthor :: Lens' Object (Maybe Object)oAuthor = makeAesonLensMb "author" oRest-- | Natural-language description of the object encoded as a single JSON--   String containing HTML markup. Visual elements such as thumbnail--   images MAY be included. An object MAY contain a @content@ property.oContent :: Lens' Object (Maybe Text)oContent = makeAesonLensMb "content" oRest-- | A natural-language, human-readable and plain-text name for the--   object. HTML markup MUST NOT be included. An object MAY contain--   a @displayName@ property. If the object does not specify an @objectType@--   property, the object SHOULD specify a @displayName@.oDisplayName :: Lens' Object (Maybe Text)oDisplayName = makeAesonLensMb "displayName" oRest-- | A JSON Array of one or more absolute IRI's--   <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]> identifying--   objects that duplicate this object's content. An object SHOULD--   contain a @downstreamDuplicates@ property when there are known objects,--   possibly in a different system, that duplicate the content in this--   object. This MAY be used as a hint for consumers to use when--   resolving duplicates between objects received from different sources.oDownstreamDuplicates :: Lens' Object (Maybe [Text])oDownstreamDuplicates = makeAesonLensMb "downstreamDuplicates" oRest-- | Provides a permanent, universally unique identifier for the object in--   the form of an absolute IRI--   <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. An--   object SHOULD contain a single @id@ property. If an object does not--   contain an @id@ property, consumers MAY use the value of the @url@--   property as a less-reliable, non-unique identifier.oId :: Lens' Object (Maybe Text)oId = makeAesonLensMb "id" oRest-- | Description of a resource providing a visual representation of the--   object, intended for human consumption. An object MAY contain an--   @image@ property whose value is a 'MediaLink'.oImage :: Lens' Object (Maybe MediaLink)oImage = makeAesonLensMb "image" oRest-- | Identifies the type of object. An object MAY contain an @objectType@--   property whose value is a JSON String that is non-empty and matches--   either the "isegment-nz-nc" or the \"IRI\" production in--   <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. Note--   that the use of a relative reference other than a simple name is--   not allowed. If no @objectType@ property is contained, the object has--   no specific type.oObjectType :: (FromJSON o, ToJSON o) => Lens' Object (Maybe o)oObjectType = makeAesonLensMb "objectType" oRest-- | The date and time at which the object was published. An object MAY--   contain a @published@ property.oPublished :: Lens' Object (Maybe UTCTime)oPublished = makeAesonLensMb "published" oRest-- | Natural-language summarization of the object encoded as a single--   JSON String containing HTML markup. Visual elements such as thumbnail--   images MAY be included. An activity MAY contain a @summary@ property.oSummary :: Lens' Object (Maybe Text)oSummary = makeAesonLensMb "summary" oRest-- | The date and time at which a previously published object has been--   modified. An Object MAY contain an @updated@ property.oUpdated :: Lens' Object (Maybe UTCTime)oUpdated = makeAesonLensMb "updated" oRest-- | A JSON Array of one or more absolute IRI's--   <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]> identifying--   objects that duplicate this object's content. An object SHOULD contain--   an @upstreamDuplicates@ property when a publisher is knowingly--   duplicating with a new ID the content from another object. This MAY be--   used as a hint for consumers to use when resolving duplicates between--   objects received from different sources.oUpstreamDuplicates :: Lens' Object (Maybe [Text])oUpstreamDuplicates = makeAesonLensMb "upstreamDuplicates" oRest-- | An IRI <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>--   identifying a resource providing an HTML representation of the--   object. An object MAY contain a url propertyoURL :: Lens' Object (Maybe Text)oURL = makeAesonLensMb "url" oRest-- | Create an @Object@ with no fields.emptyObject :: ObjectemptyObject = Object HM.empty-- | In its simplest form, an 'Activity' consists of an @actor@, a @verb@, an--   @object@, and a @target@. It tells the story of a person performing an--   action on or with an object -- "Geraldine posted a photo to her--   album" or "John shared a video". In most cases these components--   will be explicit, but they may also be implied.newtype Activity = Activity { fromActivity :: A.Object } deriving (Eq, Show)instance FromJSON Activity where  parseJSON (A.Object o) = do    ensure "Activity" o ["published", "provider"]    return (Activity o)  parseJSON _ = fail "\"Activity\" not an object"instance ToJSON Activity where  toJSON (Activity o) = A.Object o-- | Access the underlying JSON object that represents an 'Activity'acRest :: Lens' Activity A.ObjectacRest = makeLens fromActivity (\ o' m -> m { fromActivity = o' })-- | Describes the entity that performed the activity. An activity MUST--   contain one @actor@ property whose value is a single 'Object'.acActor :: Lens' Activity ObjectacActor = makeAesonLens "actor" acRest-- | Natural-language description of the activity encoded as a single--   JSON String containing HTML markup. Visual elements such as--   thumbnail images MAY be included. An activity MAY contain a--   @content@ property.acContent :: Lens' Activity (Maybe Text)acContent = makeAesonLensMb "content" acRest-- | Describes the application that generated the activity. An activity--   MAY contain a @generator@ property whose value is a single 'Object'.acGenerator :: Lens' Activity (Maybe Object)acGenerator = makeAesonLens "generator" acRest-- | Description of a resource providing a visual representation of the--   object, intended for human consumption. The image SHOULD have an--   aspect ratio of one (horizontal) to one (vertical) and SHOULD be--   suitable for presentation at a small size. An activity MAY have--   an @icon@ property.acIcon :: Lens' Activity (Maybe MediaLink)acIcon = makeAesonLensMb "icon" acRest-- | Provides a permanent, universally unique identifier for the activity--   in the form of an absolute IRI--   <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>. An--   activity SHOULD contain a single @id@ property. If an activity does--   not contain an @id@ property, consumers MAY use the value of the--   @url@ property as a less-reliable, non-unique identifier.acId :: Lens' Activity (Maybe Text)acId = makeAesonLensMb "id" acRest-- | Describes the primary object of the activity. For instance, in the--   activity, "John saved a movie to his wishlist", the object of the--   activity is "movie". An activity SHOULD contain an @object@ property--   whose value is a single 'Object'. If the @object@ property is not--   contained, the primary object of the activity MAY be implied by--   context.acObject :: Lens' Activity (Maybe Object)acObject = makeAesonLensMb "object" acRest-- | The date and time at which the activity was published. An activity--   MUST contain a @published@ property.acPublished :: Lens' Activity UTCTimeacPublished = makeAesonLens "published" acRest-- | Describes the application that published the activity. Note that this--   is not necessarily the same entity that generated the activity. An--   activity MAY contain a @provider@ property whose value is a--   single 'Object'.acProvider :: Lens' Activity (Maybe Object)acProvider = makeAesonLensMb "provider" acRest-- | Describes the target of the activity. The precise meaning of the--   activity's target is dependent on the activities verb, but will--   often be the object the English preposition "to". For instance, in--   the activity, "John saved a movie to his wishlist", the target of--   the activity is "wishlist". The activity target MUST NOT be used--   to identity an indirect object that is not a target of the--   activity. An activity MAY contain a @target@ property whose value--   is a single 'Object'.acTarget :: Lens' Activity (Maybe Object)acTarget = makeAesonLensMb "target" acRest-- | Natural-language title or headline for the activity encoded as a--  single JSON String containing HTML markup. An activity MAY contain--  a @title@ property.acTitle :: Lens' Activity (Maybe Text)acTitle = makeAesonLensMb "title" acRest-- | The date and time at which a previously published activity has--   been modified. An Activity MAY contain an @updated@ property.acUpdated :: Lens' Activity (Maybe UTCTime)acUpdated = makeAesonLensMb "updated" acRest-- | An IRI <http://www.ietf.org/rfc/rfc3987.txt RFC3987>--   identifying a resource providing an HTML representation of the--   activity. An activity MAY contain a @url@ property.acURL :: Lens' Activity (Maybe Text)acURL = makeAesonLensMb "url" acRest-- | Identifies the action that the activity describes. An activity SHOULD--   contain a verb property whose value is a JSON String that is--   non-empty and matches either the \"isegment-nz-nc\" or the--   \"IRI\" production in <http://www.ietf.org/rfc/rfc3987.txt [RFC3987]>.--   Note that the use of a relative--   reference other than a simple name is not allowed. If the @verb@ is--   not specified, or if the value is null, the @verb@ is--   assumed to be \"post\".acVerb :: (FromJSON v, ToJSON v) => Lens' Activity (Maybe v)acVerb = makeAesonLensMb "verb" acRest-- | Create an @Activity@ with an @actor@, @published@, and--   @provider@ property.makeActivity :: Object -> UTCTime -> ActivitymakeActivity actor published = Activity  $ HM.insert "actor"     (toJSON actor)  $ HM.insert "published" (toJSON published)  $ HM.empty-- | JSON Activity Streams 1.0 specificies that an @Activity@ may be used as an--   @Object@. In such a case, the object may have fields permitted on either an--   @Activity@ or an @Object@asObject :: Activity -> ObjectasObject act = Object (fromActivity act)-- | A "collection" is a generic list of 'Object's of any object type.--   The @objectType@ of each item in the collection MAY be omitted if--   the type of object can be established through context. The collection--   is used primarily as the root of an Activity Streams document as described--   in Section 4,--   but can be used as the value of extension properties in a variety of--   situations.newtype Collection = Collection { fromCollection :: A.Object } deriving (Eq, Show)instance FromJSON Collection where  parseJSON (A.Object o) = return (Collection o)  parseJSON _            = fail "\"Collection\" not an object"instance ToJSON Collection where  toJSON (Collection o) = A.Object o-- | Access the underlying JSON object that represents a 'Collection'cRest :: Lens' Collection A.ObjectcRest = makeLens fromCollection (\ o' m -> m { fromCollection = o' })-- | Non-negative integer specifying the total number of activities--   within the stream. The Stream serialization MAY contain a--   @totalItems@ property. (NOTE: there is a typo in the original--   specification, in which it inconsistently refers to this as--   either @totalItems@ or @count@.)cTotalItems :: Lens' Collection (Maybe Int)cTotalItems = makeAesonLensMb "totalItems" cRest-- | An array containing a listing of 'Object's of any object type.--   If used in combination with the @url@ property, the @items@ array--   can be used to provide a subset of the objects that may be--   found in the resource identified by the @url@.cItems :: Lens' Collection (Maybe [Object])cItems = makeAesonLensMb "items" cRest-- | An IRI <http://activitystrea.ms/specs/json/1.0/#RFC3987 [RFC3987]>--   referencing a JSON document containing the full--   listing of objects in the collection.cURL :: Lens' Collection (Maybe Text)cURL = makeAesonLensMb "url" cRest-- | Create a @Collection@ with an @items@ and a @url@ property--   and fill in the corresponding @totalItems@ field with the--   length of the @items@ array.makeCollection :: [Object] -> Text -> CollectionmakeCollection objs url = Collection  $ HM.insert "totalItems" (toJSON (length objs))  $ HM.insert "items"      (toJSON objs)  $ HM.insert "url"        (toJSON url)  $ HM.empty
 |