module Instagram.Types (
Credentials(..)
,clientIDBS
,clientSecretBS
,OAuthToken(..)
,AccessToken(..)
,UserID
,User(..)
,Scope(..)
,IGException(..)
,Envelope(..)
,ErrEnvelope(..)
,IGError
,Pagination(..)
,MediaID
,Media(..)
,Position(..)
,UserPosition(..)
,LocationID
,Location(..)
,ImageData(..)
,Images(..)
,CommentID
,Comment(..)
,Collection(..)
,Aspect(..)
,media
,CallbackUrl
,Subscription(..)
,Update(..)
,TagName
,Tag(..)
,OutgoingStatus(..)
,IncomingStatus(..)
,Relationship(..)
,NoResult
,GeographyID
)where
import Control.Applicative
import Data.Text
import Data.Typeable (Typeable)
import Data.ByteString (ByteString)
import Data.Aeson
import qualified Data.Text.Encoding as TE
import Control.Exception.Base (Exception)
import Data.Time.Clock.POSIX (POSIXTime)
import qualified Data.Text as T (pack)
import Data.Aeson.Types (Parser)
import qualified Data.HashMap.Strict as HM (lookup)
data Credentials = Credentials {
cClientID :: Text
,cClientSecret :: Text
}
deriving (Show,Read,Eq,Ord,Typeable)
clientIDBS :: Credentials -> ByteString
clientIDBS=TE.encodeUtf8 . cClientID
clientSecretBS :: Credentials -> ByteString
clientSecretBS=TE.encodeUtf8 . cClientSecret
data OAuthToken = OAuthToken {
oaAccessToken :: AccessToken
,oaUser :: User
}
deriving (Show,Read,Eq,Ord,Typeable)
instance ToJSON OAuthToken where
toJSON oa=object ["access_token" .= oaAccessToken oa, "user" .= oaUser oa]
instance FromJSON OAuthToken where
parseJSON (Object v) =OAuthToken <$>
v .: "access_token" <*>
v .: "user"
parseJSON _= fail "OAuthToken"
newtype AccessToken=AccessToken Text
deriving (Eq, Ord, Read, Show, Typeable)
instance ToJSON AccessToken where
toJSON (AccessToken at)=String at
instance FromJSON AccessToken where
parseJSON (String s)=pure $ AccessToken s
parseJSON _= fail "AccessToken"
type UserID = Text
data User = User {
uID :: UserID,
uUsername :: Text,
uFullName :: Text,
uProfilePicture :: Maybe Text,
uWebsite :: Maybe Text
}
deriving (Show,Read,Eq,Ord,Typeable)
instance ToJSON User where
toJSON u=object ["id" .= uID u, "username" .= uUsername u , "full_name" .= uFullName u, "profile_picture" .= uProfilePicture u, "website" .= uWebsite u]
instance FromJSON User where
parseJSON (Object v) =User <$>
v .: "id" <*>
v .: "username" <*>
v .: "full_name" <*>
v .:? "profile_picture" <*>
v .:? "website"
parseJSON _= fail "User"
data Scope=Basic | Comments | Relationships | Likes
deriving (Show,Read,Eq,Ord,Enum,Bounded,Typeable)
data IGError = IGError {
igeCode :: Int
,igeType :: Maybe Text
,igeMessage :: Maybe Text
}
deriving (Show,Read,Eq,Ord,Typeable)
instance ToJSON IGError where
toJSON e=object ["code" .= igeCode e, "error_type" .= igeType e , "error_message" .= igeMessage e]
instance FromJSON IGError where
parseJSON (Object v) =IGError <$>
v .: "code" <*>
v .:? "error_type" <*>
v .:? "error_message"
parseJSON _= fail "IGError"
data IGException = JSONException String
| IGAppException IGError
deriving (Show,Typeable)
instance Exception IGException
data Envelope d=Envelope{
eMeta :: IGError
,eData :: d
,ePagination :: Maybe Pagination
}
deriving (Show,Read,Eq,Ord,Typeable)
instance (ToJSON d)=>ToJSON (Envelope d) where
toJSON e=object ["meta" .= eMeta e, "data" .= eData e, "pagination" .= ePagination e]
instance (FromJSON d)=>FromJSON (Envelope d) where
parseJSON (Object v) =Envelope <$>
v .: "meta" <*>
v .: "data" <*>
v .:? "pagination"
parseJSON _= fail "Envelope"
data ErrEnvelope=ErrEnvelope{
eeMeta :: IGError
}
deriving (Show,Read,Eq,Ord,Typeable)
instance ToJSON ErrEnvelope where
toJSON e=object ["meta" .= eeMeta e]
instance FromJSON ErrEnvelope where
parseJSON (Object v) =ErrEnvelope <$>
v .: "meta"
parseJSON _= fail "ErrEnvelope"
data Pagination = Pagination {
pNextUrl :: Maybe Text
,pNextMaxID :: Maybe Text
,pNextMinID :: Maybe Text
,pNextMaxTagID :: Maybe Text
,pMinTagID :: Maybe Text
}
deriving (Show,Read,Eq,Ord,Typeable)
instance ToJSON Pagination where
toJSON p=object ["next_url" .= pNextUrl p, "next_max_id" .= pNextMaxID p, "next_min_id" .= pNextMinID p, "next_max_tag_id" .= pNextMaxTagID p,"min_tag_id" .= pMinTagID p]
instance FromJSON Pagination where
parseJSON (Object v) =Pagination <$>
v .:? "next_url" <*>
v .:? "next_max_id" <*>
v .:? "next_min_id" <*>
v .:? "next_max_tag_id" <*>
v .:? "min_tag_id"
parseJSON _= fail "Pagination"
type MediaID=Text
data Media = Media {
mID :: MediaID
,mCaption :: Maybe Comment
,mLink :: Text
,mUser :: User
,mCreated :: POSIXTime
,mImages :: Images
,mType :: Text
,mUsersInPhoto :: [UserPosition]
,mFilter :: Maybe Text
,mTags :: [Text]
,mLocation :: Maybe Location
,mComments :: Collection Comment
,mLikes :: Collection User
,mUserHasLiked :: Bool
,mAttribution :: Maybe Object
}
deriving (Show,Eq,Typeable)
instance ToJSON Media where
toJSON m=object ["id" .= mID m,"caption" .= mCaption m,"user".= mUser m,"link" .= mLink m, "created_time" .= toJSON (show ((round $ mCreated m) :: Integer))
,"images" .= mImages m,"type" .= mType m,"users_in_photo" .= mUsersInPhoto m, "filter" .= mFilter m,"tags" .= mTags m
,"location" .= mLocation m,"comments" .= mComments m,"likes" .= mLikes m,"user_has_liked" .= mUserHasLiked m,"attribution" .= mAttribution m]
instance FromJSON Media where
parseJSON (Object v) =do
ct::String<-v .: "created_time"
Media <$>
v .: "id" <*>
v .:? "caption" <*>
v .: "link" <*>
v .: "user" <*>
pure (fromIntegral (read ct::Integer)) <*>
v .: "images" <*>
v .: "type" <*>
v .: "users_in_photo" <*>
v .:? "filter" <*>
v .: "tags" <*>
v .:? "location" <*>
v .:? "comments" .!= Collection 0 [] <*>
v .:? "likes" .!= Collection 0 [] <*>
v .:? "user_has_liked" .!= False <*>
v .:? "attribution"
parseJSON _= fail "Media"
data Position = Position {
pX ::Double
,pY :: Double
} deriving (Show,Eq,Typeable)
instance ToJSON Position where
toJSON p=object ["x" .= pX p,"y" .= pY p]
instance FromJSON Position where
parseJSON (Object v) = Position <$>
v .: "x" <*>
v .: "y"
parseJSON _=fail "Position"
data UserPosition = UserPosition {
upPosition :: Position
,upUser :: User
} deriving (Show,Eq,Typeable)
instance ToJSON UserPosition where
toJSON p=object ["position" .= upPosition p,"user" .= upUser p]
instance FromJSON UserPosition where
parseJSON (Object v) = UserPosition <$>
v .: "position" <*>
v .: "user"
parseJSON _=fail "UserPosition"
type LocationID = Text
data Location = Location {
lID :: Maybe LocationID
,lLatitude :: Maybe Double
,lLongitude :: Maybe Double
,lStreetAddress :: Maybe Text
,lName :: Maybe Text
}
deriving (Show,Eq,Ord,Typeable)
instance ToJSON Location where
toJSON l=object ["id" .= lID l,"latitude" .= lLatitude l,"longitude" .= lLongitude l, "street_address" .= lStreetAddress l,"name" .= lName l]
instance FromJSON Location where
parseJSON (Object v) =
Location <$>
parseID v <*>
v .:? "latitude" <*>
v .:? "longitude" <*>
v .:? "street_address" <*>
v .:? "name"
where
parseID :: Object -> Parser (Maybe LocationID)
parseID obj=case HM.lookup "id" obj of
Just (String s)->pure $ Just s
Just (Number n)->pure $ Just $ T.pack $ show n
Nothing->pure Nothing
_->fail "LocationID"
parseJSON _= fail "Location"
data ImageData = ImageData {
idURL :: Text,
idWidth :: Integer,
idHeight :: Integer
}
deriving (Show,Eq,Ord,Typeable)
instance ToJSON ImageData where
toJSON i=object ["url" .= idURL i,"width" .= idWidth i,"height" .= idHeight i]
instance FromJSON ImageData where
parseJSON (Object v) = ImageData <$>
v .: "url" <*>
v .: "width" <*>
v .: "height"
parseJSON _= fail "ImageData"
data Images = Images {
iLowRes :: ImageData
,iThumbnail :: ImageData
,iStandardRes :: ImageData
}
deriving (Show,Eq,Ord,Typeable)
instance ToJSON Images where
toJSON i=object ["low_resolution" .= iLowRes i,"thumbnail" .= iThumbnail i,"standard_resolution" .= iStandardRes i]
instance FromJSON Images where
parseJSON (Object v) = Images <$>
v .: "low_resolution" <*>
v .: "thumbnail" <*>
v .: "standard_resolution"
parseJSON _= fail "Images"
type CommentID = Text
data Comment = Comment {
cID :: CommentID
,cCreated :: POSIXTime
,cText :: Text
,cFrom :: User
}
deriving (Show,Eq,Ord,Typeable)
instance ToJSON Comment where
toJSON c=object ["id" .= cID c,"created_time" .= toJSON (show ((round $ cCreated c) :: Integer))
,"text" .= cText c,"from" .= cFrom c]
instance FromJSON Comment where
parseJSON (Object v) =do
ct::String<-v .: "created_time"
Comment <$>
v .: "id" <*>
pure (fromIntegral (read ct::Integer)) <*>
v .: "text" <*>
v .: "from"
parseJSON _= fail "Caption"
data Collection a= Collection {
cCount :: Integer
,cData :: [a]
}
deriving (Show,Eq,Ord,Typeable)
instance (ToJSON a)=>ToJSON (Collection a) where
toJSON igc=object ["count" .= cCount igc,"data" .= cData igc]
instance (FromJSON a)=>FromJSON (Collection a) where
parseJSON (Object v) = Collection <$>
v .: "count" <*>
v .: "data"
parseJSON _= fail "Collection"
type CallbackUrl = Text
data Aspect = Aspect Text
deriving (Show, Read, Eq, Ord, Typeable)
instance ToJSON Aspect where
toJSON (Aspect t)=String t
instance FromJSON Aspect where
parseJSON (String t) = pure $ Aspect t
parseJSON _= fail "Aspect"
media :: Aspect
media = Aspect "media"
data Subscription= Subscription {
sID :: Text
,sType :: Text
,sObject :: Text
,sObjectID :: Maybe Text
,sAspect :: Aspect
,sCallbackUrl :: CallbackUrl
,sLatitude :: Maybe Double
,sLongitude :: Maybe Double
,sRadius :: Maybe Integer
}
deriving (Show,Eq,Typeable)
instance ToJSON Subscription where
toJSON s=object ["id" .= sID s,"type" .= sType s,"object" .= sObject s,"object_id" .= sObjectID s,"aspect" .= sAspect s
,"callback_url".=sCallbackUrl s,"lat".= sLatitude s,"lng".=sLongitude s,"radius".=sRadius s]
instance FromJSON Subscription where
parseJSON (Object v) = Subscription <$>
v .: "id" <*>
v .: "type" <*>
v .: "object" <*>
v .:? "object_id" <*>
v .: "aspect" <*>
v .: "callback_url" <*>
v .:? "lat" <*>
v .:? "lng" <*>
v .:? "radius"
parseJSON _= fail "Subscription"
data Update = Update {
uSubscriptionID :: Integer
,uObject :: Text
,uObjectID :: Text
,uChangedAspect :: Aspect
,uTime :: POSIXTime
}
deriving (Show,Eq,Typeable)
instance ToJSON Update where
toJSON u=object ["subscription_id" .= uSubscriptionID u ,"object" .= uObject u,"object_id" .= uObjectID u
,"changed_aspect" .= uChangedAspect u,"time" .= toJSON ((round $ uTime u) :: Integer)]
instance FromJSON Update where
parseJSON (Object v) =do
ct::Integer<-v .: "time"
Update <$>
v .: "subscription_id" <*>
v .: "object" <*>
v .: "object_id" <*>
v .: "changed_aspect" <*>
pure (fromIntegral ct)
parseJSON _= fail "Update"
type TagName = Text
data Tag = Tag {
tName :: TagName,
tMediaCount :: Integer
}
deriving (Show,Read,Eq,Ord,Typeable)
instance ToJSON Tag where
toJSON t=object ["name" .= tName t,"media_count" .= tMediaCount t]
instance FromJSON Tag where
parseJSON (Object v) = Tag <$>
v .: "name" <*>
v .:? "media_count" .!= 0
parseJSON _= fail "Tag"
data OutgoingStatus = Follows | Requested | OutNone
deriving (Show,Read,Eq,Ord,Bounded,Enum,Typeable)
instance ToJSON OutgoingStatus where
toJSON Follows = String "follows"
toJSON Requested = String "requested"
toJSON OutNone = String "none"
instance FromJSON OutgoingStatus where
parseJSON (String "follows")=pure Follows
parseJSON (String "requested")=pure Requested
parseJSON (String "none")=pure OutNone
parseJSON _= fail "OutgoingStatus"
data IncomingStatus = FollowedBy | RequestedBy | BlockedByYou | InNone
deriving (Show,Read,Eq,Ord,Bounded,Enum,Typeable)
instance ToJSON IncomingStatus where
toJSON FollowedBy = String "followed_by"
toJSON RequestedBy = String "requested_by"
toJSON BlockedByYou = String "blocked_by_you"
toJSON InNone = String "none"
instance FromJSON IncomingStatus where
parseJSON (String "followed_by")=pure FollowedBy
parseJSON (String "requested_by")=pure RequestedBy
parseJSON (String "blocked_by_you")=pure BlockedByYou
parseJSON (String "none")=pure InNone
parseJSON _= fail "IncomingStatus"
data Relationship = Relationship {
rOutgoing :: OutgoingStatus
,rIncoming :: IncomingStatus
,rTargetUserPrivate :: Bool
}
deriving (Show,Read,Eq,Ord,Typeable)
instance ToJSON Relationship where
toJSON r=object ["outgoing_status" .= rOutgoing r,"incoming_status" .= rIncoming r,"target_user_is_private" .= rTargetUserPrivate r]
instance FromJSON Relationship where
parseJSON (Object v) = Relationship <$>
v .:? "outgoing_status" .!= OutNone <*>
v .:? "incoming_status" .!= InNone <*>
v .:? "target_user_is_private" .!= False
parseJSON _= fail "Relationship"
data NoResult = NoResult
deriving (Show,Read,Eq,Ord,Typeable)
instance ToJSON NoResult where
toJSON _=Null
instance FromJSON NoResult where
parseJSON Null = pure NoResult
parseJSON _= fail "NoResult"
type GeographyID = Text