diff --git a/lib/mobility-core/mobility-core.cabal b/lib/mobility-core/mobility-core.cabal index 9dcb0b5e5..6284be49b 100644 --- a/lib/mobility-core/mobility-core.cabal +++ b/lib/mobility-core/mobility-core.cabal @@ -246,6 +246,11 @@ library Kernel.External.Verification.SafetyPortal.Error Kernel.External.Verification.SafetyPortal.Types Kernel.External.Verification.Types + Kernel.External.Weather.Interface + Kernel.External.Weather.Interface.OpenWeatherMap + Kernel.External.Weather.OpenWeatherMap.API + Kernel.External.Weather.OpenWeatherMap.Config + Kernel.External.Weather.Types Kernel.External.Whatsapp.GupShup.Config Kernel.External.Whatsapp.GupShup.Flow Kernel.External.Whatsapp.Interface diff --git a/lib/mobility-core/src/Kernel/External/Weather/Interface.hs b/lib/mobility-core/src/Kernel/External/Weather/Interface.hs new file mode 100644 index 000000000..6b542d5b7 --- /dev/null +++ b/lib/mobility-core/src/Kernel/External/Weather/Interface.hs @@ -0,0 +1,16 @@ +module Kernel.External.Weather.Interface where + +import qualified Kernel.External.Weather.Interface.OpenWeatherMap as OWM +import Kernel.External.Weather.Types +import Kernel.Tools.Metrics.CoreMetrics (CoreMetrics) +import Kernel.Utils.Common + +getWeather :: + ( EncFlow m r, + CoreMetrics m + ) => + WeatherServiceConfig -> + WeatherReq -> + m WeatherResponse +getWeather serviceConfig req = case serviceConfig of + OpenWeatherMapConfig cfg -> OWM.getWeather cfg req diff --git a/lib/mobility-core/src/Kernel/External/Weather/Interface/OpenWeatherMap.hs b/lib/mobility-core/src/Kernel/External/Weather/Interface/OpenWeatherMap.hs new file mode 100644 index 000000000..1e7dc5588 --- /dev/null +++ b/lib/mobility-core/src/Kernel/External/Weather/Interface/OpenWeatherMap.hs @@ -0,0 +1,15 @@ +module Kernel.External.Weather.Interface.OpenWeatherMap (getWeather) where + +import Kernel.External.Encryption +import qualified Kernel.External.Weather.OpenWeatherMap.API as OWM +import Kernel.External.Weather.OpenWeatherMap.Config +import Kernel.External.Weather.Types +import Kernel.Tools.Metrics.CoreMetrics (CoreMetrics) + +getWeather :: (CoreMetrics m, EncFlow m r) => OpenWeatherCfg -> WeatherReq -> m WeatherResponse +getWeather config req = do + let url = config.url + lat = req.latitude + lon = req.longitude + apiKey <- decrypt config.apiKey + OWM.getWeather url apiKey lat lon diff --git a/lib/mobility-core/src/Kernel/External/Weather/OpenWeatherMap/API.hs b/lib/mobility-core/src/Kernel/External/Weather/OpenWeatherMap/API.hs new file mode 100644 index 000000000..e2da1672b --- /dev/null +++ b/lib/mobility-core/src/Kernel/External/Weather/OpenWeatherMap/API.hs @@ -0,0 +1,29 @@ +module Kernel.External.Weather.OpenWeatherMap.API where + +import EulerHS.Prelude +import EulerHS.Types as Euler +import qualified Kernel.External.Weather.Types as OW +import Kernel.Tools.Metrics.CoreMetrics as Metrics +import Kernel.Types.Error +import Kernel.Utils.Common +import Servant + +type OpenWeatherAPI = + "data" :> "2.5" :> "weather" + :> MandatoryQueryParam "lat" Text + :> MandatoryQueryParam "lon" Text + :> MandatoryQueryParam "appid" Text + :> Get '[JSON] OW.WeatherResponse + +getWeather :: (Metrics.CoreMetrics m, MonadFlow m) => BaseUrl -> Text -> Text -> Text -> m OW.WeatherResponse +getWeather url apiKey lat lon = do + let eulerClient = Euler.client openWeatherAPI lat lon apiKey + callOpenWeatherAPI url eulerClient "getWeather" openWeatherAPI + +openWeatherAPI :: Proxy OpenWeatherAPI +openWeatherAPI = Proxy + +callOpenWeatherAPI :: CallAPI' m api res res +callOpenWeatherAPI url eulerClient description proxy = do + callAPI url eulerClient description proxy + >>= fromEitherM (\err -> InternalError $ "Failed to call " <> description <> " API: " <> show err) diff --git a/lib/mobility-core/src/Kernel/External/Weather/OpenWeatherMap/Config.hs b/lib/mobility-core/src/Kernel/External/Weather/OpenWeatherMap/Config.hs new file mode 100644 index 000000000..b546a88e7 --- /dev/null +++ b/lib/mobility-core/src/Kernel/External/Weather/OpenWeatherMap/Config.hs @@ -0,0 +1,13 @@ +{-# LANGUAGE DerivingStrategies #-} + +module Kernel.External.Weather.OpenWeatherMap.Config where + +import Data.Aeson +import Kernel.External.Encryption +import Kernel.Prelude + +data OpenWeatherCfg = OpenWeatherCfg + { apiKey :: EncryptedField 'AsEncrypted Text, + url :: BaseUrl + } + deriving (Show, Eq, Generic, ToJSON, FromJSON) diff --git a/lib/mobility-core/src/Kernel/External/Weather/Types.hs b/lib/mobility-core/src/Kernel/External/Weather/Types.hs new file mode 100644 index 000000000..b9c8f21c3 --- /dev/null +++ b/lib/mobility-core/src/Kernel/External/Weather/Types.hs @@ -0,0 +1,101 @@ +module Kernel.External.Weather.Types where + +import Data.Aeson.Types +import Kernel.External.Weather.OpenWeatherMap.Config as OWM +import Kernel.Prelude +import Kernel.Utils.JSON + +data Coordinates = Coordinates + { lon :: Float, + lat :: Float + } + deriving (Show, Generic, ToJSON, FromJSON) + +data WeatherCondition = WeatherCondition + { id :: Int, + main :: Text, + description :: Text, + icon :: Text + } + deriving (Show, Generic, ToJSON, FromJSON) + +data MainWeather = MainWeather + { temp :: Float, + feels_like :: Float, + temp_min :: Float, + temp_max :: Float, + pressure :: Int, + humidity :: Int, + sea_level :: Int, + grnd_level :: Int + } + deriving (Show, Generic, ToJSON, FromJSON) + +data Wind = Wind + { speed :: Float, + deg :: Int, + gust :: Float + } + deriving (Show, Generic, ToJSON, FromJSON) + +newtype Rain = Rain + { _1h :: Float + } + deriving (Show, Generic) + +instance FromJSON Rain where + parseJSON = genericParseJSON stripPrefixUnderscoreIfAny + +instance ToJSON Rain where + toJSON = genericToJSON stripPrefixUnderscoreIfAny + +newtype Cloud = Cloud + { _all :: Int + } + deriving (Show, Generic) + +instance FromJSON Cloud where + parseJSON = genericParseJSON stripPrefixUnderscoreIfAny + +instance ToJSON Cloud where + toJSON = genericToJSON stripPrefixUnderscoreIfAny + +data SysWeather = SysWeather + { _type :: Int, + id :: Int, + country :: Text, + sunrise :: Int, + sunset :: Int + } + deriving (Show, Generic) + +instance FromJSON SysWeather where + parseJSON = genericParseJSON stripPrefixUnderscoreIfAny + +instance ToJSON SysWeather where + toJSON = genericToJSON stripPrefixUnderscoreIfAny + +data WeatherResponse = WeatherResponse + { coord :: Coordinates, + weather :: [WeatherCondition], + main :: MainWeather, + visibility :: Int, + wind :: Wind, + rain :: Rain, + clouds :: Cloud, + dt :: Int, + sys :: SysWeather, + name :: Text, + timezone :: Int, + id :: Int, + cod :: Int + } + deriving (Show, Generic, ToJSON, FromJSON) + +data WeatherReq = WeatherReq + { latitude :: Text, + longitude :: Text + } + +data WeatherServiceConfig = OpenWeatherMapConfig OWM.OpenWeatherCfg + deriving (Show, Eq, Generic, ToJSON, FromJSON)