Experimental changes to Vervis.

[[ 🗃 ^KrXYo vervis ]] :: [📥 Inbox] [📤 Outbox] [🐤 Followers] [🤝 Collaborators] [🛠 Changes]

Clone

HTTPS: darcs clone https://vervis.peers.community/repos/KrXYo

SSH: darcs clone USERNAME@vervis.peers.community:KrXYo

Tags

TODO

src / Vervis /

ActivityStreams.hs

{- This file is part of Vervis.
 -
 - Written in 2018 by fr33domlover <fr33domlover@riseup.net>.
 -
 - ♡ Copying is an act of love. Please copy, reuse and share.
 -
 - The author(s) have dedicated all copyright and related and neighboring
 - rights to this software to the public domain worldwide. This software is
 - distributed without any warranty.
 -
 - You should have received a copy of the CC0 Public Domain Dedication along
 - with this software. If not, see
 - <http://creativecommons.org/publicdomain/zero/1.0/>.
 -}

module Vervis.ActivityStreams
    ( Actor (..)
    , ActivityStreams2 (..)
    , provideAS2
    , makeActor
    )
where

import Control.Monad.Trans.Writer
import Data.Aeson (pairs)
import Data.Monoid

import Vervis.Import
import Vervis.Model.Ident

-- AS2 is divided into core and extensions-for-common-social-web-use-cases, I'm
-- starting with the core, looking at the AS2 vocab spec

{-
data Object = Object
    { objectAttachment   ::
    , objectAttributedTo ::
    , objectAudience     ::
    , objectContent      ::
    , objectContext      ::
    , objectName         ::
    , objectEndTime      ::
    , objectGenerator    ::
    , objectIcon         ::
    , objectImage        ::
    , objectInReplyTo    ::
    , objectLocation     ::
    , objectPreview      ::
    , objectPublished    ::
    , objectReplies      ::
    , objectStartTime    ::
    , objectSummary      ::
    , objectTag          ::
    , objectUpdated      ::
    , objectUrl          ::
    , objectTo           ::
    , objectBto          ::
    , objectCc           ::
    , objectBcc          ::
    , objectMediaType    ::
    , objectDuration     ::
    }

data Link = Link
    { linkHref      ::
    , linkRel       ::
    , linkMediaType ::
    , linkName      ::
    , linkHrefLang  ::
    , linkHeight    ::
    , linkWidth     ::
    , linkPreview   ::
    }

data Activity = Activity
    { activityAsObject   :: Object
    , activityActor      ::
    , activityObject     ::
    , activityTarget     ::
    , activityResult     ::
    , activityOrigin     ::
    , activityInstrument ::
    }

data IntransitiveActivity = IntransitiveActivity
    { iactivityAsObject   :: Object
    , iactivityActor      ::
    , iactivityTarget     ::
    , iactivityResult     ::
    , iactivityOrigin     ::
    , iactivityInstrument ::
    }

data Collection = Collection
    { collectionAsObject   :: Object
    , collectionTotalItems ::
    , collectionCurrent    ::
    , collectionFirst      ::
    , collectionLast       ::
    , collectionItems      ::
    }

data OrderedCollection = OrderedCollection
    { ocollectionAsCollection :: Collection
    }

data CollectionPage = CollectionPage
    { collectionPageAsCollection :: Collection
    , collectionPagePartOf       ::
    , collectionPageNext         ::
    , collectionPagePrev         ::
    }

data OrderedCollectionPage = OrderedCollectionPage
    { orderedCollectionPageAsCollectionPage :: CollectionPage
    , orederdCollectionPageStartIndex       ::
    }

-- Now come the extended types

-- Activity types - I'm skipping them for now

-- Actor types

data Application = Application
    { applicationAsObject :: Object
    }

data Group = Group
    { groupAsObject :: Object
    }

data Organization = Organization
    { organizationAsObject :: Object
    }

data Person = Person
    { personAsObject :: Object
    }

data Service = Service
    { serviceAsObject :: Object
    }
-}

-- Actor objects in AP

data Actor = Actor
    { -- Requirements
      actorId     :: Text
    , actorType   :: Text
      -- Must
    , actorInbox  :: Text
    , actorOutbox :: Text
      -- Should
    --, actorFollowing
    --, actorFollowers
      -- May
    --, actorLiked
    --, actorStreams
    --, actorPreferredUsername
    --, actorEndpoints
    }

fields a =
    [ "@context" .= ("https://www.w3.org/ns/activitystreams" :: Text)
    , "id"       .= actorId a
    , "type"     .= actorType a
    , "inbox"    .= actorInbox a
    , "outbox"   .= actorOutbox a
    ]

instance ToJSON Actor where
    toJSON     = object . fields
    toEncoding = pairs . mconcat . fields

-- NEXT:
--
-- * Figure out how to detect the client wanting AS2 / AP
-- * Send minimal simple actor per user

typeActivityStreams2 :: ContentType
typeActivityStreams2 = "application/activity+json"

typeActivityStreams2LD :: ContentType
typeActivityStreams2LD =
    "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\""

data ActivityStreams2 = ActivityPubActor Actor

instance ToContent ActivityStreams2 where
    toContent (ActivityPubActor a) = toContent $ toEncoding a

{-
instance ToTypedContent ActivityStreams2 where
    toTypedContent = TypedContent typeActivityStreams2 . toContent

instance HasContentType ActivityStreams2 where
    getContentType _ = typeActivityStreams2

data ActivityStreams2LD = ActivityStreams2LD ActivityStreams2

instance ToContent ActivityStreams2LD where
    toContent (ActivityStreams2LD a) = toContent a

instance ToTypedContent ActivityStreams2LD where
    toTypedContent = TypedContent typeActivityStreams2LD . toContent

instance HasContentType ActivityStreams2LD where
    getContentType _ = typeActivityStreams2LD
-}

provideAS2 :: Monad m => ActivityStreams2 -> Writer (Endo [ProvidedRep m]) ()
provideAS2 as2 = do
    provideRepType typeActivityStreams2   $ return as2
    provideRepType typeActivityStreams2LD $ return as2

makeActor ur shr =
    Actor
        { actorId     = ur $ PersonR shr
        , actorType   = "Person"
        , actorInbox  = ur $ PersonR shr
        , actorOutbox = ur $ PersonActivitiesR shr
        }
[See repo JSON]