From 84285250c941bdc0c2f43a2e9da340b8d1ea7ea9 Mon Sep 17 00:00:00 2001 From: Mihovil Ilakovac Date: Sat, 23 Mar 2024 16:54:50 +0100 Subject: [PATCH] Experimenting with TH Signed-off-by: Mihovil Ilakovac --- .../forms/internal/common/LoginSignupForm.tsx | 48 ++++---- waspc/src/Wasp/AppSpec/App/Auth.hs | 98 +++------------- .../src/Wasp/AppSpec/App/Auth/AuthMethods.hs | 105 ++++++++++++++++++ waspc/src/Wasp/AppSpec/App/Auth/IsEnabled.hs | 12 ++ waspc/src/Wasp/AppSpec/Valid.hs | 6 +- waspc/src/Wasp/Generator/AuthProviders.hs | 15 +++ .../Generator/SdkGenerator/Auth/AuthFormsG.hs | 37 +++--- .../Generator/SdkGenerator/Auth/EmailAuthG.hs | 4 +- .../Generator/SdkGenerator/Auth/LocalAuthG.hs | 4 +- .../Generator/SdkGenerator/Auth/OAuthAuthG.hs | 10 +- .../src/Wasp/Generator/SdkGenerator/AuthG.hs | 6 +- .../Generator/SdkGenerator/Client/AuthG.hs | 71 ++++-------- .../Generator/SdkGenerator/Server/AuthG.hs | 21 +--- .../ServerGenerator/Auth/EmailAuthG.hs | 11 +- .../ServerGenerator/Auth/LocalAuthG.hs | 5 +- .../ServerGenerator/Auth/OAuthAuthG.hs | 15 ++- .../Wasp/Generator/ServerGenerator/AuthG.hs | 29 +++-- .../Wasp/Generator/WebAppGenerator/AuthG.hs | 3 +- .../WebAppGenerator/RouterGenerator.hs | 4 +- waspc/waspc.cabal | 2 + 20 files changed, 279 insertions(+), 227 deletions(-) create mode 100644 waspc/src/Wasp/AppSpec/App/Auth/AuthMethods.hs create mode 100644 waspc/src/Wasp/AppSpec/App/Auth/IsEnabled.hs diff --git a/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx b/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx index ba9f336c52..206a52d235 100644 --- a/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx +++ b/waspc/data/Generator/templates/sdk/wasp/auth/forms/internal/common/LoginSignupForm.tsx @@ -27,12 +27,12 @@ import { SocialButton } from '../social/SocialButton' {=# isAnyPasswordBasedAuthEnabled =} import { useHistory } from 'react-router-dom' {=/ isAnyPasswordBasedAuthEnabled =} -{=# isUsernameAndPasswordAuthEnabled =} +{=# providers.isUsernameAndPasswordAuthEnabled =} import { useUsernameAndPassword } from '../usernameAndPassword/useUsernameAndPassword' -{=/ isUsernameAndPasswordAuthEnabled =} -{=# isEmailAuthEnabled =} +{=/ providers.isUsernameAndPasswordAuthEnabled =} +{=# providers.isEmailAuthEnabled =} import { useEmail } from '../email/useEmail' -{=/ isEmailAuthEnabled =} +{=/ providers.isEmailAuthEnabled =} {=# areBothSocialAndPasswordBasedAuthEnabled =} const OrContinueWith = styled('div', { @@ -105,15 +105,15 @@ const SocialAuthButtons = styled('div', { } }) {=/ isSocialAuthEnabled =} -{=# isGoogleAuthEnabled =} +{=# providers.isGoogleAuthEnabled =} const googleSignInUrl = `${config.apiUrl}{= googleSignInPath =}` -{=/ isGoogleAuthEnabled =} -{=# isKeycloakAuthEnabled =} +{=/ providers.isGoogleAuthEnabled =} +{=# providers.isKeycloakAuthEnabled =} const keycloakSignInUrl = `${config.apiUrl}{= keycloakSignInPath =}` -{=/ isKeycloakAuthEnabled =} -{=# isGitHubAuthEnabled =} +{=/ providers.isKeycloakAuthEnabled =} +{=# providers.isGitHubAuthEnabled =} const gitHubSignInUrl = `${config.apiUrl}{= gitHubSignInPath =}` -{=/ isGitHubAuthEnabled =} +{=/ providers.isGitHubAuthEnabled =} {=! // Since we allow users to add additional fields to the signup form, we don't @@ -151,7 +151,7 @@ export const LoginSignupForm = ({ {=/ isAnyPasswordBasedAuthEnabled =} const hookForm = useForm() const { register, formState: { errors }, handleSubmit: hookFormHandleSubmit } = hookForm - {=# isUsernameAndPasswordAuthEnabled =} + {=# providers.isUsernameAndPasswordAuthEnabled =} const { handleSubmit } = useUsernameAndPassword({ isLogin, onError: onErrorHandler, @@ -159,8 +159,8 @@ export const LoginSignupForm = ({ history.push('{= onAuthSucceededRedirectTo =}') }, }); - {=/ isUsernameAndPasswordAuthEnabled =} - {=# isEmailAuthEnabled =} + {=/ providers.isUsernameAndPasswordAuthEnabled =} + {=# providers.isEmailAuthEnabled =} const { handleSubmit } = useEmail({ isLogin, onError: onErrorHandler, @@ -172,7 +172,7 @@ export const LoginSignupForm = ({ history.push('{= onAuthSucceededRedirectTo =}') }, }); - {=/ isEmailAuthEnabled =} + {=/ providers.isEmailAuthEnabled =} {=# isAnyPasswordBasedAuthEnabled =} async function onSubmit (data) { setIsLoading(true); @@ -191,17 +191,17 @@ export const LoginSignupForm = ({ {cta} with - {=# isGoogleAuthEnabled =} + {=# providers.isGoogleAuthEnabled =} - {=/ isGoogleAuthEnabled =} + {=/ providers.isGoogleAuthEnabled =} - {=# isKeycloakAuthEnabled =} + {=# providers.isKeycloakAuthEnabled =} - {=/ isKeycloakAuthEnabled =} + {=/ providers.isKeycloakAuthEnabled =} - {=# isGitHubAuthEnabled =} + {=# providers.isGitHubAuthEnabled =} - {=/ isGitHubAuthEnabled =} + {=/ providers.isGitHubAuthEnabled =} {=/ isSocialAuthEnabled =} @@ -217,7 +217,7 @@ export const LoginSignupForm = ({ {=/ areBothSocialAndPasswordBasedAuthEnabled =} {=# isAnyPasswordBasedAuthEnabled =}
- {=# isUsernameAndPasswordAuthEnabled =} + {=# providers.isUsernameAndPasswordAuthEnabled =} Username {errors.username && {errors.username.message}} - {=/ isUsernameAndPasswordAuthEnabled =} - {=# isEmailAuthEnabled =} + {=/ providers.isUsernameAndPasswordAuthEnabled =} + {=# providers.isEmailAuthEnabled =} E-mail {errors.email && {errors.email.message}} - {=/ isEmailAuthEnabled =} + {=/ providers.isEmailAuthEnabled =} Password Bool -isUsernameAndPasswordAuthEnabled = isJust . usernameAndPassword . methods - -isExternalAuthEnabled :: Auth -> Bool -isExternalAuthEnabled auth = - any - ($ auth) - -- NOTE: Make sure to add new external auth methods here. - [ isGoogleAuthEnabled, - isGitHubAuthEnabled, - isKeycloakAuthEnabled - ] - -isGoogleAuthEnabled :: Auth -> Bool -isGoogleAuthEnabled = isJust . google . methods - -isKeycloakAuthEnabled :: Auth -> Bool -isKeycloakAuthEnabled = isJust . keycloak . methods - -isGitHubAuthEnabled :: Auth -> Bool -isGitHubAuthEnabled = isJust . gitHub . methods - -isEmailAuthEnabled :: Auth -> Bool -isEmailAuthEnabled = isJust . email . methods - --- These helper functions are used to avoid ambiguity when using the --- `userSignupFields` function (otherwise we need to use the DuplicateRecordFields --- extension in each module that uses them). -userSignupFieldsForEmailAuth :: EmailAuthConfig -> Maybe ExtImport -userSignupFieldsForEmailAuth = userSignupFields - -userSignupFieldsForUsernameAuth :: UsernameAndPasswordConfig -> Maybe ExtImport -userSignupFieldsForUsernameAuth = userSignupFields - -userSignupFieldsForExternalAuth :: ExternalAuthConfig -> Maybe ExtImport -userSignupFieldsForExternalAuth = userSignupFields +generateIsAuthMethodEnabled :: Q [Dec] +generateIsAuthMethodEnabled = do + let authMethodNames = map (\method -> (mkName . show $ method, (mkName . toLowerFirst . show) method)) [minBound .. maxBound :: AuthMethod] + clauses <- mapM generateClause authMethodNames + return [FunD (mkName "isAuthMethodEnabled") clauses] + where + generateClause :: (Name, Name) -> Q Clause + generateClause (authMethodCtor, authMethodName) = do + let authVar = mkName "auth" + body <- [|isJust ($(varE authMethodName) ($(varE (mkName "methods")) $(varE authVar)))|] + return $ Clause [ConP authMethodCtor [], VarP authVar] (NormalB body) [] diff --git a/waspc/src/Wasp/AppSpec/App/Auth/AuthMethods.hs b/waspc/src/Wasp/AppSpec/App/Auth/AuthMethods.hs new file mode 100644 index 0000000000..2cf4c9f6cc --- /dev/null +++ b/waspc/src/Wasp/AppSpec/App/Auth/AuthMethods.hs @@ -0,0 +1,105 @@ +{-# LANGUAGE DeriveDataTypeable #-} +{-# LANGUAGE DuplicateRecordFields #-} +{-# LANGUAGE TemplateHaskell #-} + +module Wasp.AppSpec.App.Auth.AuthMethods + ( generateAuthMethods, + userSignupFieldsForEmailAuth, + userSignupFieldsForUsernameAuth, + userSignupFieldsForExternalAuth, + isAuthMethodExternal, + AuthMethod (..), + UsernameAndPasswordConfig (..), + ExternalAuthConfig (..), + EmailAuthConfig (..), + ) +where + +import Data.Data (Data) +import Language.Haskell.TH +import Language.Haskell.TH.Syntax (VarBangType) +import Wasp.AppSpec.App.Auth.EmailVerification (EmailVerificationConfig) +import Wasp.AppSpec.App.Auth.PasswordReset (PasswordResetConfig) +import Wasp.AppSpec.App.EmailSender (EmailFromField) +import Wasp.AppSpec.ExtImport (ExtImport) +import Wasp.Util (toLowerFirst) + +data AuthMethod = UsernameAndPassword | Email | Google | Keycloak | GitHub deriving (Show, Enum, Bounded) + +data UsernameAndPasswordConfig = UsernameAndPasswordConfig + { userSignupFields :: Maybe ExtImport + } + deriving (Show, Eq, Data) + +data ExternalAuthConfig = ExternalAuthConfig + { configFn :: Maybe ExtImport, + userSignupFields :: Maybe ExtImport + } + deriving (Show, Eq, Data) + +data EmailAuthConfig = EmailAuthConfig + { userSignupFields :: Maybe ExtImport, + fromField :: EmailFromField, + emailVerification :: EmailVerificationConfig, + passwordReset :: PasswordResetConfig + } + deriving (Show, Eq, Data) + +configType :: AuthMethod -> Name +configType UsernameAndPassword = ''UsernameAndPasswordConfig +configType Email = ''EmailAuthConfig +configType Google = ''ExternalAuthConfig +configType Keycloak = ''ExternalAuthConfig +configType GitHub = ''ExternalAuthConfig + +-- Generate the AuthMethods data type +-- data AuthMethods = AuthMethods +-- { usernameAndPassword :: Maybe UsernameAndPasswordConfig, +-- google :: Maybe ExternalAuthConfig, +-- gitHub :: Maybe ExternalAuthConfig, +-- keycloak :: Maybe ExternalAuthConfig, +-- email :: Maybe EmailAuthConfig +-- ... +-- } deriving (Show, Eq, Data) +generateAuthMethods :: Q [Dec] +generateAuthMethods = do + let authMethodsName = mkName "AuthMethods" + let authMethodsCtorName = mkName "AuthMethods" + let fields = generateField <$> [UsernameAndPassword .. GitHub] + -- data AuthMethods + let authMethods = + dataD + (cxt []) + authMethodsName + [] + Nothing + [recC authMethodsCtorName fields] + [derivClause Nothing [[t|Show|], [t|Eq|], [t|Data|]]] + sequence [authMethods] + where + -- usernameAndPassword :: Maybe UsernameAndPasswordConfig + generateField :: AuthMethod -> Q VarBangType + generateField authMethod = do + let fieldName = mkName (toLowerFirst (show authMethod)) + let fieldConfigType = configType authMethod + let fieldType = appT (conT ''Maybe) (conT fieldConfigType) + let fieldStrictness = bang noSourceUnpackedness noSourceStrictness + varBangType fieldName $ bangType fieldStrictness fieldType + +-- These helper functions are used to avoid ambiguity when using the +-- `userSignupFields` function (otherwise we need to use the DuplicateRecordFields +-- extension in each module that uses them). +userSignupFieldsForEmailAuth :: EmailAuthConfig -> Maybe ExtImport +userSignupFieldsForEmailAuth = userSignupFields + +userSignupFieldsForUsernameAuth :: UsernameAndPasswordConfig -> Maybe ExtImport +userSignupFieldsForUsernameAuth = userSignupFields + +userSignupFieldsForExternalAuth :: ExternalAuthConfig -> Maybe ExtImport +userSignupFieldsForExternalAuth = userSignupFields + +isAuthMethodExternal :: AuthMethod -> Bool +isAuthMethodExternal Google = True +isAuthMethodExternal Keycloak = True +isAuthMethodExternal GitHub = True +isAuthMethodExternal _ = False diff --git a/waspc/src/Wasp/AppSpec/App/Auth/IsEnabled.hs b/waspc/src/Wasp/AppSpec/App/Auth/IsEnabled.hs new file mode 100644 index 0000000000..cb3b58baf5 --- /dev/null +++ b/waspc/src/Wasp/AppSpec/App/Auth/IsEnabled.hs @@ -0,0 +1,12 @@ +module Wasp.AppSpec.App.Auth.IsEnabled where + +import Language.Haskell.TH +import Wasp.AppSpec.App.Auth (Auth (..), AuthMethods (..), generateIsAuthMethodEnabled) +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod(..), isAuthMethodExternal) + +$(generateIsAuthMethodEnabled) + +isExternalAuthEnabled :: Auth -> Bool +isExternalAuthEnabled auth = any check [minBound .. maxBound :: AuthMethod] + where + check method = isAuthMethodExternal method && isAuthMethodEnabled method auth \ No newline at end of file diff --git a/waspc/src/Wasp/AppSpec/Valid.hs b/waspc/src/Wasp/AppSpec/Valid.hs index 67d549121b..8832d17ff9 100644 --- a/waspc/src/Wasp/AppSpec/Valid.hs +++ b/waspc/src/Wasp/AppSpec/Valid.hs @@ -26,6 +26,8 @@ import Wasp.AppSpec.App (App) import qualified Wasp.AppSpec.App as AS.App import qualified Wasp.AppSpec.App as App import qualified Wasp.AppSpec.App.Auth as Auth +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (Email, UsernameAndPassword)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as Auth.IsEnabled import qualified Wasp.AppSpec.App.Client as Client import qualified Wasp.AppSpec.App.Db as AS.Db import qualified Wasp.AppSpec.App.EmailSender as AS.EmailSender @@ -169,7 +171,7 @@ validateOnlyEmailOrUsernameAndPasswordAuthIsUsed spec = | areBothAuthMethodsUsed ] where - areBothAuthMethodsUsed = Auth.isEmailAuthEnabled auth && Auth.isUsernameAndPasswordAuthEnabled auth + areBothAuthMethodsUsed = Auth.IsEnabled.isAuthMethodEnabled Email auth && Auth.IsEnabled.isAuthMethodEnabled UsernameAndPassword auth validateDbIsPostgresIfPgBossUsed :: AppSpec -> [ValidationError] validateDbIsPostgresIfPgBossUsed spec = @@ -182,7 +184,7 @@ validateEmailSenderIsDefinedIfEmailAuthIsUsed :: AppSpec -> [ValidationError] validateEmailSenderIsDefinedIfEmailAuthIsUsed spec = case App.auth app of Nothing -> [] Just auth -> - if Auth.isEmailAuthEnabled auth && isNothing (App.emailSender app) + if Auth.IsEnabled.isAuthMethodEnabled Email auth && isNothing (App.emailSender app) then [GenericValidationError "app.emailSender must be specified when using email auth. You can use the Dummy email sender for development purposes."] else [] where diff --git a/waspc/src/Wasp/Generator/AuthProviders.hs b/waspc/src/Wasp/Generator/AuthProviders.hs index 40b6fd18c5..3338ae93bd 100644 --- a/waspc/src/Wasp/Generator/AuthProviders.hs +++ b/waspc/src/Wasp/Generator/AuthProviders.hs @@ -1,6 +1,13 @@ module Wasp.Generator.AuthProviders where +import Data.Aeson (KeyValue ((.=)), object) +import qualified Data.Aeson as Aeson import Data.Maybe (fromJust) +import Data.Text (Text) +import qualified Data.Text as Text +import qualified Wasp.AppSpec.App.Auth as AS.Auth +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (..)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import Wasp.Generator.AuthProviders.Common (makeProviderId) import qualified Wasp.Generator.AuthProviders.Email as E import qualified Wasp.Generator.AuthProviders.Local as L @@ -43,3 +50,11 @@ emailAuthProvider = { E._providerId = fromJust $ makeProviderId "email", E._displayName = "Email and password" } + +getAuthProvidersJson :: AS.Auth.Auth -> Aeson.Value +getAuthProvidersJson auth = object $ (\(key, fn) -> key .= fn auth) . mapAuthMethodToPair <$> listOfAllAuthMethods + where + listOfAllAuthMethods = [minBound .. maxBound] :: [AuthMethod] + + mapAuthMethodToPair :: AuthMethod -> (Text, AS.Auth.Auth -> Bool) + mapAuthMethodToPair method = (Text.pack $ "is" ++ show method ++ "AuthEnabled", AS.Auth.IsEnabled.isAuthMethodEnabled method) diff --git a/waspc/src/Wasp/Generator/SdkGenerator/Auth/AuthFormsG.hs b/waspc/src/Wasp/Generator/SdkGenerator/Auth/AuthFormsG.hs index 0e0f731849..ae0a9a6f3f 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator/Auth/AuthFormsG.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator/Auth/AuthFormsG.hs @@ -6,16 +6,20 @@ where import Data.Aeson (object, (.=)) import StrongPath (reldir, relfile, ()) import qualified Wasp.AppSpec.App.Auth as AS.Auth +-- todo(filip) -- Should I put this under something like Wasp.Generator.Auth (doesn't exist) or Wasp.Generator.Common? + +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (Email, UsernameAndPassword)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import Wasp.Generator.AuthProviders ( gitHubAuthProvider, googleAuthProvider, keycloakAuthProvider, ) +import qualified Wasp.Generator.AuthProviders as AuthProviders import qualified Wasp.Generator.AuthProviders.OAuth as OAuth import Wasp.Generator.FileDraft (FileDraft) import Wasp.Generator.Monad (Generator) import Wasp.Generator.SdkGenerator.Common as C --- todo(filip) -- Should I put this under something like Wasp.Generator.Auth (doesn't exist) or Wasp.Generator.Common? import Wasp.Generator.WebAppGenerator.Auth.Common (getOnAuthSucceededRedirectToOrDefault) import Wasp.Util ((<++>)) @@ -41,7 +45,7 @@ genAuthComponent auth = [relfile|auth/forms/Auth.tsx|] tmplData where - tmplData = object ["isEmailAuthEnabled" .= AS.Auth.isEmailAuthEnabled auth] + tmplData = object ["isEmailAuthEnabled" .= AS.Auth.IsEnabled.isAuthMethodEnabled Email auth] genTypes :: AS.Auth.Auth -> Generator FileDraft genTypes auth = @@ -50,7 +54,7 @@ genTypes auth = [relfile|auth/forms/types.ts|] tmplData where - tmplData = object ["isEmailAuthEnabled" .= AS.Auth.isEmailAuthEnabled auth] + tmplData = object ["isEmailAuthEnabled" .= AS.Auth.IsEnabled.isAuthMethodEnabled Email auth] genEmailForms :: AS.Auth.Auth -> Generator [FileDraft] genEmailForms auth = @@ -62,7 +66,7 @@ genEmailForms auth = ] where genFileCopy = return . C.mkTmplFd - isEmailAuthEnabled = AS.Auth.isEmailAuthEnabled auth + isEmailAuthEnabled = AS.Auth.IsEnabled.isAuthMethodEnabled Email auth genInternalAuthComponents :: AS.Auth.Auth -> Generator [FileDraft] genInternalAuthComponents auth = @@ -95,9 +99,9 @@ genInternalAuthComponents auth = copyInternalAuthComponent [relfile|social/SocialIcons.tsx|] ] - isExternalAuthEnabled = AS.Auth.isExternalAuthEnabled auth - isUsernameAndPasswordAuthEnabled = AS.Auth.isUsernameAndPasswordAuthEnabled auth - isEmailAuthEnabled = AS.Auth.isEmailAuthEnabled auth + isExternalAuthEnabled = AS.Auth.IsEnabled.isExternalAuthEnabled auth + isUsernameAndPasswordAuthEnabled = AS.Auth.IsEnabled.isAuthMethodEnabled UsernameAndPassword auth + isEmailAuthEnabled = AS.Auth.IsEnabled.isAuthMethodEnabled Email auth copyInternalAuthComponent = return . C.mkTmplFd . (pathToInternalInAuth ) pathToInternalInAuth = [reldir|auth/forms/internal|] @@ -114,23 +118,14 @@ genLoginSignupForm auth = [ "onAuthSucceededRedirectTo" .= getOnAuthSucceededRedirectToOrDefault auth, "areBothSocialAndPasswordBasedAuthEnabled" .= areBothSocialAndPasswordBasedAuthEnabled, "isAnyPasswordBasedAuthEnabled" .= isAnyPasswordBasedAuthEnabled, - "isSocialAuthEnabled" .= AS.Auth.isExternalAuthEnabled auth, - -- Google - "isGoogleAuthEnabled" .= AS.Auth.isGoogleAuthEnabled auth, + "isSocialAuthEnabled" .= AS.Auth.IsEnabled.isExternalAuthEnabled auth, + "providers" .= AuthProviders.getAuthProvidersJson auth, "googleSignInPath" .= OAuth.serverLoginUrl googleAuthProvider, - -- Keycloak - "isKeycloakAuthEnabled" .= AS.Auth.isKeycloakAuthEnabled auth, "keycloakSignInPath" .= OAuth.serverLoginUrl keycloakAuthProvider, - -- GitHub - "isGitHubAuthEnabled" .= AS.Auth.isGitHubAuthEnabled auth, - "gitHubSignInPath" .= OAuth.serverLoginUrl gitHubAuthProvider, - -- Username and password - "isUsernameAndPasswordAuthEnabled" .= AS.Auth.isUsernameAndPasswordAuthEnabled auth, - -- Email - "isEmailAuthEnabled" .= AS.Auth.isEmailAuthEnabled auth + "gitHubSignInPath" .= OAuth.serverLoginUrl gitHubAuthProvider ] - areBothSocialAndPasswordBasedAuthEnabled = AS.Auth.isExternalAuthEnabled auth && isAnyPasswordBasedAuthEnabled - isAnyPasswordBasedAuthEnabled = AS.Auth.isUsernameAndPasswordAuthEnabled auth || AS.Auth.isEmailAuthEnabled auth + areBothSocialAndPasswordBasedAuthEnabled = AS.Auth.IsEnabled.isExternalAuthEnabled auth && isAnyPasswordBasedAuthEnabled + isAnyPasswordBasedAuthEnabled = AS.Auth.IsEnabled.isAuthMethodEnabled UsernameAndPassword auth || AS.Auth.IsEnabled.isAuthMethodEnabled Email auth genConditionally :: Bool -> Generator [FileDraft] -> Generator [FileDraft] genConditionally isEnabled gen = if isEnabled then gen else return [] diff --git a/waspc/src/Wasp/Generator/SdkGenerator/Auth/EmailAuthG.hs b/waspc/src/Wasp/Generator/SdkGenerator/Auth/EmailAuthG.hs index 70c09a1e3f..3e8d10619a 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator/Auth/EmailAuthG.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator/Auth/EmailAuthG.hs @@ -7,6 +7,8 @@ import Data.Aeson (object, (.=)) import StrongPath (relfile) import qualified Wasp.AppSpec as AS import qualified Wasp.AppSpec.App.Auth as AS.Auth +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (Email)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import Wasp.Generator.AuthProviders (emailAuthProvider) import Wasp.Generator.AuthProviders.Email ( serverLoginUrl, @@ -24,7 +26,7 @@ import qualified Wasp.Util as Util genEmailAuth :: AS.Auth.Auth -> Generator [FileDraft] genEmailAuth auth - | AS.Auth.isEmailAuthEnabled auth = + | AS.Auth.IsEnabled.isAuthMethodEnabled Email auth = sequence [ genIndex, genServerUtils auth diff --git a/waspc/src/Wasp/Generator/SdkGenerator/Auth/LocalAuthG.hs b/waspc/src/Wasp/Generator/SdkGenerator/Auth/LocalAuthG.hs index 5ca5f1c4a9..3efb91413d 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator/Auth/LocalAuthG.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator/Auth/LocalAuthG.hs @@ -7,6 +7,8 @@ import Data.Aeson (object, (.=)) import StrongPath (relfile) import qualified StrongPath as SP import qualified Wasp.AppSpec.App.Auth as AS.Auth +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (UsernameAndPassword)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import Wasp.Generator.AuthProviders (localAuthProvider) import Wasp.Generator.AuthProviders.Local (serverLoginUrl, serverSignupUrl) import Wasp.Generator.FileDraft (FileDraft) @@ -18,7 +20,7 @@ genLocalAuth = genActions genActions :: AS.Auth.Auth -> Generator [FileDraft] genActions auth - | AS.Auth.isUsernameAndPasswordAuthEnabled auth = + | AS.Auth.IsEnabled.isAuthMethodEnabled UsernameAndPassword auth = sequence [ genLocalLoginAction, genLocalSignupAction diff --git a/waspc/src/Wasp/Generator/SdkGenerator/Auth/OAuthAuthG.hs b/waspc/src/Wasp/Generator/SdkGenerator/Auth/OAuthAuthG.hs index c09c31517a..a0aa570eba 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator/Auth/OAuthAuthG.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator/Auth/OAuthAuthG.hs @@ -7,6 +7,8 @@ import Data.Aeson (object, (.=)) import StrongPath (File', Path', Rel', reldir, relfile) import qualified StrongPath as SP import qualified Wasp.AppSpec.App.Auth as AS.Auth +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (GitHub, Google, Keycloak)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import Wasp.Generator.AuthProviders ( gitHubAuthProvider, googleAuthProvider, @@ -20,7 +22,7 @@ import Wasp.Generator.SdkGenerator.Common as C genOAuthAuth :: AS.Auth.Auth -> Generator [FileDraft] genOAuthAuth auth - | AS.Auth.isExternalAuthEnabled auth = + | AS.Auth.IsEnabled.isExternalAuthEnabled auth = genHelpers auth | otherwise = return [] @@ -28,9 +30,9 @@ genHelpers :: AS.Auth.Auth -> Generator [FileDraft] genHelpers auth = return $ concat - [ [gitHubHelpers | AS.Auth.isGitHubAuthEnabled auth], - [googleHelpers | AS.Auth.isGoogleAuthEnabled auth], - [keycloakHelpers | AS.Auth.isKeycloakAuthEnabled auth] + [ [gitHubHelpers | AS.Auth.IsEnabled.isAuthMethodEnabled GitHub auth], + [googleHelpers | AS.Auth.IsEnabled.isAuthMethodEnabled Google auth], + [keycloakHelpers | AS.Auth.IsEnabled.isAuthMethodEnabled Keycloak auth] ] where gitHubHelpers = mkHelpersFd gitHubAuthProvider [relfile|GitHub.tsx|] diff --git a/waspc/src/Wasp/Generator/SdkGenerator/AuthG.hs b/waspc/src/Wasp/Generator/SdkGenerator/AuthG.hs index fa2dbc4c8c..7c9893ef84 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator/AuthG.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator/AuthG.hs @@ -9,6 +9,8 @@ import Wasp.AppSpec (AppSpec) import qualified Wasp.AppSpec as AS import qualified Wasp.AppSpec.App as AS.App import qualified Wasp.AppSpec.App.Auth as AS.Auth +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (Email, UsernameAndPassword)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import Wasp.AppSpec.Valid (getApp) import Wasp.Generator.Common (makeJsArrayFromHaskellList) import qualified Wasp.Generator.DbGenerator.Auth as DbAuth @@ -122,8 +124,8 @@ genIndexTs auth = [ "isEmailAuthEnabled" .= isEmailAuthEnabled, "isLocalAuthEnabled" .= isLocalAuthEnabled ] - isEmailAuthEnabled = AS.Auth.isEmailAuthEnabled auth - isLocalAuthEnabled = AS.Auth.isUsernameAndPasswordAuthEnabled auth + isEmailAuthEnabled = AS.Auth.IsEnabled.isAuthMethodEnabled Email auth + isLocalAuthEnabled = AS.Auth.IsEnabled.isAuthMethodEnabled UsernameAndPassword auth genProvidersTypes :: AS.Auth.Auth -> Generator FileDraft genProvidersTypes auth = return $ C.mkTmplFdWithData [relfile|auth/providers/types.ts|] tmplData diff --git a/waspc/src/Wasp/Generator/SdkGenerator/Client/AuthG.hs b/waspc/src/Wasp/Generator/SdkGenerator/Client/AuthG.hs index 9b2fd9b7f6..66323ce3e0 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator/Client/AuthG.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator/Client/AuthG.hs @@ -3,13 +3,14 @@ module Wasp.Generator.SdkGenerator.Client.AuthG ) where -import Data.Aeson (object, (.=)) -import qualified Data.Aeson as Aeson import StrongPath (File', Path', Rel, relfile) import Wasp.AppSpec (AppSpec) import qualified Wasp.AppSpec.App as AS.App import qualified Wasp.AppSpec.App.Auth as AS.Auth +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (..)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import Wasp.AppSpec.Valid (getApp) +import qualified Wasp.Generator.AuthProviders as AuthProviders import Wasp.Generator.FileDraft (FileDraft) import Wasp.Generator.Monad (Generator) import Wasp.Generator.SdkGenerator.Common (SdkTemplatesDir) @@ -25,11 +26,7 @@ genNewClientAuth spec = [ genAuthIndex auth, genAuthUI auth ] - <++> genAuthEmail auth - <++> genAuthUsername auth - <++> genAuthGoogle auth - <++> genAuthKeycloak auth - <++> genAuthGitHub auth + <++> genAuthHelpers auth where maybeAuth = AS.App.auth $ snd $ getApp spec @@ -40,7 +37,7 @@ genAuthIndex auth = [relfile|client/auth/index.ts|] tmplData where - tmplData = getAuthProvidersJson auth + tmplData = AuthProviders.getAuthProvidersJson auth genAuthUI :: AS.Auth.Auth -> Generator FileDraft genAuthUI auth = @@ -49,47 +46,23 @@ genAuthUI auth = [relfile|client/auth/ui.ts|] tmplData where - tmplData = getAuthProvidersJson auth + tmplData = AuthProviders.getAuthProvidersJson auth -genAuthEmail :: AS.Auth.Auth -> Generator [FileDraft] -genAuthEmail auth = - if AS.Auth.isEmailAuthEnabled auth - then sequence [genFileCopy [relfile|client/auth/email.ts|]] - else return [] - -genAuthUsername :: AS.Auth.Auth -> Generator [FileDraft] -genAuthUsername auth = - if AS.Auth.isUsernameAndPasswordAuthEnabled auth - then sequence [genFileCopy [relfile|client/auth/username.ts|]] - else return [] - -genAuthGoogle :: AS.Auth.Auth -> Generator [FileDraft] -genAuthGoogle auth = - if AS.Auth.isGoogleAuthEnabled auth - then sequence [genFileCopy [relfile|client/auth/google.ts|]] - else return [] - -genAuthKeycloak :: AS.Auth.Auth -> Generator [FileDraft] -genAuthKeycloak auth = - if AS.Auth.isKeycloakAuthEnabled auth - then sequence [genFileCopy [relfile|client/auth/keycloak.ts|]] - else return [] - -genAuthGitHub :: AS.Auth.Auth -> Generator [FileDraft] -genAuthGitHub auth = - if AS.Auth.isGitHubAuthEnabled auth - then sequence [genFileCopy [relfile|client/auth/github.ts|]] - else return [] +genAuthHelpers :: AS.Auth.Auth -> Generator [FileDraft] +genAuthHelpers auth = return $ concatMap genAuthHelper [minBound .. maxBound :: AuthMethod] + where + genAuthHelper :: AuthMethod -> [FileDraft] + genAuthHelper authMethod = + if AS.Auth.IsEnabled.isAuthMethodEnabled authMethod auth + then [genHelperForAuthMethod authMethod] + else [] -getAuthProvidersJson :: AS.Auth.Auth -> Aeson.Value -getAuthProvidersJson auth = - object - [ "isGoogleAuthEnabled" .= AS.Auth.isGoogleAuthEnabled auth, - "isKeycloakAuthEnabled" .= AS.Auth.isKeycloakAuthEnabled auth, - "isGitHubAuthEnabled" .= AS.Auth.isGitHubAuthEnabled auth, - "isUsernameAndPasswordAuthEnabled" .= AS.Auth.isUsernameAndPasswordAuthEnabled auth, - "isEmailAuthEnabled" .= AS.Auth.isEmailAuthEnabled auth - ] +genHelperForAuthMethod :: AuthMethod -> FileDraft +genHelperForAuthMethod Google = genFileCopy [relfile|client/auth/google.ts|] +genHelperForAuthMethod Keycloak = genFileCopy [relfile|client/auth/keycloak.ts|] +genHelperForAuthMethod GitHub = genFileCopy [relfile|client/auth/github.ts|] +genHelperForAuthMethod Email = genFileCopy [relfile|client/auth/email.ts|] +genHelperForAuthMethod UsernameAndPassword = genFileCopy [relfile|client/auth/username.ts|] -genFileCopy :: Path' (Rel SdkTemplatesDir) File' -> Generator FileDraft -genFileCopy = return . C.mkTmplFd +genFileCopy :: Path' (Rel SdkTemplatesDir) File' -> FileDraft +genFileCopy = C.mkTmplFd diff --git a/waspc/src/Wasp/Generator/SdkGenerator/Server/AuthG.hs b/waspc/src/Wasp/Generator/SdkGenerator/Server/AuthG.hs index 8e27196139..762a938079 100644 --- a/waspc/src/Wasp/Generator/SdkGenerator/Server/AuthG.hs +++ b/waspc/src/Wasp/Generator/SdkGenerator/Server/AuthG.hs @@ -3,13 +3,14 @@ module Wasp.Generator.SdkGenerator.Server.AuthG ) where -import Data.Aeson (object, (.=)) -import qualified Data.Aeson as Aeson import StrongPath (File', Path', Rel, relfile) import Wasp.AppSpec (AppSpec) import qualified Wasp.AppSpec.App as AS.App import qualified Wasp.AppSpec.App.Auth as AS.Auth +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (Email, UsernameAndPassword)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import Wasp.AppSpec.Valid (getApp) +import qualified Wasp.Generator.AuthProviders as AuthProviders import Wasp.Generator.FileDraft (FileDraft) import Wasp.Generator.Monad (Generator) import Wasp.Generator.SdkGenerator.Common (SdkTemplatesDir) @@ -36,29 +37,19 @@ genAuthIndex auth = [relfile|server/auth/index.ts|] tmplData where - tmplData = getAuthProvidersJson auth + tmplData = AuthProviders.getAuthProvidersJson auth genAuthEmail :: AS.Auth.Auth -> Generator [FileDraft] genAuthEmail auth = - if AS.Auth.isEmailAuthEnabled auth + if AS.Auth.IsEnabled.isAuthMethodEnabled Email auth then sequence [genFileCopy [relfile|server/auth/email/index.ts|]] else return [] genAuthUsername :: AS.Auth.Auth -> Generator [FileDraft] genAuthUsername auth = - if AS.Auth.isUsernameAndPasswordAuthEnabled auth + if AS.Auth.IsEnabled.isAuthMethodEnabled UsernameAndPassword auth then sequence [genFileCopy [relfile|server/auth/username.ts|]] else return [] -getAuthProvidersJson :: AS.Auth.Auth -> Aeson.Value -getAuthProvidersJson auth = - object - [ "isGoogleAuthEnabled" .= AS.Auth.isGoogleAuthEnabled auth, - "isKeycloakAuthEnabled" .= AS.Auth.isKeycloakAuthEnabled auth, - "isGitHubAuthEnabled" .= AS.Auth.isGitHubAuthEnabled auth, - "isUsernameAndPasswordAuthEnabled" .= AS.Auth.isUsernameAndPasswordAuthEnabled auth, - "isEmailAuthEnabled" .= AS.Auth.isEmailAuthEnabled auth - ] - genFileCopy :: Path' (Rel SdkTemplatesDir) File' -> Generator FileDraft genFileCopy = return . C.mkTmplFd diff --git a/waspc/src/Wasp/Generator/ServerGenerator/Auth/EmailAuthG.hs b/waspc/src/Wasp/Generator/ServerGenerator/Auth/EmailAuthG.hs index da078de103..7ab9855d75 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator/Auth/EmailAuthG.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator/Auth/EmailAuthG.hs @@ -19,6 +19,7 @@ import StrongPath import qualified StrongPath as SP import qualified Wasp.AppSpec as AS import qualified Wasp.AppSpec.App.Auth as AS.Auth +import qualified Wasp.AppSpec.App.Auth.AuthMethods as AS.AuthMethods import qualified Wasp.AppSpec.App.Auth.EmailVerification as AS.Auth.EmailVerification import qualified Wasp.AppSpec.App.Auth.PasswordReset as AS.Auth.PasswordReset import qualified Wasp.AppSpec.App.EmailSender as AS.EmailSender @@ -42,7 +43,7 @@ genEmailAuth spec auth = case emailAuth of where emailAuth = AS.Auth.email $ AS.Auth.methods auth -genEmailAuthConfig :: AS.AppSpec -> AS.Auth.EmailAuthConfig -> Generator FileDraft +genEmailAuthConfig :: AS.AppSpec -> AS.AuthMethods.EmailAuthConfig -> Generator FileDraft genEmailAuthConfig spec emailAuthConfig = return $ C.mkTmplFdWithDstAndData tmplFile dstFile (Just tmplData) where tmplFile = C.srcDirInServerTemplatesDir SP.castRel authIndexFileInSrcDir @@ -67,7 +68,7 @@ genEmailAuthConfig spec emailAuthConfig = return $ C.mkTmplFdWithDstAndData tmpl "email" .= email ] - fromField = AS.Auth.fromField emailAuthConfig + fromField = AS.AuthMethods.fromField emailAuthConfig maybeName = AS.EmailSender.name fromField email = AS.EmailSender.email fromField @@ -77,10 +78,10 @@ genEmailAuthConfig spec emailAuthConfig = return $ C.mkTmplFdWithDstAndData tmpl passwordResetClientRoute = getRoutePathFromRef spec $ AS.Auth.PasswordReset.clientRoute passwordReset getPasswordResetEmailContent = extImportToImportJson relPathToServerSrcDir $ AS.Auth.PasswordReset.getEmailContentFn passwordReset getVerificationEmailContent = extImportToImportJson relPathToServerSrcDir $ AS.Auth.EmailVerification.getEmailContentFn emailVerification - maybeUserSignupFields = AS.Auth.userSignupFieldsForEmailAuth emailAuthConfig + maybeUserSignupFields = AS.AuthMethods.userSignupFieldsForEmailAuth emailAuthConfig - emailVerification = AS.Auth.emailVerification emailAuthConfig - passwordReset = AS.Auth.passwordReset emailAuthConfig + emailVerification = AS.AuthMethods.emailVerification emailAuthConfig + passwordReset = AS.AuthMethods.passwordReset emailAuthConfig relPathToServerSrcDir :: Path Posix (Rel importLocation) (Dir C.ServerSrcDir) relPathToServerSrcDir = [reldirP|../../../|] diff --git a/waspc/src/Wasp/Generator/ServerGenerator/Auth/LocalAuthG.hs b/waspc/src/Wasp/Generator/ServerGenerator/Auth/LocalAuthG.hs index 4209e81cfa..d67b21308b 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator/Auth/LocalAuthG.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator/Auth/LocalAuthG.hs @@ -19,6 +19,7 @@ import StrongPath import qualified StrongPath as SP import qualified Wasp.AppSpec as AS import qualified Wasp.AppSpec.App.Auth as AS.Auth +import qualified Wasp.AppSpec.App.Auth.AuthMethods as AS.AuthMethods import Wasp.Generator.AuthProviders (localAuthProvider) import qualified Wasp.Generator.AuthProviders.Local as Local import Wasp.Generator.FileDraft (FileDraft) @@ -39,7 +40,7 @@ genLocalAuth auth = case usernameAndPasswordAuth of where usernameAndPasswordAuth = AS.Auth.usernameAndPassword $ AS.Auth.methods auth -genLocalAuthConfig :: AS.Auth.UsernameAndPasswordConfig -> Generator FileDraft +genLocalAuthConfig :: AS.AuthMethods.UsernameAndPasswordConfig -> Generator FileDraft genLocalAuthConfig usernameAndPasswordConfig = return $ C.mkTmplFdWithDstAndData tmplFile dstFile (Just tmplData) where tmplFile = C.srcDirInServerTemplatesDir SP.castRel authIndexFileInSrcDir @@ -52,7 +53,7 @@ genLocalAuthConfig usernameAndPasswordConfig = return $ C.mkTmplFdWithDstAndData "userSignupFields" .= extImportToImportJson relPathToServerSrcDir maybeUserSignupFields ] - maybeUserSignupFields = AS.Auth.userSignupFieldsForUsernameAuth usernameAndPasswordConfig + maybeUserSignupFields = AS.AuthMethods.userSignupFieldsForUsernameAuth usernameAndPasswordConfig authIndexFileInSrcDir :: Path' (Rel C.ServerSrcDir) File' authIndexFileInSrcDir = [relfile|auth/providers/config/username.ts|] diff --git a/waspc/src/Wasp/Generator/ServerGenerator/Auth/OAuthAuthG.hs b/waspc/src/Wasp/Generator/ServerGenerator/Auth/OAuthAuthG.hs index 127ddb2007..b4519cbc01 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator/Auth/OAuthAuthG.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator/Auth/OAuthAuthG.hs @@ -24,6 +24,9 @@ import qualified Wasp.AppSpec as AS import qualified Wasp.AppSpec.App as AS.App import qualified Wasp.AppSpec.App.Auth as AS.App.Auth import qualified Wasp.AppSpec.App.Auth as AS.Auth +import qualified Wasp.AppSpec.App.Auth.AuthMethods as AS.AuthMethods +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.App.Auth.IsEnabled +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import qualified Wasp.AppSpec.App.Dependency as App.Dependency import Wasp.AppSpec.Valid (getApp) import Wasp.Generator.AuthProviders @@ -50,7 +53,7 @@ import qualified Wasp.Util as Util genOAuthAuth :: AS.Auth.Auth -> Generator [FileDraft] genOAuthAuth auth - | AS.Auth.isExternalAuthEnabled auth = + | AS.Auth.IsEnabled.isExternalAuthEnabled auth = genOAuthHelpers auth <++> genOAuthProvider googleAuthProvider (AS.Auth.google . AS.Auth.methods $ auth) <++> genOAuthProvider keycloakAuthProvider (AS.Auth.keycloak . AS.Auth.methods $ auth) @@ -104,7 +107,7 @@ genTypes auth = return $ C.mkTmplFdWithData tmplFile (Just tmplData) genOAuthProvider :: OAuthAuthProvider -> - Maybe AS.Auth.ExternalAuthConfig -> + Maybe AS.AuthMethods.ExternalAuthConfig -> Generator [FileDraft] genOAuthProvider provider maybeUserConfig | isJust maybeUserConfig = @@ -123,7 +126,7 @@ genOAuthProvider provider maybeUserConfig -- It's all in one config file. genOAuthConfig :: OAuthAuthProvider -> - Maybe AS.Auth.ExternalAuthConfig -> + Maybe AS.AuthMethods.ExternalAuthConfig -> Path' (Rel ServerTemplatesSrcDir) File' -> Generator FileDraft genOAuthConfig provider maybeUserConfig pathToConfigTmpl = return $ C.mkTmplFdWithData tmplFile (Just tmplData) @@ -137,14 +140,14 @@ genOAuthConfig provider maybeUserConfig pathToConfigTmpl = return $ C.mkTmplFdWi "configFn" .= extImportToImportJson relPathFromAuthConfigToServerSrcDir maybeConfigFn, "userSignupFields" .= extImportToImportJson relPathFromAuthConfigToServerSrcDir maybeUserSignupFields ] - maybeConfigFn = AS.Auth.configFn =<< maybeUserConfig - maybeUserSignupFields = AS.Auth.userSignupFieldsForExternalAuth =<< maybeUserConfig + maybeConfigFn = AS.AuthMethods.configFn =<< maybeUserConfig + maybeUserSignupFields = AS.AuthMethods.userSignupFieldsForExternalAuth =<< maybeUserConfig relPathFromAuthConfigToServerSrcDir :: Path Posix (Rel importLocation) (Dir C.ServerSrcDir) relPathFromAuthConfigToServerSrcDir = [reldirP|../../../|] depsRequiredByOAuth :: AppSpec -> [App.Dependency.Dependency] depsRequiredByOAuth spec = - [App.Dependency.make ("arctic", "^1.2.1") | (AS.App.Auth.isExternalAuthEnabled <$> maybeAuth) == Just True] + [App.Dependency.make ("arctic", "^1.2.1") | (AS.App.Auth.IsEnabled.isExternalAuthEnabled <$> maybeAuth) == Just True] where maybeAuth = AS.App.auth $ snd $ getApp spec diff --git a/waspc/src/Wasp/Generator/ServerGenerator/AuthG.hs b/waspc/src/Wasp/Generator/ServerGenerator/AuthG.hs index 2b1e686a72..e17aaef2ef 100644 --- a/waspc/src/Wasp/Generator/ServerGenerator/AuthG.hs +++ b/waspc/src/Wasp/Generator/ServerGenerator/AuthG.hs @@ -4,8 +4,9 @@ module Wasp.Generator.ServerGenerator.AuthG ) where -import Data.Aeson (object, (.=)) +import Data.Aeson (Value (String), object, (.=)) import Data.Maybe (fromJust) +import GHC.Enum (Bounded (minBound)) import StrongPath ( File', Path', @@ -18,6 +19,8 @@ import qualified StrongPath as SP import Wasp.AppSpec (AppSpec) import qualified Wasp.AppSpec.App as AS.App import qualified Wasp.AppSpec.App.Auth as AS.Auth +import Wasp.AppSpec.App.Auth.AuthMethods (AuthMethod (Email, GitHub, Google, Keycloak, UsernameAndPassword)) +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import qualified Wasp.AppSpec.App.Dependency as AS.Dependency import Wasp.AppSpec.Valid (getApp) import Wasp.Generator.AuthProviders @@ -63,7 +66,7 @@ genAuthRoutesIndex auth = return $ C.mkTmplFdWithDstAndData tmplFile dstFile (Ju tmplFile = C.srcDirInServerTemplatesDir SP.castRel authIndexFileInSrcDir dstFile = C.serverSrcDirInServerRootDir authIndexFileInSrcDir tmplData = - object ["isExternalAuthEnabled" .= AS.Auth.isExternalAuthEnabled auth] + object ["isExternalAuthEnabled" .= AS.Auth.IsEnabled.isExternalAuthEnabled auth] authIndexFileInSrcDir :: Path' (Rel C.ServerSrcDir) File' authIndexFileInSrcDir = [relfile|routes/auth/index.js|] @@ -74,18 +77,20 @@ genProvidersIndex auth = return $ C.mkTmplFdWithData [relfile|src/auth/providers tmplData = object [ "providers" .= providers, - "isExternalAuthEnabled" .= AS.Auth.isExternalAuthEnabled auth + "isExternalAuthEnabled" .= AS.Auth.IsEnabled.isExternalAuthEnabled auth ] - providers = - makeConfigImportJson - <$> concat - [ [OAuthProvider.providerId gitHubAuthProvider | AS.Auth.isGitHubAuthEnabled auth], - [OAuthProvider.providerId googleAuthProvider | AS.Auth.isGoogleAuthEnabled auth], - [OAuthProvider.providerId keycloakAuthProvider | AS.Auth.isKeycloakAuthEnabled auth], - [LocalProvider.providerId localAuthProvider | AS.Auth.isUsernameAndPasswordAuthEnabled auth], - [EmailProvider.providerId emailAuthProvider | AS.Auth.isEmailAuthEnabled auth] - ] + providers = makeConfigImportJson <$> concatMap check [minBound .. maxBound :: AuthMethod] + + check :: AuthMethod -> [String] + check authMethod = [getProviderId authMethod | AS.Auth.IsEnabled.isAuthMethodEnabled authMethod auth] + + getProviderId :: AuthMethod -> String + getProviderId GitHub = OAuthProvider.providerId gitHubAuthProvider + getProviderId Google = OAuthProvider.providerId googleAuthProvider + getProviderId Keycloak = OAuthProvider.providerId keycloakAuthProvider + getProviderId UsernameAndPassword = LocalProvider.providerId localAuthProvider + getProviderId Email = EmailProvider.providerId emailAuthProvider makeConfigImportJson providerId = jsImportToImportJson $ diff --git a/waspc/src/Wasp/Generator/WebAppGenerator/AuthG.hs b/waspc/src/Wasp/Generator/WebAppGenerator/AuthG.hs index 916accbb42..d79a0cb604 100644 --- a/waspc/src/Wasp/Generator/WebAppGenerator/AuthG.hs +++ b/waspc/src/Wasp/Generator/WebAppGenerator/AuthG.hs @@ -8,6 +8,7 @@ import StrongPath (relfile) import Wasp.AppSpec (AppSpec) import qualified Wasp.AppSpec.App as AS.App import qualified Wasp.AppSpec.App.Auth as AS.Auth +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.Auth.IsEnabled import Wasp.AppSpec.Valid (getApp) import Wasp.Generator.AuthProviders.OAuth (serverExchangeCodeForTokenUrl) import Wasp.Generator.FileDraft (FileDraft) @@ -34,7 +35,7 @@ genCreateAuthRequiredPage auth = (object ["onAuthFailedRedirectTo" .= AS.Auth.onAuthFailedRedirectTo auth]) genOAuthAuth :: AS.Auth.Auth -> Generator [FileDraft] -genOAuthAuth auth = sequence [genOAuthCodeExchange auth | AS.Auth.isExternalAuthEnabled auth] +genOAuthAuth auth = sequence [genOAuthCodeExchange auth | AS.Auth.IsEnabled.isExternalAuthEnabled auth] genOAuthCodeExchange :: AS.Auth.Auth -> Generator FileDraft genOAuthCodeExchange auth = diff --git a/waspc/src/Wasp/Generator/WebAppGenerator/RouterGenerator.hs b/waspc/src/Wasp/Generator/WebAppGenerator/RouterGenerator.hs index 4e8ebec6e1..a34f939830 100644 --- a/waspc/src/Wasp/Generator/WebAppGenerator/RouterGenerator.hs +++ b/waspc/src/Wasp/Generator/WebAppGenerator/RouterGenerator.hs @@ -15,7 +15,7 @@ import StrongPath.Types (Posix) import Wasp.AppSpec (AppSpec) import qualified Wasp.AppSpec as AS import qualified Wasp.AppSpec.App as AS.App -import qualified Wasp.AppSpec.App.Auth as AS.App.Auth +import qualified Wasp.AppSpec.App.Auth.IsEnabled as AS.App.Auth.IsEnabled import qualified Wasp.AppSpec.App.Client as AS.App.Client import qualified Wasp.AppSpec.ExtImport as AS.ExtImport import qualified Wasp.AppSpec.Page as AS.Page @@ -97,7 +97,7 @@ createRouterTemplateData spec = { _routes = routes, _pagesToImport = pages, _isAuthEnabled = isAuthEnabled spec, - _isExternalAuthEnabled = (AS.App.Auth.isExternalAuthEnabled <$> maybeAuth) == Just True, + _isExternalAuthEnabled = (AS.App.Auth.IsEnabled.isExternalAuthEnabled <$> maybeAuth) == Just True, _rootComponent = extImportToImportJson relPathToWebAppSrcDir maybeRootComponent, _baseDir = SP.fromAbsDirP $ C.getBaseDir spec } diff --git a/waspc/waspc.cabal b/waspc/waspc.cabal index 004469c373..deddbc0768 100644 --- a/waspc/waspc.cabal +++ b/waspc/waspc.cabal @@ -224,6 +224,8 @@ library Wasp.AppSpec.Crud Wasp.AppSpec.App Wasp.AppSpec.App.Auth + Wasp.AppSpec.App.Auth.AuthMethods + Wasp.AppSpec.App.Auth.IsEnabled Wasp.AppSpec.App.Auth.PasswordReset Wasp.AppSpec.App.Auth.EmailVerification Wasp.AppSpec.App.Client