mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-24 01:22:24 +03:00
Merge branch 'master' into realworld
This commit is contained in:
commit
6a4469c370
@ -1,63 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
|
||||
import signUp from '@wasp/actions/signUp.js'
|
||||
import login from '@wasp/auth/login.js'
|
||||
|
||||
export default () => {
|
||||
const [method, setMethod] = useState('login')
|
||||
|
||||
const toggleMethod = () => {
|
||||
setMethod(method === 'login' ? 'signup' : 'login')
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<AuthForm method={method} />
|
||||
<a href='javascript:;' onClick={toggleMethod}>
|
||||
{method === 'login'
|
||||
? 'I don\'t have an account yet (go to sign up).'
|
||||
: 'I already have an account (go to log in).'}
|
||||
</a>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const AuthForm = (props) => {
|
||||
const history = useHistory()
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault()
|
||||
try {
|
||||
if (props.method === 'signup') {
|
||||
await signUp({ email, password })
|
||||
}
|
||||
await login(email, password)
|
||||
history.push('/')
|
||||
} catch (err) {
|
||||
window.alert('Error:' + err.message)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<h2>Email</h2>
|
||||
<input
|
||||
type='text'
|
||||
value={email}
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
/>
|
||||
<h2>Password</h2>
|
||||
<input
|
||||
type='password'
|
||||
value={password}
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
/>
|
||||
<div>
|
||||
<input type='submit' value={props.method === 'signup' ? 'Sign up' : 'Log in'} />
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
@ -14,7 +14,7 @@ const MainPage = () => {
|
||||
|
||||
const { data: user } = useAuth()
|
||||
if (!user) {
|
||||
return <span> Please <Link to='/auth'>log in</Link>. </span>
|
||||
return <span> Please <Link to='/login'>log in</Link>. </span>
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -12,11 +12,6 @@ page Main {
|
||||
component: import Main from "@ext/MainPage.js"
|
||||
}
|
||||
|
||||
route "/auth" -> page Auth
|
||||
page Auth {
|
||||
component: import Auth from "@ext/AuthPage.js"
|
||||
}
|
||||
|
||||
entity User {=psl
|
||||
id Int @id @default(autoincrement())
|
||||
email String @unique
|
||||
@ -54,4 +49,4 @@ action updateTask {
|
||||
|
||||
dependencies {=json
|
||||
"react-clock": "3.0.0"
|
||||
json=}
|
||||
json=}
|
||||
|
@ -19,4 +19,3 @@ const login = async (email, password) => {
|
||||
}
|
||||
|
||||
export default login
|
||||
|
||||
|
56
waspc/data/Generator/templates/react-app/src/auth/pages/Login.js
vendored
Normal file
56
waspc/data/Generator/templates/react-app/src/auth/pages/Login.js
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useHistory, Link } from 'react-router-dom'
|
||||
|
||||
import login from '../login.js'
|
||||
|
||||
const Login = (props) => {
|
||||
|
||||
const LoginForm = () => {
|
||||
const history = useHistory()
|
||||
|
||||
const [emailFieldVal, setEmailFieldVal] = useState('')
|
||||
const [passwordFieldVal, setPasswordFieldVal] = useState('')
|
||||
|
||||
const handleLogin = async (event) => {
|
||||
event.preventDefault()
|
||||
try {
|
||||
await login(emailFieldVal, passwordFieldVal)
|
||||
|
||||
history.push('/')
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
window.alert('Error:' + err.message)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<form onSubmit={handleLogin}>
|
||||
<h2>Email</h2>
|
||||
<input
|
||||
type="text"
|
||||
value={emailFieldVal}
|
||||
onChange={e => setEmailFieldVal(e.target.value)}
|
||||
/>
|
||||
<h2>Password</h2>
|
||||
<input
|
||||
type="password"
|
||||
value={passwordFieldVal}
|
||||
onChange={e => setPasswordFieldVal(e.target.value)}
|
||||
/>
|
||||
<div>
|
||||
<input type="submit" value="Log in"/>
|
||||
</div>
|
||||
</form>
|
||||
<br/>
|
||||
<span>
|
||||
I don't have an account yet (<Link to="/signup">go to signup</Link>).
|
||||
</span>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return <LoginForm/>
|
||||
}
|
||||
|
||||
export default Login
|
67
waspc/data/Generator/templates/react-app/src/auth/pages/Signup.js
vendored
Normal file
67
waspc/data/Generator/templates/react-app/src/auth/pages/Signup.js
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useHistory, Link } from 'react-router-dom'
|
||||
|
||||
import signup from '../signup.js'
|
||||
import login from '../login.js'
|
||||
|
||||
const Signup = (props) => {
|
||||
|
||||
const SignUpForm = () => {
|
||||
const history = useHistory()
|
||||
|
||||
const [emailFieldVal, setEmailFieldVal] = useState('')
|
||||
const [passwordFieldVal, setPasswordFieldVal] = useState('')
|
||||
|
||||
const handleSignup = async (event) => {
|
||||
event.preventDefault()
|
||||
try {
|
||||
await signup({ email: emailFieldVal, password: passwordFieldVal })
|
||||
await login (emailFieldVal, passwordFieldVal)
|
||||
|
||||
setEmailFieldVal('')
|
||||
setPasswordFieldVal('')
|
||||
|
||||
// Redirect to main page.
|
||||
history.push('/')
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
window.alert('Error:' + err.message)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<form onSubmit={handleSignup}>
|
||||
<h2>Email</h2>
|
||||
<input
|
||||
type="text"
|
||||
value={emailFieldVal}
|
||||
onChange={e => setEmailFieldVal(e.target.value)}
|
||||
/>
|
||||
<h2>Password</h2>
|
||||
<input
|
||||
type="password"
|
||||
value={passwordFieldVal}
|
||||
onChange={e => setPasswordFieldVal(e.target.value)}
|
||||
/>
|
||||
<div>
|
||||
<input type="submit" value="Sign up"/>
|
||||
</div>
|
||||
</form>
|
||||
<br/>
|
||||
<span>
|
||||
I already have an account (<Link to="/login">go to login</Link>).
|
||||
</span>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SignUpForm/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Signup
|
||||
|
13
waspc/data/Generator/templates/react-app/src/auth/signup.js
vendored
Normal file
13
waspc/data/Generator/templates/react-app/src/auth/signup.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import config from '../config.js'
|
||||
import api, { handleApiError } from '../api.js'
|
||||
|
||||
|
||||
const signup = async (userFields) => {
|
||||
try {
|
||||
await api.post(config.apiUrl + '/auth/signup', userFields)
|
||||
} catch (error) {
|
||||
handleApiError(error)
|
||||
}
|
||||
}
|
||||
|
||||
export default signup
|
@ -1,13 +1,11 @@
|
||||
{{={= =}=}}
|
||||
import Prisma from '@prisma/client'
|
||||
import prisma from '../dbClient.js'
|
||||
|
||||
{=& jsFnImportStatement =}
|
||||
|
||||
{=! TODO: This template is exactly the same at the moment as one for queries,
|
||||
consider in the future if it is worth removing this duplication. =}
|
||||
|
||||
const prisma = new Prisma.PrismaClient()
|
||||
|
||||
export default async (args, context) => {
|
||||
context = { ...context, entities: {
|
||||
{=# entities =}
|
||||
|
@ -2,12 +2,10 @@
|
||||
import jwt from 'jsonwebtoken'
|
||||
import SecurePassword from 'secure-password'
|
||||
import util from 'util'
|
||||
import Prisma from '@prisma/client'
|
||||
|
||||
import prisma from '../dbClient.js'
|
||||
import { handleRejection } from '../utils.js'
|
||||
|
||||
const prisma = new Prisma.PrismaClient()
|
||||
|
||||
const jwtSign = util.promisify(jwt.sign)
|
||||
const jwtVerify = util.promisify(jwt.verify)
|
||||
|
||||
@ -46,15 +44,11 @@ const auth = handleRejection(async (req, res, next) => {
|
||||
next()
|
||||
})
|
||||
|
||||
// TODO(matija): since this function is not doing much anymore, we can remove it.
|
||||
// Make sure to replace its invocations with direct calls to prisma client's create().
|
||||
// Github issue: https://github.com/wasp-lang/wasp/issues/150
|
||||
export const createNewUser = async (userFields) => {
|
||||
const hashedPassword = await hashPassword(userFields.password)
|
||||
|
||||
const newUser = await prisma.{= userEntityLower =}.create({
|
||||
data: {
|
||||
...userFields,
|
||||
password: hashedPassword
|
||||
},
|
||||
})
|
||||
const newUser = await prisma.{= userEntityLower =}.create({ data: userFields })
|
||||
|
||||
return newUser
|
||||
}
|
||||
|
44
waspc/data/Generator/templates/server/src/dbClient.js
Normal file
44
waspc/data/Generator/templates/server/src/dbClient.js
Normal file
@ -0,0 +1,44 @@
|
||||
{{={= =}=}}
|
||||
import Prisma from '@prisma/client'
|
||||
|
||||
import { hashPassword } from './core/auth.js'
|
||||
|
||||
{=# isAuthEnabled =}
|
||||
const PASSWORD_FIELD = 'password'
|
||||
|
||||
{=/ isAuthEnabled =}
|
||||
const createDbClient = () => {
|
||||
const prismaClient = new Prisma.PrismaClient()
|
||||
|
||||
{=# isAuthEnabled =}
|
||||
prismaClient.$use(async (params, next) => {
|
||||
// Make sure password is always hashed before storing to the database.
|
||||
if (params.model === '{= userEntityUpper =}') {
|
||||
if (['create', 'update', 'updateMany'].includes(params.action)) {
|
||||
if (params.args.data.hasOwnProperty(PASSWORD_FIELD)) {
|
||||
params.args.data[PASSWORD_FIELD] = await hashPassword(params.args.data[PASSWORD_FIELD])
|
||||
}
|
||||
} else if (params.action === 'upsert') {
|
||||
if (params.args.create.data.hasOwnProperty(PASSWORD_FIELD)) {
|
||||
params.args.create.data[PASSWORD_FIELD] =
|
||||
await hashPassword(params.args.create.data[PASSWORD_FIELD])
|
||||
}
|
||||
if (params.args.update.data.hasOwnProperty(PASSWORD_FIELD)) {
|
||||
params.args.update.data[PASSWORD_FIELD] =
|
||||
await hashPassword(params.args.update.data[PASSWORD_FIELD])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const result = next(params)
|
||||
|
||||
return result
|
||||
})
|
||||
|
||||
{=/ isAuthEnabled =}
|
||||
return prismaClient
|
||||
}
|
||||
|
||||
const dbClient = createDbClient()
|
||||
|
||||
export default dbClient
|
@ -1,13 +1,11 @@
|
||||
{{={= =}=}}
|
||||
import Prisma from '@prisma/client'
|
||||
import prisma from '../dbClient.js'
|
||||
|
||||
{=& jsFnImportStatement =}
|
||||
|
||||
{=! TODO: This template is exactly the same at the moment as one for queries,
|
||||
consider in the future if it is worth removing this duplication. =}
|
||||
|
||||
const prisma = new Prisma.PrismaClient()
|
||||
|
||||
export default async (args, context) => {
|
||||
context = { ...context, entities: {
|
||||
{=# entities =}
|
||||
|
@ -2,11 +2,13 @@ import express from 'express'
|
||||
|
||||
import auth from '../../core/auth.js'
|
||||
import login from './login.js'
|
||||
import signup from './signup.js'
|
||||
import me from './me.js'
|
||||
|
||||
const router = express.Router()
|
||||
|
||||
router.post('/login', login)
|
||||
router.post('/signup', signup)
|
||||
router.get('/me', auth, me)
|
||||
|
||||
export default router
|
||||
|
@ -38,4 +38,3 @@ export default handleRejection(async (req, res) => {
|
||||
|
||||
return res.json({ token })
|
||||
})
|
||||
|
||||
|
@ -0,0 +1,10 @@
|
||||
import { createNewUser } from '../../core/auth.js'
|
||||
import { handleRejection } from '../../utils.js'
|
||||
|
||||
export default handleRejection(async (req, res) => {
|
||||
const userFields = req.body || {}
|
||||
|
||||
await createNewUser(userFields)
|
||||
|
||||
res.send()
|
||||
})
|
@ -1,9 +1,4 @@
|
||||
import HttpError from '@wasp/core/HttpError.js'
|
||||
import { createNewUser } from '@wasp/core/auth.js'
|
||||
|
||||
export const signUp = async (args, context) => {
|
||||
await createNewUser({ email: args.email, password: args.password })
|
||||
}
|
||||
|
||||
export const createTask = async (task, context) => {
|
||||
if (!context.user) {
|
||||
|
@ -1,50 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
|
||||
import login from '@wasp/auth/login.js'
|
||||
|
||||
const Login = (props) => {
|
||||
|
||||
const LoginForm = () => {
|
||||
const history = useHistory()
|
||||
|
||||
const [emailFieldVal, setEmailFieldVal] = useState('')
|
||||
const [passwordFieldVal, setPasswordFieldVal] = useState('')
|
||||
|
||||
const handleLogin = async (event) => {
|
||||
event.preventDefault()
|
||||
try {
|
||||
await login(emailFieldVal, passwordFieldVal)
|
||||
|
||||
history.push('/')
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
window.alert('Error:' + err.message)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleLogin}>
|
||||
<h2>Email</h2>
|
||||
<input
|
||||
type="text"
|
||||
value={emailFieldVal}
|
||||
onChange={e => setEmailFieldVal(e.target.value)}
|
||||
/>
|
||||
<h2>Password</h2>
|
||||
<input
|
||||
type="password"
|
||||
value={passwordFieldVal}
|
||||
onChange={e => setPasswordFieldVal(e.target.value)}
|
||||
/>
|
||||
<div>
|
||||
<input type="submit" value="Log in"/>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
return <LoginForm/>
|
||||
}
|
||||
|
||||
export default Login
|
@ -1,60 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
|
||||
import signUp from '@wasp/actions/signUp.js'
|
||||
import login from '@wasp/auth/login.js'
|
||||
|
||||
const Signup = (props) => {
|
||||
|
||||
const SignUpForm = () => {
|
||||
const history = useHistory()
|
||||
|
||||
const [emailFieldVal, setEmailFieldVal] = useState('')
|
||||
const [passwordFieldVal, setPasswordFieldVal] = useState('')
|
||||
|
||||
const handleSignup = async (event) => {
|
||||
event.preventDefault()
|
||||
try {
|
||||
await signUp({ email: emailFieldVal, password: passwordFieldVal })
|
||||
await login (emailFieldVal, passwordFieldVal)
|
||||
|
||||
setEmailFieldVal('')
|
||||
setPasswordFieldVal('')
|
||||
|
||||
// Redirect to main page.
|
||||
history.push('/')
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
window.alert('Error:' + err.message)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSignup}>
|
||||
<h2>Email</h2>
|
||||
<input
|
||||
type="text"
|
||||
value={emailFieldVal}
|
||||
onChange={e => setEmailFieldVal(e.target.value)}
|
||||
/>
|
||||
<h2>Password</h2>
|
||||
<input
|
||||
type="password"
|
||||
value={passwordFieldVal}
|
||||
onChange={e => setPasswordFieldVal(e.target.value)}
|
||||
/>
|
||||
<div>
|
||||
<input type="submit" value="Sign up"/>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<SignUpForm/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Signup
|
@ -19,8 +19,15 @@ export const getTask = async ({ id }, context) => {
|
||||
}
|
||||
|
||||
const Task = context.entities.Task
|
||||
const task = await Task.findOne(
|
||||
{ where: { id, user: { id: context.user.id } } }
|
||||
)
|
||||
// NOTE(matija): we can't call findOne() with the specific user, so we have to fetch user first
|
||||
// and then manually check.
|
||||
const task = await Task.findOne({ where: { id }, include: { user: true } })
|
||||
if (!task) {
|
||||
throw new HttpError(404)
|
||||
}
|
||||
if (task.user.id !== context.user.id) {
|
||||
throw new HttpError(403)
|
||||
}
|
||||
|
||||
return task
|
||||
}
|
||||
|
@ -22,16 +22,6 @@ entity Task {=psl
|
||||
userId Int
|
||||
psl=}
|
||||
|
||||
route "/login" -> page Login
|
||||
page Login {
|
||||
component: import Login from "@ext/pages/Login"
|
||||
}
|
||||
|
||||
route "/signup" -> page Signup
|
||||
page Signup {
|
||||
component: import Signup from "@ext/pages/Signup"
|
||||
}
|
||||
|
||||
route "/" -> page Main
|
||||
page Main {
|
||||
component: import Main from "@ext/pages/Main"
|
||||
@ -68,11 +58,6 @@ query getTask {
|
||||
|
||||
// --------- Actions --------- //
|
||||
|
||||
action signUp {
|
||||
fn: import { signUp } from "@ext/actions.js",
|
||||
entities: [User]
|
||||
}
|
||||
|
||||
action createTask {
|
||||
fn: import { createTask } from "@ext/actions.js",
|
||||
entities: [Task]
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Cabal file when you run `stack build`. See the hpack website for help with
|
||||
# this file: <https://github.com/sol/hpack>.
|
||||
name: waspc
|
||||
version: 0.1.7 # %WASP_VERSION% - annotation for new-release script.
|
||||
version: 0.1.8 # %WASP_VERSION% - annotation for new-release script.
|
||||
github: "Martinsos/waspc"
|
||||
license: MIT
|
||||
author: "wasp-lang"
|
||||
|
@ -4,9 +4,10 @@ module Generator.ServerGenerator
|
||||
) where
|
||||
|
||||
import Data.Aeson (object, (.=))
|
||||
import Data.Maybe (isJust)
|
||||
import Data.Maybe (isJust, fromJust)
|
||||
import Data.List (intercalate)
|
||||
import qualified Path as P
|
||||
import StrongPath ((</>))
|
||||
|
||||
import CompileOptions (CompileOptions)
|
||||
import Generator.Common (nodeVersionAsText)
|
||||
@ -24,6 +25,7 @@ import Generator.ServerGenerator.AuthG (genAuth)
|
||||
import qualified NpmDependency as ND
|
||||
import Wasp (Wasp, getAuth)
|
||||
import qualified Wasp
|
||||
import qualified Wasp.Auth
|
||||
import qualified Wasp.NpmDependencies as WND
|
||||
|
||||
|
||||
@ -94,12 +96,30 @@ genSrcDir wasp = concat
|
||||
, [C.copySrcTmplAsIs $ C.asTmplSrcFile [P.relfile|server.js|]]
|
||||
, [C.copySrcTmplAsIs $ C.asTmplSrcFile [P.relfile|utils.js|]]
|
||||
, [C.copySrcTmplAsIs $ C.asTmplSrcFile [P.relfile|core/HttpError.js|]]
|
||||
, [genDbClient wasp]
|
||||
, genRoutesDir wasp
|
||||
, genOperationsRoutes wasp
|
||||
, genOperations wasp
|
||||
, genAuth wasp
|
||||
]
|
||||
|
||||
genDbClient :: Wasp -> FileDraft
|
||||
genDbClient wasp = C.makeTemplateFD tmplFile dstFile (Just tmplData)
|
||||
where
|
||||
maybeAuth = getAuth wasp
|
||||
|
||||
dbClientRelToSrcP = [P.relfile|dbClient.js|]
|
||||
tmplFile = C.asTmplFile $ [P.reldir|src|] P.</> dbClientRelToSrcP
|
||||
dstFile = C.serverSrcDirInServerRootDir </> (C.asServerSrcFile dbClientRelToSrcP)
|
||||
|
||||
tmplData =
|
||||
if (isJust maybeAuth)
|
||||
then object
|
||||
[ "isAuthEnabled" .= True
|
||||
, "userEntityUpper" .= (Wasp.Auth._userEntity $ fromJust maybeAuth)
|
||||
]
|
||||
else object []
|
||||
|
||||
genRoutesDir :: Wasp -> [FileDraft]
|
||||
genRoutesDir wasp =
|
||||
-- TODO(martin): We will probably want to extract "routes" path here same as we did with "src", to avoid hardcoding,
|
||||
|
@ -18,6 +18,7 @@ genAuth wasp = case maybeAuth of
|
||||
-- Auth routes
|
||||
, genAuthRoutesIndex
|
||||
, genLoginRoute auth
|
||||
, genSignupRoute
|
||||
, genMeRoute auth
|
||||
]
|
||||
Nothing -> []
|
||||
@ -52,6 +53,9 @@ genLoginRoute auth = C.makeTemplateFD tmplFile dstFile (Just tmplData)
|
||||
, "userEntityLower" .= Util.toLowerFirst userEntity
|
||||
]
|
||||
|
||||
genSignupRoute :: FileDraft
|
||||
genSignupRoute = C.copySrcTmplAsIs (C.asTmplSrcFile [P.relfile|routes/auth/signup.js|])
|
||||
|
||||
genMeRoute :: Wasp.Auth.Auth -> FileDraft
|
||||
genMeRoute auth = C.makeTemplateFD tmplFile dstFile (Just tmplData)
|
||||
where
|
||||
|
@ -10,14 +10,19 @@ import Generator.WebAppGenerator.Common as C
|
||||
|
||||
genAuth :: Wasp -> [FileDraft]
|
||||
genAuth wasp = case maybeAuth of
|
||||
Just _ -> [ genLogin
|
||||
Just _ -> [ genSignup
|
||||
, genLogin
|
||||
, genLogout
|
||||
, genUseAuth
|
||||
]
|
||||
] ++ genAuthPages
|
||||
Nothing -> []
|
||||
where
|
||||
maybeAuth = getAuth wasp
|
||||
|
||||
-- | Generates file with signup function to be used by Wasp developer.
|
||||
genSignup :: FileDraft
|
||||
genSignup = C.copyTmplAsIs (C.asTmplFile [P.relfile|src/auth/signup.js|])
|
||||
|
||||
-- | Generates file with login function to be used by Wasp developer.
|
||||
genLogin :: FileDraft
|
||||
genLogin = C.copyTmplAsIs (C.asTmplFile [P.relfile|src/auth/login.js|])
|
||||
@ -32,21 +37,14 @@ genLogout = C.copyTmplAsIs (C.asTmplFile [P.relfile|src/auth/logout.js|])
|
||||
genUseAuth :: FileDraft
|
||||
genUseAuth = C.copyTmplAsIs (C.asTmplFile [P.relfile|src/auth/useAuth.js|])
|
||||
|
||||
genAuthPages :: [FileDraft]
|
||||
genAuthPages =
|
||||
[ genSignupPage
|
||||
, genLoginPage
|
||||
]
|
||||
|
||||
{-
|
||||
-- | Generates React hook that Wasp developer can use in a component to get
|
||||
-- access to the currently logged in user (and check whether user is logged in
|
||||
-- ot not).
|
||||
genUseUser :: Wasp.Auth.Auth -> FileDraft
|
||||
genUseUser auth = C.makeTemplateFD tmplFile dstFile (Just tmplData)
|
||||
where
|
||||
tmplFile = C.asTmplFile [P.relfile|src/auth/_useUser.js|]
|
||||
dstFile = C.asWebAppFile $ [P.reldir|src/auth/|] P.</> fromJust (getUseUserDstFileName auth)
|
||||
tmplData = object
|
||||
[ "userEntityLower" .= Util.toLowerFirst (Wasp.Auth._userEntity auth)
|
||||
, "userEntity" .= (Wasp.Auth._userEntity auth)
|
||||
]
|
||||
genLoginPage :: FileDraft
|
||||
genLoginPage = C.copyTmplAsIs (C.asTmplFile [P.relfile|src/auth/pages/Login.js|])
|
||||
|
||||
getUseUserDstFileName :: Wasp.Auth.Auth -> Maybe (P.Path P.Rel P.File)
|
||||
getUseUserDstFileName a = P.parseRelFile ("use" ++ (Wasp.Auth._userEntity a) ++ ".js")
|
||||
-}
|
||||
genSignupPage :: FileDraft
|
||||
genSignupPage = C.copyTmplAsIs (C.asTmplFile [P.relfile|src/auth/pages/Signup.js|])
|
||||
|
@ -2,6 +2,7 @@ module Generator.WebAppGenerator.RouterGenerator
|
||||
( generateRouter
|
||||
) where
|
||||
|
||||
import Data.Maybe (isJust)
|
||||
import Data.Aeson (ToJSON (..), object, (.=))
|
||||
import qualified Path as P
|
||||
|
||||
@ -51,13 +52,58 @@ generateRouter wasp = C.makeTemplateFD
|
||||
|
||||
createRouterTemplateData :: Wasp -> RouterTemplateData
|
||||
createRouterTemplateData wasp = RouterTemplateData
|
||||
{ _routes = Wasp.getRoutes wasp
|
||||
, _pagesToImport = map createPageTemplateData $ Wasp.getPages wasp
|
||||
{ _routes = routes
|
||||
, _pagesToImport = pages
|
||||
}
|
||||
where
|
||||
maybeAuth = Wasp.getAuth wasp
|
||||
routes = (Wasp.getRoutes wasp) ++ (if isJust maybeAuth then authRoutes else [])
|
||||
|
||||
-- TODO(matija): It would be nicer if we were changing AST "higher" in the program, e.g.
|
||||
-- adding built-in pages rather than doing it here in the generator -> that way we'd keep
|
||||
-- generator code simpler and push the logic higher.
|
||||
pages = (map createPageTemplateData $ Wasp.getPages wasp) ++
|
||||
(if isJust maybeAuth then authPages else [])
|
||||
|
||||
authRoutes :: [Wasp.Route.Route]
|
||||
authRoutes =
|
||||
[ Wasp.Route.Route -- Signup route
|
||||
{ Wasp.Route._urlPath = signupPageRoute
|
||||
, Wasp.Route._targetPage = signupPageName
|
||||
}
|
||||
, Wasp.Route.Route -- Login route
|
||||
{ Wasp.Route._urlPath = loginPageRoute
|
||||
, Wasp.Route._targetPage = loginPageName
|
||||
}
|
||||
]
|
||||
|
||||
authPages :: [PageTemplateData]
|
||||
authPages =
|
||||
[ PageTemplateData -- Signup page
|
||||
{ _importWhat = signupPageName
|
||||
, _importFrom =
|
||||
"./" ++ (SP.fromRelFileP $
|
||||
SP.fromPathRelFileP [P.relfile|auth/pages/Signup.js|])
|
||||
}
|
||||
, PageTemplateData -- Login page
|
||||
{ _importWhat = loginPageName
|
||||
, _importFrom =
|
||||
"./" ++ (SP.fromRelFileP $
|
||||
SP.fromPathRelFileP [P.relfile|auth/pages/Login.js|])
|
||||
}
|
||||
]
|
||||
|
||||
signupPageName = "Signup"
|
||||
signupPageRoute = "/signup"
|
||||
|
||||
loginPageName = "Login"
|
||||
loginPageRoute = "/login"
|
||||
|
||||
|
||||
createPageTemplateData :: Wasp.Page.Page -> PageTemplateData
|
||||
createPageTemplateData page = PageTemplateData
|
||||
{ _importFrom = relPathToExtSrcDir ++ SP.toFilePath (SP.relFileToPosix' $ Wasp.JsImport._from pageComponent)
|
||||
{ _importFrom = relPathToExtSrcDir ++
|
||||
SP.toFilePath (SP.relFileToPosix' $ Wasp.JsImport._from pageComponent)
|
||||
, _importWhat = case Wasp.JsImport._namedImports pageComponent of
|
||||
-- If no named imports, we go with the default import.
|
||||
[] -> pageName
|
||||
|
Loading…
Reference in New Issue
Block a user