webfinger-client 0.1.0.0 → 0.2.0.0
raw patch · 3 files changed
+78/−28 lines, 3 filesdep +link-relations
Dependencies added: link-relations
Files
- NEWS.md +24/−0
- src/Web/Finger/Client.hs +52/−27
- webfinger-client.cabal +2/−1
NEWS.md view
@@ -3,6 +3,30 @@ +webfinger-client 0.2.0.0 -- 2016-01-28+======================================++General, build and documentation changes:++* (None)++New APIs, features and enhancements:++* Allow to specify typed link relations in the query+* Return typed link relations in result++Bug fixes:++* (None)++Dependency changes:++* Add link-relations+++++ webfinger-client 0.1.0.0 -- 2015-12-12 ======================================
src/Web/Finger/Client.hs view
@@ -1,6 +1,6 @@ {- This file is part of webfinger-client. -- - Written in 2015 by fr33domlover <fr33domlover@riseup.net>.+ - Written in 2015, 2016 by fr33domlover <fr33domlover@riseup.net>. - - ♡ Copying is an act of love. Please copy, reuse and share. -@@ -22,6 +22,9 @@ -- To allow Language-hashed maps be FromJSON {-# LANGUAGE FlexibleInstances #-} +-- For avoiding redundant imports in base 4.8+{-# LANGUAGE CPP #-}+ module Web.Finger.Client ( Account (..) , Resource (..)@@ -35,19 +38,26 @@ ) where +#if !MIN_VERSION_base(4,8,0) import Control.Applicative+#endif+ import Control.Exception import Data.Aeson hiding (Result, Success) import Data.Aeson.Types (typeMismatch)+import Data.ByteString (ByteString) import Data.Default.Class import Data.Hashable+import Data.HashMap.Lazy (HashMap) import Data.Monoid ((<>))+import Data.Text (Text)+import Data.Text.Encoding (encodeUtf8) import GHC.Generics (Generic)+import Web.LinkRelations (LinkRelation, fromByteString, toByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC import qualified Data.HashMap.Lazy as M-import qualified Data.Text as T import qualified Network.HTTP.Client as H import qualified Network.HTTP.Client.TLS as H import qualified Network.HTTP.Types as HT@@ -66,7 +76,8 @@ - Other Nodes -* [ ] Add a list of properties and link relations, the Python module has one...+* [x] Support typed link relations+* [ ] Support typed properties * [x] Add an HTTP Accept header containing the JRD MIME type, the python module does it. But first read in the RFC to make sure it's ok -}@@ -74,20 +85,20 @@ -- | A given user at a given host. For example, /john@example.org/ means the -- user is /john/ and the host is /example.org/. data Account = Account- { acctUser :: B.ByteString- , acctHost :: B.ByteString+ { acctUser :: ByteString+ , acctHost :: ByteString } -- | A web resource about which you'd like to make a query. data Resource = ResAccount Account | ResUri U.URI- | ResUriStr B.ByteString+ | ResUriStr ByteString -- | HTTP user authentication details. data Auth = Auth- { authUser :: B.ByteString- , authPassword :: B.ByteString+ { authUser :: ByteString+ , authPassword :: ByteString } -- | A WebFinger query, for which the client can get a response.@@ -101,15 +112,16 @@ qryTarget :: Resource -- | A list of link relations by which to filter the link list in the -- returned description. If you'd like to receive /all/ the links, leave- -- this list empty.- , qryLinkRels :: [B.ByteString]+ -- this list empty. Use 'Left' to specify a raw link relation string, and+ -- 'Right' to specify a known typed relation.+ , qryLinkRels :: [Either ByteString LinkRelation] -- | You can explicitly specify a host (e.g. @www.example.org@) here, to -- which the WebFinger query will be sent. If you don't specify a host -- here, it will be extracted from the 'qryTarget' field (if it has a -- host part). Therefore this field is useful in special cases where the -- WebFinger server isn't the one referred by the target URI, or the URI -- doesn't have a host.- , qryHost :: Maybe B.ByteString+ , qryHost :: Maybe ByteString -- | HTTP authentication details. If the WebFinger server requires a -- username and password to access it, specify them here. For publicly -- available WebFinger servers, pass 'Nothing'.@@ -128,7 +140,7 @@ -- written. data Language -- | A specific language specified using a code, e.g. @en-us@.- = LanguageCode T.Text+ = LanguageCode Text -- | No specific language. However it doesn't mean that nothing is -- specified. It means that "language undefined" is explicity specified. | LanguageUndefined@@ -136,13 +148,13 @@ instance Hashable Language -toLang :: T.Text -> Language+toLang :: Text -> Language toLang t = if t == "und" then LanguageUndefined else LanguageCode t -instance FromJSON (M.HashMap Language T.Text) where+instance FromJSON (HashMap Language Text) where parseJSON v = M.fromList . map f . M.toList <$> parseJSON v where f (l, t) = (toLang l, t)@@ -159,30 +171,42 @@ -- /avatar/. -- -- A link relation may be a URI or one of the registered relation type- -- names.- lnkRelation :: T.Text --TODO: URI or registered relation type. Maybe parse it and give more typed info?+ -- names. If the relation type is recognized when parsing the server's+ -- response, you will get 'Right' a typed link relation here. Otherwise,+ -- e.g. if a non-URL private application-specific relation type is found,+ -- you will get 'Left' the raw relation type string.+ lnkRelation :: Either Text LinkRelation -- | The MIME type to be expected of the content behind the link URI. For -- example, if the link refers to a user's avatar image, the MIME type -- may be @image/png@ (i.e. an image file in PNG format).- , lnkMediaType :: Maybe T.Text+ , lnkMediaType :: Maybe Text -- | The link address itself. It is optional, because there may be cases -- in which all the information about the link is provided by the -- properties (the 'lnkProperties' field). For example, if the link is a -- user's avatar image, the address may be -- @https://example.org/users/john/avatar.png@.- , lnkAddress :: Maybe T.Text+ , lnkAddress :: Maybe Text -- | Optional title(s) for the link, possibly in various languages.- , lnkTitles :: M.HashMap Language T.Text+ , lnkTitles :: HashMap Language Text -- | Additional properties the link may have. Maps property names, which -- are URIs, to string values.- , lnkProperties :: M.HashMap T.Text (Maybe T.Text) --TODO use IANA database to parse known values?+ , lnkProperties :: HashMap Text (Maybe Text) --TODO use IANA database to parse known values? } deriving (Show) +parseRel :: Text -> Either Text LinkRelation+parseRel t =+ case fromByteString $ encodeUtf8 t of+ Nothing -> Left t+ Just lr -> Right lr++forF :: Functor f => f a -> (a -> b) -> f b+forF = flip fmap+ instance FromJSON Link where parseJSON (Object o) = Link <$>- o .: "rel" <*>+ o .: "rel" `forF` parseRel <*> o .:? "type" <*> o .:? "href" <*> o .:? "titles" .!= M.empty <*>@@ -194,13 +218,13 @@ { -- | A URI representing the resource being described. This is the same -- resource specified in the query, but the URI may slightly differ (e.g. -- appear in canonical form).- desSubject :: Maybe T.Text+ desSubject :: Maybe Text -- | List of URIs which identify the same resource as the 'desSubject' -- URI.- , desAliases :: [T.Text]+ , desAliases :: [Text] -- | Additional information about the subject. Maps property names, which -- are URIs, to string values.- , desProperties :: M.HashMap T.Text (Maybe T.Text) --TODO use IANA database to parse known values?+ , desProperties :: HashMap Text (Maybe Text) --TODO use IANA database to parse known values? -- | Links of various relation types from the subject resource to other -- resources represented by URIs. , desLinks :: [Link]@@ -242,7 +266,7 @@ newManager = H.newManager H.tlsManagerSettings -- | Try to get the host from a resource URI.-getHost :: U.URI -> Either String B.ByteString+getHost :: U.URI -> Either String ByteString getHost uri = case U.uriAuthority uri of Nothing -> Left "Resource URI has no authority part"@@ -250,7 +274,7 @@ -- | Determine URI and host from resource. If no host is found, return a -- message instead which explains why.-parseResource :: Resource -> (B.ByteString, Either String B.ByteString)+parseResource :: Resource -> (ByteString, Either String ByteString) parseResource (ResAccount a) = ( "acct:" <> acctUser a <> "@" <> acctHost a -- escape user! do i need to espcape host? , Right $ acctHost a -- do i need to escape host? does http-client do it anyway?@@ -305,7 +329,8 @@ Nothing -> req Just (Auth user pass) -> H.applyBasicAuth user pass req res = ("resource", Just uri)- rels = map ((,) "rel" . Just) $ qryLinkRels q+ toBS = either id toByteString+ rels = map ((,) "rel" . Just . toBS) $ qryLinkRels q params = res : rels req'' = H.setQueryString params req' eresp <- try (H.httpLbs req'' manager)
webfinger-client.cabal view
@@ -1,5 +1,5 @@ name: webfinger-client-version: 0.1.0.0+version: 0.2.0.0 synopsis: WebFinger client library description: This is a client library for querying a@@ -33,6 +33,7 @@ , http-client >=0.3.6 , http-client-tls >=0.2.2 , http-types+ , link-relations , text , unordered-containers >=0.2.5 , uri-bytestring >=0.1.7