11{-# LANGUAGE DataKinds #-}
2+ {-# LANGUAGE MultiWayIf #-}
23{-# LANGUAGE MonadFailDesugaring #-}
34{-# LANGUAGE RankNTypes #-}
45{-# LANGUAGE DeriveGeneric #-}
@@ -93,20 +94,25 @@ type UsersAPI =
9394 Get '[JSON ] [Item UserId User ] :<|>
9495 Capture " user_id" UserId :> Get '[JSON ] (Item UserId User ) :<|>
9596 Protected :>
96- ReqBody '[JSON ] User :>
97+ ReqBody '[JSON ] UserInfo :>
9798 Post '[JSON ] (Item UserId User ) :<|>
9899 Protected :>
99100 Capture " user_id" UserId :>
100- ReqBody '[JSON ] User :> Put '[JSON ] (Item UserId User ) :<|>
101+ ReqBody '[JSON ] UserInfo :> Put '[JSON ] (Item UserId User ) :<|>
101102 Protected :> Capture " user_id" UserId :> Delete '[JSON ] ()
102103
103104newtype Username = Username { unUsername :: T. Text }
104105 deriving stock (Show , Eq )
105106 deriving newtype (Aeson.FromJSON , Aeson.ToJSON )
106107
108+ data UserInfo = UserInfo
109+ { userInfoFirebaseId :: FirebaseId
110+ , userInfoEmail :: Maybe T. Text
111+ } deriving (Show , Eq )
112+
107113data User = User
108114 { userFirebaseId :: FirebaseId
109- , userUsername :: Maybe Username
115+ , userUsername :: Maybe Username -- + return anonymous
110116 } deriving (Show , Eq )
111117
112118newtype UserId = UserId { unUserId :: FirebaseId }
@@ -134,6 +140,21 @@ newtype FirebaseId = FirebaseId { unFirebaseId :: T.Text }
134140 ( Generic )
135141
136142-- XXX !!?!??!?!! pattern match failures are propagated to the client!!!
143+ instance FromJSONObject UserInfo where
144+ parseJSONObject = \ obj ->
145+ UserInfo
146+ <$> obj .: " firebase_uid"
147+ <*> (
148+ (do
149+ True <- obj .: " anonymous"
150+ (Nothing :: Maybe T. Text ) <- obj .:? " email"
151+ pure Nothing
152+ ) <|> (do
153+ False <- obj .: " anonymous"
154+ obj .:? " email"
155+ )
156+ )
157+
137158instance FromJSONObject User where
138159 parseJSONObject = \ obj ->
139160 User
@@ -145,23 +166,33 @@ instance FromJSONObject User where
145166 pure Nothing
146167 ) <|> (do
147168 False <- obj .: " anonymous"
148- obj .: " username"
169+ obj .:? " username"
149170 )
150171 )
151172
173+ instance ToJSONObject UserInfo where
174+ toJSONObject uinfo = HMS. fromList
175+ [ " anonymous" .= isNothing (userInfoEmail uinfo)
176+ , " email" .= userInfoEmail uinfo
177+ , " firebase_uid" .= userInfoFirebaseId uinfo
178+ ]
179+
180+ instance Aeson. FromJSON UserInfo where
181+ parseJSON = Aeson. withObject " UserInfo" parseJSONObject
182+
152183instance ToJSONObject User where
153184 toJSONObject user = HMS. fromList
154- [ " firebase_uid" .= userFirebaseId user
155- , " anonymous" .= isNothing (userUsername user)
185+ [ " anonymous" .= isNothing (userUsername user)
156186 , " username" .= userUsername user
187+ , " firebase_uid" .= userFirebaseId user
157188 ]
158189
159- instance Aeson. FromJSON User where
160- parseJSON = Aeson. withObject " User" parseJSONObject
161-
162190instance Aeson. ToJSON User where
163191 toJSON = Aeson. Object . toJSONObject
164192
193+ instance Aeson. ToJSON UserInfo where
194+ toJSON = Aeson. Object . toJSONObject
195+
165196instance ToSchema (Item UserId User ) where
166197 declareNamedSchema _ = pure $ NamedSchema (Just " UserWithId" ) mempty
167198
@@ -174,6 +205,18 @@ instance ToParamSchema (Item UserId User) where
174205instance ToParamSchema UserId where
175206 toParamSchema _ = mempty
176207
208+ -- instance ToSchema (Item UserId User) where
209+ -- declareNamedSchema _ = pure $ NamedSchema (Just "UserWithId") mempty
210+
211+ instance ToSchema UserInfo where
212+ declareNamedSchema _ = pure $ NamedSchema (Just " UserInfo" ) mempty
213+
214+ instance ToParamSchema (Item UserId UserInfo ) where
215+ toParamSchema _ = mempty
216+
217+ -- instance ToParamSchema UserId where
218+ -- toParamSchema _ = mempty
219+
177220-- DECKS
178221
179222type DecksAPI =
@@ -415,21 +458,34 @@ usersGetUserIdStatement = Statement sql encoder decoder True
415458 HD. nullableColumn (Username <$> HD. text)
416459 )
417460
418- usersPost :: HC. Connection -> Firebase. UserId -> User -> Servant. Handler (Item UserId User )
419- usersPost conn fuid user = do
420- let userId = UserId (userFirebaseId user)
421- liftIO $ putStrLn " POST users"
461+ usersPost
462+ :: HC. Connection
463+ -> Firebase. UserId
464+ -> UserInfo
465+ -> Servant. Handler (Item UserId User )
466+ usersPost conn fuid uinfo = do
422467
423- when (Firebase. unUserId fuid /= unFirebaseId (userFirebaseId user )) $ do
468+ when (Firebase. unUserId fuid /= unFirebaseId (userInfoFirebaseId uinfo )) $ do
424469 Servant. throwError Servant. err403
425- liftIO $ putStrLn " auth is ok"
426470
427471 iface <- liftIO $ getDbInterface conn
428472 liftIO $ putStrLn " got DB interface"
473+
474+ let userId = UserId (userInfoFirebaseId uinfo)
475+ user = userInfoToUser uinfo
429476 liftIO (dbCreateUser iface userId user) >>= \ case
430477 Left () -> Servant. throwError $ Servant. err409
431478 Right () -> pure $ Item userId user
432479
480+ userInfoToUser :: UserInfo -> User
481+ userInfoToUser uinfo = User
482+ { userFirebaseId = userInfoFirebaseId uinfo
483+ , userUsername = emailToUsername <$> userInfoEmail uinfo
484+ }
485+
486+ emailToUsername :: T. Text -> Username
487+ emailToUsername = Username
488+
433489usersPostSession :: UserId -> User -> HS. Session (Either () () )
434490usersPostSession uid u = do
435491 HS. sql " BEGIN"
@@ -505,20 +561,26 @@ usersPostStatement'' = Statement sql encoder decoder True
505561 (HE. param HE. text)
506562 decoder = HD. unit
507563
508- usersPut :: HC. Connection -> Firebase. UserId -> UserId -> User -> Servant. Handler (Item UserId User )
509- usersPut conn fuid userId user = do
564+ usersPut
565+ :: HC. Connection
566+ -> Firebase. UserId
567+ -> UserId
568+ -> UserInfo
569+ -> Servant. Handler (Item UserId User )
570+ usersPut conn fuid userId uinfo = do
510571
511572 when (Firebase. unUserId fuid /= unFirebaseId (unUserId userId)) $ do
512573 liftIO $ putStrLn $ unwords
513- [ " User is trying to update another user :" , show (fuid, userId, user ) ]
574+ [ " User is trying to update another uinfo :" , show (fuid, userId, uinfo ) ]
514575 Servant. throwError Servant. err404
515576
516- when (Firebase. unUserId fuid /= unFirebaseId (userFirebaseId user )) $ do
577+ when (Firebase. unUserId fuid /= unFirebaseId (userInfoFirebaseId uinfo )) $ do
517578 liftIO $ putStrLn $ unwords
518- [ " Client used the wrong user ID on user " , show (fuid, userId, user ) ]
579+ [ " Client used the wrong uinfo ID on uinfo " , show (fuid, userId, uinfo ) ]
519580 Servant. throwError Servant. err400
520581
521582 iface <- liftIO $ getDbInterface conn
583+ let user = userInfoToUser uinfo
522584 liftIO (dbUpdateUser iface userId user) >>= \ case
523585 UserUpdateOk -> pure $ Item userId user -- TODO: check # of affected rows
524586 e -> do -- TODO: handle not found et al.
@@ -1131,12 +1193,9 @@ data DbVersion
11311193
11321194-- | Migrates from ver to latest
11331195migrateFrom :: DbVersion -> HS. Session ()
1134- migrateFrom = \ ver ->
1135- if ver < maxBound
1136- then
1137- let frm = succ ver
1138- in forM_ [frm .. maxBound ] migrateTo
1139- else pure ()
1196+ migrateFrom = \ ver -> do
1197+ liftIO $ putStrLn $ " Migration: " <> show (dbVersionToText <$> [ver .. maxBound ])
1198+ forM_ [ver .. maxBound ] migrateTo
11401199 where
11411200 -- | Migrates from (ver -1) to ver
11421201 migrateTo :: DbVersion -> HS. Session ()
@@ -1159,7 +1218,7 @@ migrateFrom = \ver ->
11591218 ver@ DbVersion1 -> do
11601219 HS. statement () $ Statement
11611220 (BS8. unwords
1162- [ " DROP TABLE IF EXISTS account"
1221+ [ " DROP TABLE IF EXISTS account CASCADE "
11631222 ]
11641223 ) HE. unit HD. unit True
11651224 HS. statement () $ Statement
@@ -1215,8 +1274,7 @@ readDbVersion = do
12151274 , " );"
12161275 ]
12171276 ) HE. unit HD. unit True
1218- migrateFrom minBound
1219- pure $ Right $ Just maxBound
1277+ pure $ Right Nothing
12201278
12211279latestDbVersion :: DbVersion
12221280latestDbVersion = maxBound
@@ -1230,17 +1288,18 @@ dbVersionFromText :: T.Text -> Maybe DbVersion
12301288dbVersionFromText t =
12311289 find (\ ver -> dbVersionToText ver == t) [minBound .. maxBound ]
12321290
1233- -- XXX: this is not quite right, it'll never do the Version1 migration. Not a
1234- -- problem currently since we dump everything at v2 anyway.
12351291migrate :: HS. Session ()
12361292migrate = do
12371293 readDbVersion >>= \ case
12381294 Left e -> error $ show e
1239- Right Nothing -> migrateFrom minBound
1295+ Right Nothing -> do
1296+ liftIO $ putStrLn " Migrating from beginning"
1297+ migrateFrom minBound
12401298 Right (Just v) ->
1241- if v >= maxBound
1242- then pure ()
1243- else migrateFrom v
1299+ if
1300+ | v == maxBound -> pure ()
1301+ | v > maxBound -> error " V greater than maxbound"
1302+ | v < maxBound -> migrateFrom (succ v)
12441303
12451304getDbInterface :: HC. Connection -> IO DbInterface
12461305getDbInterface conn = do
@@ -1251,8 +1310,8 @@ getDbInterface conn = do
12511310 pure $ DbInterface
12521311 { dbGetAllUsers = wrap usersGetSession
12531312 , dbGetUserById = \ uid -> wrap (usersGetUserIdSession uid)
1254- , dbCreateUser = \ uid user -> wrap (usersPostSession uid user )
1255- , dbUpdateUser = \ uid user -> wrap (usersPutSession uid user )
1313+ , dbCreateUser = \ uid uinfo -> wrap (usersPostSession uid uinfo )
1314+ , dbUpdateUser = \ uid uinfo -> wrap (usersPutSession uid uinfo )
12561315 , dbDeleteUser = \ uid -> Right <$> wrap (usersDeleteSession uid)
12571316 }
12581317 where
0 commit comments