mirror of
https://code.sup39.dev/repos/Wqawg
synced 2025-01-07 20:46:45 +09:00
e8ba301c6a
See Vervis ticket #60.
224 lines
5.5 KiB
Haskell
224 lines
5.5 KiB
Haskell
{- 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 $ SharerR shr
|
|
, actorType = "Person"
|
|
, actorInbox = ur $ SharerR shr
|
|
, actorOutbox = ur $ error "We don't have outboxes yet"
|
|
}
|