module Data.JSONResume
( Resume (..)
, URL
, EmailAddress
, Address (..)
, Profile (..)
, Basics (..)
, Organization (..)
, Work (..)
, Volunteer (..)
, Education (..)
, Award (..)
, Publication (..)
, Skill (..)
, Language (..)
, Interest (..)
, Reference (..)
) where
import qualified Data.Text as T
import qualified Data.HashMap.Strict as H
import System.Locale (defaultTimeLocale)
import Data.Time (UTCTime)
import Data.Time.Format (formatTime, parseTime)
import Data.Aeson (ToJSON (..), FromJSON (..), Value (..),
object, (.:?), (.!=), (.=), withText)
import Data.Aeson.Types (Parser)
import Control.Applicative (Applicative (..), (<$>), (<*>), pure)
import Control.Monad (mzero)
data Resume = Resume
{ basics :: Maybe Basics
, work :: [Work]
, volunteer :: [Volunteer]
, education :: [Education]
, awards :: [Award]
, publications :: [Publication]
, skills :: [Skill]
, languages :: [Language]
, interests :: [Interest]
, references :: [Reference]
} deriving (Read, Show)
instance FromJSON Resume where
parseJSON (Object v) =
Resume <$> v .:? "basics"
<*> v .:? "work" .!= []
<*> v .:? "volunteer" .!= []
<*> v .:? "education" .!= []
<*> v .:? "awards" .!= []
<*> v .:? "publications" .!= []
<*> v .:? "skills" .!= []
<*> v .:? "languages" .!= []
<*> v .:? "interests" .!= []
<*> v .:? "references" .!= []
parseJSON _ = mzero
instance ToJSON Resume where
toJSON (Resume b w v e a p s l i r) = object
[ "basics" .= b
, "work" .= w
, "volunteer" .= v
, "education" .= e
, "awards" .= a
, "publications" .= p
, "skills" .= s
, "languages" .= l
, "interests" .= i
, "references" .= r
]
type URL = T.Text
type EmailAddress = T.Text
data Address = Address
{ address :: Maybe T.Text
, postalCode :: Maybe T.Text
, city :: Maybe T.Text
, countryCode :: Maybe T.Text
, region :: Maybe T.Text
} deriving (Read, Show)
instance FromJSON Address where
parseJSON (Object v) =
Address <$> v .:? "address"
<*> v .:? "postalCode"
<*> v .:? "city"
<*> v .:? "countryCode"
<*> v .:? "region"
parseJSON _ = mzero
instance ToJSON Address where
toJSON (Address a p c cc r) = object
[ "address" .= a
, "postalCode" .= p
, "city" .= c
, "countryCode" .= cc
, "region" .= r
]
data Profile = Profile
{ network :: Maybe T.Text
, username :: Maybe T.Text
, url :: Maybe URL
} deriving (Read, Show)
instance FromJSON Profile where
parseJSON (Object v) =
Profile <$> v .:? "network"
<*> v .:? "username"
<*> v .:? "url"
parseJSON _ = mzero
instance ToJSON Profile where
toJSON (Profile n u web) = object
[ "network" .= n
, "username" .= u
, "url" .= web
]
data Basics = Basics
{ name :: Maybe T.Text
, label :: Maybe T.Text
, picture :: Maybe URL
, email :: Maybe EmailAddress
, phone :: Maybe T.Text
, website :: Maybe URL
, summary :: Maybe T.Text
, location :: Maybe Address
, profiles :: [Profile]
} deriving (Read, Show)
instance FromJSON Basics where
parseJSON (Object v) =
Basics <$> v .:? "name"
<*> v .:? "label"
<*> v .:? "picture"
<*> v .:? "email"
<*> v .:? "phone"
<*> v .:? "website"
<*> v .:? "summary"
<*> v .:? "location"
<*> v .:? "profiles" .!= []
parseJSON _ = mzero
instance ToJSON Basics where
toJSON (Basics n l pic e phn w s loc ps) = object
[ "name" .= n
, "label" .= l
, "picture" .= pic
, "email" .= e
, "phone" .= phn
, "website" .= w
, "summary" .= s
, "location" .= loc
, "profiles" .= ps
]
data Organization = Organization
{ orgName :: Maybe T.Text
, orgPosition :: Maybe T.Text
, orgSite :: Maybe URL
, orgStartDate :: Maybe UTCTime
, orgEndDate :: Maybe UTCTime
, orgSummary :: Maybe T.Text
, orgHighlights :: [T.Text]
} deriving (Read, Show)
newtype Work = Work Organization deriving (Read, Show)
instance FromJSON Work where
parseJSON (Object v) = fmap Work $
Organization <$> v .:? "company"
<*> v .:? "position"
<*> v .:? "website"
<*> potentially dateFromJSON v "startDate"
<*> potentially dateFromJSON v "endDate"
<*> v .:? "summary"
<*> v .:? "highlights" .!= []
parseJSON _ = mzero
instance ToJSON Work where
toJSON (Work (Organization n p web start end smry hl)) = object
[ "company" .= n
, "position" .= p
, "website" .= web
, ("startDate", toJSON $ dateToJSON <$> start)
, ("endDate", toJSON $ dateToJSON <$> end)
, "summary" .= smry
, "highlights" .= hl
]
newtype Volunteer = Volunteer Organization deriving (Read, Show)
instance FromJSON Volunteer where
parseJSON (Object v) = fmap Volunteer $
Organization <$> v .:? "organization"
<*> v .:? "position"
<*> v .:? "website"
<*> potentially dateFromJSON v "startDate"
<*> potentially dateFromJSON v "endDate"
<*> v .:? "summary"
<*> v .:? "highlights" .!= []
parseJSON _ = mzero
instance ToJSON Volunteer where
toJSON (Volunteer (Organization n p web start end smry hl)) = object
[ "organization" .= n
, "position" .= p
, "website" .= web
, ("startDate", toJSON $ dateToJSON <$> start)
, ("endDate", toJSON $ dateToJSON <$> end)
, "summary" .= smry
, "highlights" .= hl
]
data Education = Education
{ institution :: Maybe T.Text
, area :: Maybe T.Text
, studyType :: Maybe T.Text
, startDate :: Maybe UTCTime
, endDate :: Maybe UTCTime
, gpa :: Maybe T.Text
, courses :: [T.Text]
} deriving (Read, Show)
instance FromJSON Education where
parseJSON (Object v) =
Education <$> v .:? "institution"
<*> v .:? "area"
<*> v .:? "studyType"
<*> potentially dateFromJSON v "startDate"
<*> potentially dateFromJSON v "endDate"
<*> v .:? "gpa"
<*> v .:? "courses" .!= []
parseJSON _ = mzero
instance ToJSON Education where
toJSON (Education i a t start end g cs) = object
[ "institution" .= i
, "area" .= a
, "studyType" .= t
, ("startDate", toJSON $ dateToJSON <$> start)
, ("endDate", toJSON $ dateToJSON <$> end)
, "gpa" .= g
, "courses" .= cs
]
data Award = Award
{ title :: Maybe T.Text
, date :: Maybe UTCTime
, awarder :: Maybe T.Text
, awardSummary :: Maybe T.Text
} deriving (Read, Show)
instance FromJSON Award where
parseJSON (Object v) =
Award <$> v .:? "title"
<*> potentially dateFromJSON v "date"
<*> v .:? "awarder"
<*> v .:? "summary"
parseJSON _ = mzero
instance ToJSON Award where
toJSON (Award t d a s) = object
[ "title" .= t
, ("date", toJSON $ dateToJSON <$> d)
, "awarder" .= a
, "summary" .= s
]
data Publication = Publication
{ pubName :: Maybe T.Text
, publisher :: Maybe T.Text
, pubReleaseDate :: Maybe UTCTime
, pubSite :: Maybe URL
, pubSummary :: Maybe T.Text
} deriving (Read, Show)
instance FromJSON Publication where
parseJSON (Object v) =
Publication <$> v .:? "name"
<*> v .:? "publisher"
<*> potentially dateFromJSON v "releaseDate"
<*> v .:? "website"
<*> v .:? "summary"
parseJSON _ = mzero
instance ToJSON Publication where
toJSON (Publication n p d web s) = object
[ "name" .= n
, "publisher" .= p
, ("releaseDate", toJSON $ dateToJSON <$> d)
, "website" .= web
, "summary" .= s
]
data Skill = Skill
{ skillName :: Maybe T.Text
, skillLevel :: Maybe T.Text
, skillKeywords :: [T.Text]
} deriving (Read, Show)
instance FromJSON Skill where
parseJSON (Object v) =
Skill <$> v .:? "name"
<*> v .:? "level"
<*> v .:? "keywords" .!= []
parseJSON _ = mzero
instance ToJSON Skill where
toJSON (Skill n l ks) = object
[ "name" .= n
, "level" .= l
, "keywords" .= ks
]
data Language = Language
{ language :: Maybe T.Text
, fluency :: Maybe T.Text
} deriving (Read, Show)
instance FromJSON Language where
parseJSON (Object v) =
Language <$> v .:? "language"
<*> v .:? "fluency"
parseJSON _ = mzero
instance ToJSON Language where
toJSON (Language l f) = object
[ "language" .= l
, "fluency" .= f
]
data Interest = Interest
{ interestName :: Maybe T.Text
, interestKeywords :: [T.Text]
} deriving (Read, Show)
instance FromJSON Interest where
parseJSON (Object v) =
Interest <$> v .:? "name"
<*> v .:? "keywords" .!= []
parseJSON _ = mzero
instance ToJSON Interest where
toJSON (Interest n ks) = object
[ "name" .= n
, "keywords" .= ks
]
data Reference = Reference
{ refName :: Maybe T.Text
, reference :: Maybe T.Text
} deriving (Read, Show)
instance FromJSON Reference where
parseJSON (Object v) =
Reference <$> v .:? "name"
<*> v .:? "reference"
parseJSON _ = mzero
instance ToJSON Reference where
toJSON (Reference n r) = object
[ "name" .= n
, "reference" .= r
]
dateToJSON :: UTCTime -> Value
dateToJSON t = String $ T.pack $ formatTime defaultTimeLocale "%F" t
dateFromJSON :: Value -> Parser UTCTime
dateFromJSON = withText "UTCTime" $ \t ->
case parseTime defaultTimeLocale "%F" (T.unpack t) of
Just d -> pure d
_ -> fail "could not parse ISO-8601 date"
potentially :: (Value -> Parser a) -> H.HashMap T.Text Value -> T.Text -> Parser (Maybe a)
potentially f obj key = case H.lookup key obj of
Nothing -> pure Nothing
Just v -> Just <$> f v