harvest-api-0.1.0: Web/Harvest/API/Type.hs
-- |
-- Module : Web.Harvest.API.Type
-- Copyright : © 2016 Stack Builders
-- License : MIT
--
-- Maintainer : Mark Karpov <mkarpov@stackbuilders.com>
-- Stability : experimental
-- Portability : portable
--
-- Used types, they are re-exported in "Web.Harvest.API", so you can import
-- just that module.
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Web.Harvest.API.Type
( Credentials (..)
, UserId (..)
, User (..)
, TimeEntryId (..)
, TimeEntries (..)
, TimeEntry (..) )
where
import Data.Aeson
import Data.ByteString (ByteString)
import Data.Text (Text)
import Data.Time (UTCTime, Day)
import Servant.API
-- | Information that is necessary for interaction with Harvest API.
data Credentials = Credentials
{ credentialsUsername :: ByteString -- ^ Username
, credentialsPassword :: ByteString -- ^ Password
, credentialsAccount :: ByteString -- ^ Account (name of your organization)
} deriving (Eq, Ord, Show)
-- | User identifier.
newtype UserId = UserId { unUserId :: Word }
deriving (Eq, Ord, Show, FromJSON, ToHttpApiData)
-- | User record.
data User = User
{ userId :: UserId -- ^ User id
, userEmail :: Text -- ^ Email address
, userCreatedAt :: UTCTime -- ^ When the user was created
, userIsAdmin :: Bool -- ^ Is the user admin?
, userFirstName :: Text -- ^ The user's first name
, userLastName :: Text -- ^ The user's last name
, userTimeZone :: Text -- ^ The user's time zone ('Text' for now)
, userIsContractor :: Bool -- ^ Is the user contractor?
, userTelephone :: Text -- ^ User's telephone
, userIsActive :: Bool -- ^ Is it an active user?
, userAccessFuture :: Bool
-- ^ Does he\/she have access to all future projects?
, userDefaultHourlyRate :: Word -- ^ Default hourly rate
, userDepartment :: Maybe Text -- ^ User's department
, userWantsNewsletter :: Bool
-- ^ Does he\/she want to recieve newsletter?
, userUpdatedAt :: UTCTime -- ^ Time of last update of account
, userCostRate :: Maybe Word -- ^ User's cost rate
, userIdentityAccountId :: Maybe Word -- ^ Identity account id
, userIdentityUserId :: Maybe Word -- ^ Identity user id
} deriving (Eq, Ord, Show)
instance FromJSON User where
parseJSON = withObject "User" $ \o -> do
u <- o .: "user"
userId <- u .: "id"
userEmail <- u .: "email"
userCreatedAt <- u .: "created_at"
userIsAdmin <- u .: "is_admin"
userFirstName <- u .: "first_name"
userLastName <- u .: "last_name"
userTimeZone <- u .: "timezone"
userIsContractor <- u .: "is_contractor"
userTelephone <- u .: "telephone"
userIsActive <- u .: "is_active"
userAccessFuture <- u .: "has_access_to_all_future_projects"
userDefaultHourlyRate <- u .: "default_hourly_rate"
userDepartment <- u .: "department"
userWantsNewsletter <- u .: "wants_newsletter"
userUpdatedAt <- u .: "updated_at"
userCostRate <- u .: "cost_rate"
userIdentityAccountId <- u .:? "identity_account_id"
userIdentityUserId <- u .:? "identity_user_id"
return User {..}
-- | Collection of entries for specific day.
-- TODO This response also contains the "projects" field with some stuff,
-- we could parse it as well, but let's skip it for now.
data TimeEntries = TimeEntries
{ teForDay :: Day -- ^ That collection is for this day
, teDayEntries :: [TimeEntry] -- ^ Collection of time entries
} deriving (Eq, Ord, Show)
instance FromJSON TimeEntries where
parseJSON = withObject "TimeEntries" $ \o -> do
teDayEntries <- o .: "day_entries"
teForDay <- o .: "for_day"
return TimeEntries {..}
-- | Time entry identifier.
newtype TimeEntryId = TimeEntryId
{ unTimeEntryId :: Word }
deriving (Eq, Ord, Show, FromJSON)
-- | A time entry.
data TimeEntry = TimeEntry
{ teProjectId :: Text -- ^ Project id
, teProject :: Text -- ^ Project
, teUserId :: UserId -- ^ User id
, teSpentAt :: Day -- ^ The day this time is spent on
, teTaskId :: Text -- ^ Task id
, teTask :: Text -- ^ Task name
, teClient :: Text -- ^ Client name
, teId :: TimeEntryId -- ^ Time entry id
, teNotes :: Maybe Text -- ^ Notes
, teTimerStartedAt :: Maybe UTCTime
-- ^ When the task was started, if 'Nothing' — timer is not running
, teCreatedAt :: UTCTime -- ^ When the task was created
, teUpdatedAt :: UTCTime -- ^ When the task was updated
, teHoursWithoutTimer :: Double -- ^ Hours without timer
, teHours :: Double -- ^ Hours
} deriving (Eq, Ord, Show)
instance FromJSON TimeEntry where
parseJSON = withObject "TimeEntry" $ \o -> do
teProjectId <- o .: "project_id"
teProject <- o .: "project"
teUserId <- o .: "user_id"
teSpentAt <- o .: "spent_at"
teTaskId <- o .: "task_id"
teTask <- o .: "task"
teClient <- o .: "client"
teId <- o .: "id"
teNotes <- o .: "notes"
teTimerStartedAt <- o .:? "timer_started_at"
teCreatedAt <- o .: "created_at"
teUpdatedAt <- o .: "updated_at"
teHoursWithoutTimer <- o .: "hours_without_timer"
teHours <- o .: "hours"
return TimeEntry {..}