tweak auth api

This commit is contained in:
Ryan Haskell-Glatz 2021-03-02 17:11:01 -06:00
parent 79546c51bf
commit fffcad03f1
15 changed files with 374 additions and 28 deletions

5
examples/04-demo/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.DS_Store
.elm-spa
elm-stuff
node_modules
dist

View File

@ -0,0 +1,28 @@
# my new project
> 🌳 built with [elm-spa](https://elm-spa.dev)
## dependencies
This project requires the latest LTS version of [Node.js](https://nodejs.org/)
```bash
npm install -g elm elm-spa
```
## running locally
```bash
elm-spa server # starts this app at http:/localhost:1234
```
### other commands
```bash
elm-spa add # add a new page to the application
elm-spa build # production build
elm-spa watch # runs build as you code (without the server)
```
## learn more
You can learn more at [elm-spa.dev](https://elm-spa.dev)

27
examples/04-demo/elm.json Normal file
View File

@ -0,0 +1,27 @@
{
"type": "application",
"source-directories": [
"src",
".elm-spa/defaults",
".elm-spa/generated"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/json": "1.1.3",
"elm/url": "1.0.0",
"ryannhg/elm-spa": "5.2.0"
},
"indirect": {
"elm/time": "1.0.0",
"elm/virtual-dom": "1.0.2"
}
},
"test-dependencies": {
"direct": {},
"indirect": {}
}
}

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script src="/dist/elm.js"></script>
<script> Elm.Main.init() </script>
</body>
</html>

View File

@ -0,0 +1,30 @@
module Auth exposing
( User
, beforeProtectedInit
)
{-|
@docs User
@docs beforeProtectedInit
-}
import ElmSpa.Internals.Page as ElmSpa
import Gen.Route exposing (Route)
import Request exposing (Request)
import Shared
type alias User =
Shared.User
beforeProtectedInit : Shared.Model -> Request -> ElmSpa.Protected User Route
beforeProtectedInit shared req =
case shared.user of
Just user ->
ElmSpa.Provide user
Nothing ->
ElmSpa.RedirectTo Gen.Route.SignIn

View File

@ -0,0 +1,59 @@
module Pages.Home_ exposing (Model, Msg, page, view)
import Auth
import Effect exposing (Effect)
import Html
import Page
import Request exposing (Request)
import Shared
import View exposing (View)
page : Shared.Model -> Request -> Page.With Model Msg
page _ _ =
Page.protected.advanced
{ init = always init
, update = always update
, view = view
, subscriptions = \_ _ -> Sub.none
}
-- INIT
type alias Model =
{}
init : ( Model, Effect Msg )
init =
( {}, Effect.none )
-- UPDATE
type Msg
= ClickedSignOut
update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
case msg of
ClickedSignOut ->
( model
, Effect.fromShared Shared.SignedOut
)
view : Auth.User -> Model -> View msg
view user _ =
{ title = "Homepage"
, body =
[ Html.h1 [] [ Html.text ("Hello, " ++ user.name ++ "!") ]
, Html.button [] [ Html.text "Sign out" ]
]
}

View File

@ -0,0 +1,93 @@
module Pages.SignIn exposing (Model, Msg, page)
import Effect exposing (Effect)
import Gen.Params.SignIn exposing (Params)
import Html
import Html.Attributes as Attr
import Html.Events as Events
import Page
import Request
import Shared
import View exposing (View)
page : Shared.Model -> Request.With Params -> Page.With Model Msg
page shared req =
Page.advanced
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
}
-- INIT
type alias Model =
{ name : String }
init : ( Model, Effect Msg )
init =
( { name = "" }
, Effect.none
)
-- UPDATE
type Msg
= UpdatedName String
| SubmittedSignInForm
update : Msg -> Model -> ( Model, Effect Msg )
update msg model =
case msg of
UpdatedName name ->
( { model | name = name }
, Effect.none
)
SubmittedSignInForm ->
( model
, Effect.fromShared (Shared.SignedIn model.name)
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> View Msg
view model =
{ title = "Sign in"
, body =
[ Html.form [ Events.onSubmit SubmittedSignInForm ]
[ Html.label []
[ Html.span [] [ Html.text "Name" ]
, Html.input
[ Attr.type_ "text"
, Attr.value model.name
, Events.onInput UpdatedName
]
[]
]
, Html.button [ Attr.disabled (String.isEmpty model.name) ]
[ Html.text "Sign in" ]
]
]
}

View File

@ -0,0 +1,66 @@
module Shared exposing
( Flags
, Model
, Msg(..)
, User
, init
, subscriptions
, update
)
import Gen.Route
import Json.Decode as Json
import Request exposing (Request)
type alias User =
{ name : String
}
-- INIT
type alias Flags =
Json.Value
type alias Model =
{ user : Maybe User
}
init : Request -> Flags -> ( Model, Cmd Msg )
init _ _ =
( { user = Nothing }
, Cmd.none
)
-- UPDATE
type Msg
= SignedIn String
| SignedOut
update : Request -> Msg -> Model -> ( Model, Cmd Msg )
update req msg model =
case msg of
SignedIn name ->
( { model | user = Just { name = name } }
, Request.pushRoute Gen.Route.Home_ req
)
SignedOut ->
( { model | user = Nothing }
, Cmd.none
)
subscriptions : Request -> Model -> Sub Msg
subscriptions _ _ =
Sub.none

View File

@ -1,6 +1,6 @@
{
"name": "elm-spa",
"version": "6.0.8--beta",
"version": "6.0.9--beta",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
"name": "elm-spa",
"version": "6.0.8--beta",
"version": "6.0.9--beta",
"description": "single page apps made easy",
"bin": "dist/src/index.js",
"scripts": {

View File

@ -4,6 +4,8 @@ import config from '../config'
import * as File from '../file'
import RouteTemplate from '../templates/routes'
import PagesTemplate from '../templates/pages'
import PageTemplate from '../templates/page'
import RequestTemplate from '../templates/request'
import ModelTemplate from '../templates/model'
import MsgTemplate from '../templates/msg'
import ParamsTemplate from '../templates/params'
@ -114,6 +116,9 @@ const createGeneratedFiles = async () => {
const filesToCreate = [
...paramFiles,
{ filepath: [ 'Page' ], contents: PageTemplate() },
{ filepath: [ 'Request' ], contents: RequestTemplate() },
{ filepath: [ 'Gen', 'Route' ], contents: RouteTemplate(segments, options(kindForPage)) },
{ filepath: [ 'Gen', 'Route' ], contents: RouteTemplate(segments, options(kindForPage)) },
{ filepath: [ 'Gen', 'Pages' ], contents: PagesTemplate(segments, options(kindForPage)) },
{ filepath: [ 'Gen', 'Model' ], contents: ModelTemplate(segments, options(kindForPage)) },

View File

@ -36,12 +36,11 @@ const config = {
terser: `npx terser`
},
defaults: [
[ 'Auth.elm' ],
[ 'Effect.elm' ],
[ 'Main.elm' ],
[ 'Shared.elm' ],
[ `Pages`, `${reserved.notFound}.elm` ],
[ 'Page.elm' ],
[ 'Request.elm' ],
[ 'View.elm' ]
]
}

View File

@ -0,0 +1,39 @@
module Auth exposing
( User
, beforeProtectedInit
)
{-|
@docs User
@docs beforeProtectedInit
-}
import ElmSpa.Internals.Page as ElmSpa
import Gen.Route exposing (Route)
import Request exposing (Request)
import Shared
{-| Replace the "()" with your actual User type
-}
type alias User =
()
{-| This function will run before any `protected` pages.
Here, you can provide logic on where to redirect if a user is not signed in. Here's an example:
case shared.user of
Just user ->
ElmSpa.Provide user
Nothing ->
ElmSpa.RedirectTo Gen.Route.SignIn
-}
beforeProtectedInit : Shared.Model -> Request -> ElmSpa.Protected User Route
beforeProtectedInit shared req =
ElmSpa.RedirectTo Gen.Route.NotFound

View File

@ -1,3 +1,4 @@
export default (): string => `
module Page exposing
( Page, With
, static, sandbox, element, advanced
@ -12,6 +13,7 @@ module Page exposing
-}
import Auth exposing (User)
import Effect exposing (Effect)
import ElmSpa.Internals.Page as ElmSpa
import Gen.Route exposing (Route)
@ -76,29 +78,6 @@ advanced =
-- PROTECTED PAGES
{-| Replace "()" with your actual User type
-}
type alias User =
()
{-| This function will run before any `protected` pages.
Here, you can provide logic on where to redirect if a user is not signed in. Here's an example:
case shared.user of
Just user ->
ElmSpa.Provide user
Nothing ->
ElmSpa.RedirectTo Gen.Route.SignIn
-}
beforeProtectedInit : Shared.Model -> Request -> ElmSpa.Protected User Route
beforeProtectedInit shared req =
ElmSpa.RedirectTo Gen.Route.NotFound
protected :
{ static :
{ view : User -> View msg
@ -129,5 +108,7 @@ protected =
ElmSpa.protected2
{ effectNone = Effect.none
, fromCmd = Effect.fromCmd
, beforeInit = beforeProtectedInit
, beforeInit = Auth.beforeProtectedInit
}
`.trimLeft()

View File

@ -1,3 +1,4 @@
export default (): string => `
module Request exposing
( Request, With
, create
@ -39,3 +40,5 @@ pushRoute route req =
replaceRoute : Route -> With params -> Cmd msg
replaceRoute route req =
Browser.Navigation.replaceUrl req.key (Route.toHref route)
`.trimLeft()