Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added offline mode and save/refresh FromClient-constructed Credentials functions #66

Merged
merged 3 commits into from
Mar 17, 2017

Conversation

rueshyna
Copy link
Contributor

@rueshyna rueshyna commented Mar 6, 2017

I added the several functions to save/refresh FromClient-constructed Credentials.

After initial authorization, an accessToken can be refresh by refreshStore. As well as, it can be converted to AuthorizedUser and saved. Next time, users can read it directly.

Moreover, I added an assess_type param to form URL.

@rueshyna
Copy link
Contributor Author

rueshyna commented Mar 10, 2017

Here is an example of the new change.
In run "fst" part, it shows auth retrieving and saving.
In run "snd" part, it shows reading credential back, token refreshing and operating google sheet.

@brendanhay , Can you review the change?

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE KindSignatures    #-}
{-# LANGUAGE DataKinds         #-}
{-# LANGUAGE FlexibleContexts  #-}

module Main where


import Control.Lens           ((&), (.~), (<&>), (?~), (^.))
import Control.Monad.IO.Class
import Control.Monad.Catch
import Data.Text      as T
import Data.Text.IO   as T
import GHC.TypeLits
import Network.Google
import Network.Google.Auth
import Network.Google.Auth.InstalledApplication
import Network.Google.Sheets
import Network.HTTP.Client
import System.Environment
import System.IO              (stdout)

type S = '["https://www.googleapis.com/auth/spreadsheets"]

getGEnv ::(AllowScopes S) => IO (Env S)
getGEnv = do
    let clientId = ClientId "xxx"
        secret   = Secret "xxx"
        oAuthClient = OAuthClient clientId secret
    oc <- redirectPrompt oAuthClient spreadsheetsScope
    let c = installedApplication oAuthClient oc

    lgr  <- newLogger Debug stdout
    m <- liftIO (newManager tlsManagerSettings)
    newEnvWith c lgr m <&> (envScopes .~ spreadsheetsScope)

callSheet :: AllowScopes S => Env S -> IO ValueRange
callSheet e = runResourceT . runGoogle e $
        send (spreadsheetsValuesGet "xxxx" "Sheet1!A1")

redirectPrompt :: AllowScopes (s :: [Symbol]) => OAuthClient -> proxy s -> IO (OAuthCode s)
redirectPrompt c p = do
 let url = formAccessTypeURL c Offline p
 T.putStrLn $ "Opening URL " `T.append` url
 T.putStrLn "Please input the authorisation code: "
 OAuthCode <$> T.getLine

main :: IO ()
main = do
    args <- getArgs
    run $ pack $ Prelude.head args
    return ()

run :: T.Text -> IO ()
run "fst" = do
    env <- getGEnv
    auth <- retrieveAuthFromStore $ env ^. envStore
    either print (saveAuthorizedUserToWellKnownPath True) $ authToAuthorizedUser auth

run "snd" = do
    c <- fromWellKnownPath
    lgr  <- newLogger Debug stdout
    m <- liftIO (newManager tlsManagerSettings)
    env <- newEnvWith c lgr m <&> (envScopes .~ spreadsheetsScope)
    callSheet env >>= print

run _  = print "unknown"

} deriving (Eq, Show, Generic)

instance ToJSON AuthorizedUser where
toEncoding (AuthorizedUser i r s) =
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By giving AuthorizedUser a Generic instance and not supplying toJSON you will get divergent behaviour between encode . toJSON and encode which will used toJSON and toEncoding, respectively. Could you add the toJSON implementation, even if it means dropping the toEncoding?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right.
I removed toEncoding and add toJSON implementation.

mx <- validate x
if mx
then pure ss
else liftIO . modifyMVar s $ \y -> do
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since MVars are actually lazy I'm not entirely sure (and could be wrong) but the result of this operation won't be evaluated until the store is read? Some details here and here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm.. after re-tracking the code, I think this function might be unnecessary. It looks like the token would be refreshed if it expired while using send, isn't it? so, I removed it for now.

@brendanhay
Copy link
Owner

Just the question about MVar use and the need to supply a toJSON implementation.

Thanks for the PR!

@rueshyna
Copy link
Contributor Author

@brendanhay
I made some changes and left messages on your comments.
Could you review it again?

@brendanhay
Copy link
Owner

:shipit: Thanks!

@brendanhay brendanhay merged commit f14b3b6 into brendanhay:develop Mar 17, 2017
@rueshyna
Copy link
Contributor Author

rueshyna commented Apr 9, 2017

@brendanhay Could you publish the new changes? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants