Update part10
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
"evancz/url-parser": "2.0.1 <= v < 3.0.0",
|
||||
"lukewestby/elm-http-builder": "5.1.0 <= v < 6.0.0",
|
||||
"mgold/elm-date-format": "1.3.0 <= v < 2.0.0",
|
||||
"rtfeldman/elm-validate": "2.0.0 <= v < 3.0.0",
|
||||
"rtfeldman/elm-validate": "3.0.0 <= v < 4.0.0",
|
||||
"rtfeldman/selectlist": "1.0.0 <= v < 2.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"rtfeldman/elm-validate": "2.0.0",
|
||||
"rtfeldman/elm-validate": "3.0.0",
|
||||
"rtfeldman/selectlist": "1.0.0",
|
||||
"elm-lang/navigation": "2.1.0",
|
||||
"elm-lang/virtual-dom": "2.0.4",
|
||||
|
||||
@@ -16,7 +16,7 @@ type alias Model =
|
||||
{ name : String, email : String, age : String, selections : List String }
|
||||
|
||||
|
||||
modelValidator : Validator Model String
|
||||
modelValidator : Validator String Model
|
||||
modelValidator =
|
||||
Validate.all
|
||||
[ ifBlank .name "Please enter a name."
|
||||
@@ -28,8 +28,7 @@ modelValidator =
|
||||
|
||||
validate modelValidator
|
||||
{ name = "Sam", email = "", age = "abc", selections = [ "cats" ] }
|
||||
== [ "Please enter an email address.", "Age must be a whole number." ]
|
||||
--> True
|
||||
--> [ "Please enter an email address.", "Age must be a whole number." ]
|
||||
```
|
||||
|
||||
You can represent your errors however you like. One nice approach is to use
|
||||
@@ -56,8 +55,7 @@ type alias Model =
|
||||
|
||||
validate modelValidator
|
||||
{ name = "Sam", email = "", age = "abc", selections = [ "cats" ] }
|
||||
== [ ( Email, "Please enter an email address." )
|
||||
, ( Age, "Age must be a whole number." )
|
||||
]
|
||||
--> True
|
||||
--> [ ( Email, "Please enter an email address." )
|
||||
--> , ( Age, "Age must be a whole number." )
|
||||
--> ]
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"version": "3.0.0",
|
||||
"summary": "Convenience functions for validating data.",
|
||||
"repository": "https://github.com/rtfeldman/elm-validate.git",
|
||||
"license": "BSD-3-Clause",
|
||||
@@ -4,6 +4,7 @@ module Validate
|
||||
, all
|
||||
, any
|
||||
, firstError
|
||||
, fromErrors
|
||||
, ifBlank
|
||||
, ifEmptyDict
|
||||
, ifEmptyList
|
||||
@@ -21,7 +22,7 @@ module Validate
|
||||
|
||||
{-| Convenience functions for validating data.
|
||||
|
||||
import Validate exposing (ifBlank, ifNotInt, validate)
|
||||
import Validate exposing (Validator, ifBlank, ifNotInt, validate)
|
||||
|
||||
type Field = Name | Email | Age
|
||||
|
||||
@@ -49,7 +50,7 @@ module Validate
|
||||
|
||||
# Creating validators
|
||||
|
||||
@docs ifBlank, ifNotInt, ifEmptyList, ifEmptyDict, ifEmptySet, ifNothing, ifInvalidEmail, ifTrue, ifFalse
|
||||
@docs ifBlank, ifNotInt, ifEmptyList, ifEmptyDict, ifEmptySet, ifNothing, ifInvalidEmail, ifTrue, ifFalse, fromErrors
|
||||
|
||||
|
||||
# Combining validators
|
||||
@@ -86,7 +87,7 @@ type Validator error subject
|
||||
{-| Return an error if the given predicate returns `True` for the given
|
||||
subject.
|
||||
|
||||
import Validate exposing (ifBlank, ifNotInt, validate)
|
||||
import Validate exposing (Validator, ifBlank, ifNotInt, validate)
|
||||
|
||||
type Field = Name | Email | Age
|
||||
|
||||
@@ -116,7 +117,7 @@ validate (Validator getErrors) subject =
|
||||
{-| Return an error if the given `String` is empty, or if it contains only
|
||||
whitespace characters.
|
||||
|
||||
import Validate exposing (ifBlank, ifNotInt)
|
||||
import Validate exposing (Validator, ifBlank)
|
||||
|
||||
modelValidator : Validator Model String
|
||||
modelValidator =
|
||||
@@ -132,10 +133,31 @@ ifBlank subjectToString error =
|
||||
|
||||
|
||||
{-| Return an error if the given `String` cannot be parsed as an `Int`.
|
||||
|
||||
import Validate exposing (Validator, ifNotInt)
|
||||
|
||||
modelValidator : Validator Model String
|
||||
modelValidator =
|
||||
Validate.all
|
||||
[ ifNotInt .followers (\_ -> "Please enter a whole number for followers.")
|
||||
, ifNotInt .stars (\stars -> "Stars was \"" ++ stars ++ "\", but it needs to be a whole number.")"
|
||||
]
|
||||
|
||||
-}
|
||||
ifNotInt : (subject -> String) -> error -> Validator error subject
|
||||
ifNotInt subjectToString error =
|
||||
ifFalse (\subject -> isInt (subjectToString subject)) error
|
||||
ifNotInt : (subject -> String) -> (String -> error) -> Validator error subject
|
||||
ifNotInt subjectToString errorFromString =
|
||||
let
|
||||
getErrors subject =
|
||||
let
|
||||
str =
|
||||
subjectToString subject
|
||||
in
|
||||
if isInt str then
|
||||
[]
|
||||
else
|
||||
[ errorFromString str ]
|
||||
in
|
||||
Validator getErrors
|
||||
|
||||
|
||||
{-| Return an error if a `List` is empty.
|
||||
@@ -167,16 +189,65 @@ ifNothing subjectToMaybe error =
|
||||
|
||||
|
||||
{-| Return an error if an email address is malformed.
|
||||
|
||||
import Validate exposing (Validator, ifBlank, ifNotInt)
|
||||
|
||||
modelValidator : Validator Model String
|
||||
modelValidator =
|
||||
Validate.all
|
||||
[ ifInvalidEmail .primaryEmail (\_ -> "Please enter a valid primary email address.")
|
||||
, ifInvalidEmail .superSecretEmail (\email -> "Unfortunately, \"" ++ email ++ "\" is not a valid Super Secret Email Address.")
|
||||
]
|
||||
|
||||
-}
|
||||
ifInvalidEmail : (subject -> String) -> error -> Validator error subject
|
||||
ifInvalidEmail subjectToEmail error =
|
||||
ifFalse (\subject -> isValidEmail (subjectToEmail subject)) error
|
||||
ifInvalidEmail : (subject -> String) -> (String -> error) -> Validator error subject
|
||||
ifInvalidEmail subjectToEmail errorFromEmail =
|
||||
let
|
||||
getErrors subject =
|
||||
let
|
||||
email =
|
||||
subjectToEmail subject
|
||||
in
|
||||
if isValidEmail email then
|
||||
[]
|
||||
else
|
||||
[ errorFromEmail email ]
|
||||
in
|
||||
Validator getErrors
|
||||
|
||||
|
||||
{-| Create a custom validator, by providing a function that returns a list of
|
||||
errors given a subject.
|
||||
|
||||
import Validate exposing (Validator, fromErrors)
|
||||
|
||||
modelValidator : Validator Model String
|
||||
modelValidator =
|
||||
fromErrors modelToErrors
|
||||
|
||||
modelToErrors : Model -> List String
|
||||
modelToErrors model =
|
||||
let
|
||||
usernameLength =
|
||||
String.length model.username
|
||||
in
|
||||
if usernameLength < minUsernameChars then
|
||||
[ "Username not long enough" ]
|
||||
else if usernameLength > maxUsernameChars then
|
||||
[ "Username too long" ]
|
||||
else
|
||||
[]
|
||||
|
||||
-}
|
||||
fromErrors : (subject -> List error) -> Validator error subject
|
||||
fromErrors toErrors =
|
||||
Validator toErrors
|
||||
|
||||
|
||||
{-| Return an error if a predicate returns `True` for the given
|
||||
subject.
|
||||
|
||||
import Validate exposing (ifTrue)
|
||||
import Validate exposing (Validator, ifTrue)
|
||||
|
||||
modelValidator : Validator Model String
|
||||
modelValidator =
|
||||
@@ -199,7 +270,7 @@ ifTrue test error =
|
||||
{-| Return an error if a predicate returns `False` for the given
|
||||
subject.
|
||||
|
||||
import Validate exposing (ifFalse)
|
||||
import Validate exposing (Validator, ifFalse)
|
||||
|
||||
modelValidator : Validator Model String
|
||||
modelValidator =
|
||||
@@ -226,7 +297,7 @@ ifFalse test error =
|
||||
{-| Run each of the given validators, in order, and return their concatenated
|
||||
error lists.
|
||||
|
||||
import Validate exposing (ifBlank, ifNotInt)
|
||||
import Validate exposing (Validator, ifBlank, ifNotInt)
|
||||
|
||||
modelValidator : Validator Model String
|
||||
modelValidator =
|
||||
@@ -253,7 +324,7 @@ all validators =
|
||||
{-| Run each of the given validators, in order, stopping after the first error
|
||||
and returning it. If no errors are encountered, return `Nothing`.
|
||||
|
||||
import Validate exposing (ifBlank, ifInvalidEmail, ifNotInt)
|
||||
import Validate exposing (Validator, ifBlank, ifInvalidEmail, ifNotInt)
|
||||
|
||||
|
||||
type alias Model =
|
||||
@@ -337,7 +408,7 @@ isBlank str =
|
||||
Regex.contains lacksNonWhitespaceChars str
|
||||
|
||||
|
||||
{-| Returns `True` if the email is malformed.
|
||||
{-| Returns `True` if the email is valid.
|
||||
|
||||
[`ifInvalidEmail`](#ifInvalidEmail) uses this under the hood.
|
||||
|
||||
@@ -3,7 +3,7 @@ module Data.Article.Author exposing (Author, decoder)
|
||||
import Data.User as User exposing (Username)
|
||||
import Data.UserPhoto as UserPhoto exposing (UserPhoto)
|
||||
import Json.Decode as Decode exposing (Decoder)
|
||||
import Json.Decode.Pipeline exposing (custom, decode, required)
|
||||
import Json.Decode.Pipeline exposing (custom, decode, optional, required)
|
||||
|
||||
|
||||
decoder : Decoder Author
|
||||
@@ -12,7 +12,7 @@ decoder =
|
||||
|> required "username" User.usernameDecoder
|
||||
|> required "bio" (Decode.nullable Decode.string)
|
||||
|> required "image" UserPhoto.decoder
|
||||
|> required "following" Decode.bool
|
||||
|> optional "following" Decode.bool False
|
||||
|
||||
|
||||
type alias Author =
|
||||
|
||||
@@ -4,7 +4,7 @@ import Data.AuthToken as AuthToken exposing (AuthToken)
|
||||
import Data.UserPhoto as UserPhoto exposing (UserPhoto)
|
||||
import Html exposing (Html)
|
||||
import Json.Decode as Decode exposing (Decoder)
|
||||
import Json.Decode.Pipeline exposing (decode, required)
|
||||
import Json.Decode.Pipeline exposing (decode, optional, required)
|
||||
import Json.Encode as Encode exposing (Value)
|
||||
import Json.Encode.Extra as EncodeExtra
|
||||
import UrlParser
|
||||
@@ -16,8 +16,6 @@ type alias User =
|
||||
, username : Username
|
||||
, bio : Maybe String
|
||||
, image : UserPhoto
|
||||
, createdAt : String
|
||||
, updatedAt : String
|
||||
}
|
||||
|
||||
|
||||
@@ -33,8 +31,6 @@ decoder =
|
||||
|> required "username" usernameDecoder
|
||||
|> required "bio" (Decode.nullable Decode.string)
|
||||
|> required "image" UserPhoto.decoder
|
||||
|> required "createdAt" Decode.string
|
||||
|> required "updatedAt" Decode.string
|
||||
|
||||
|
||||
encode : User -> Value
|
||||
@@ -45,8 +41,6 @@ encode user =
|
||||
, ( "username", encodeUsername user.username )
|
||||
, ( "bio", EncodeExtra.maybe Encode.string user.bio )
|
||||
, ( "image", UserPhoto.encode user.image )
|
||||
, ( "createdAt", Encode.string user.createdAt )
|
||||
, ( "updatedAt", Encode.string user.updatedAt )
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -39,7 +39,15 @@ photoToUrl : UserPhoto -> String
|
||||
photoToUrl (UserPhoto maybeUrl) =
|
||||
case maybeUrl of
|
||||
Nothing ->
|
||||
"https://static.productionready.io/images/smiley-cyrus.jpg"
|
||||
defaultPhotoUrl
|
||||
|
||||
Just "" ->
|
||||
defaultPhotoUrl
|
||||
|
||||
Just url ->
|
||||
url
|
||||
|
||||
|
||||
defaultPhotoUrl : String
|
||||
defaultPhotoUrl =
|
||||
"/assets/images/smiley-cyrus.jpg"
|
||||
|
||||
@@ -4,7 +4,7 @@ import Data.Article as Article exposing (Article, Body)
|
||||
import Data.Session exposing (Session)
|
||||
import Data.User exposing (User)
|
||||
import Html exposing (..)
|
||||
import Html.Attributes exposing (attribute, class, disabled, href, id, placeholder, type_, value)
|
||||
import Html.Attributes exposing (attribute, class, defaultValue, disabled, href, id, placeholder, type_)
|
||||
import Html.Events exposing (onInput, onSubmit)
|
||||
import Http
|
||||
import Page.Errored exposing (PageLoadError, pageLoadError)
|
||||
@@ -102,26 +102,26 @@ viewForm model =
|
||||
[ class "form-control-lg"
|
||||
, placeholder "Article Title"
|
||||
, onInput SetTitle
|
||||
, value model.title
|
||||
, defaultValue model.title
|
||||
]
|
||||
[]
|
||||
, Form.input
|
||||
[ placeholder "What's this article about?"
|
||||
, onInput SetDescription
|
||||
, value model.description
|
||||
, defaultValue model.description
|
||||
]
|
||||
[]
|
||||
, Form.textarea
|
||||
[ placeholder "Write your article (in markdown)"
|
||||
, attribute "rows" "8"
|
||||
, onInput SetBody
|
||||
, value model.body
|
||||
, defaultValue model.body
|
||||
]
|
||||
[]
|
||||
, Form.input
|
||||
[ placeholder "Enter tags"
|
||||
, onInput SetTags
|
||||
, value (String.join " " model.tags)
|
||||
, defaultValue (String.join " " model.tags)
|
||||
]
|
||||
[]
|
||||
, button [ class "btn btn-lg pull-xs-right btn-primary", disabled model.isSaving ]
|
||||
|
||||
@@ -133,37 +133,12 @@ update session msg model =
|
||||
)
|
||||
|
||||
Just user ->
|
||||
let
|
||||
-- TODO
|
||||
-- 1) head over to the Request.Profile module and look up
|
||||
-- what arguments the `toggleFollow` function takes.
|
||||
--
|
||||
-- 2) call Request.Profile.toggleFollow here,
|
||||
-- to get back a Request.
|
||||
--
|
||||
-- 3) pass that Request to Http.send to get a Cmd.
|
||||
-- Use that Cmd here.
|
||||
--
|
||||
-- Here's the documentation for Http.send:
|
||||
-- http://package.elm-lang.org/packages/elm-lang/http/1.0.0/Http#send
|
||||
--
|
||||
-- Here are some hepful values that are in scope:
|
||||
--
|
||||
-- user.token : Maybe AuthToken
|
||||
--
|
||||
-- profile : Profile [look in the Data.Profile module!]
|
||||
--
|
||||
-- FollowCompleted : Result Http.Error Profile -> Msg
|
||||
--
|
||||
cmd : Cmd Msg
|
||||
cmd =
|
||||
Request.Profile.toggleFollow
|
||||
user.token
|
||||
|> Request.Profile.toggleFollow
|
||||
profile.username
|
||||
profile.following
|
||||
user.token
|
||||
|> Http.send FollowCompleted
|
||||
in
|
||||
( model, cmd )
|
||||
|> pair model
|
||||
|
||||
FollowCompleted (Ok newProfile) ->
|
||||
( { model | profile = newProfile }, Cmd.none )
|
||||
|
||||
@@ -186,10 +186,23 @@ modelValidator =
|
||||
Validate.all
|
||||
[ ifBlank .username ( Username, "username can't be blank." )
|
||||
, ifBlank .email ( Email, "email can't be blank." )
|
||||
, ifBlank .password ( Password, "password can't be blank." )
|
||||
, Validate.fromErrors passwordLength
|
||||
]
|
||||
|
||||
|
||||
minPasswordChars : Int
|
||||
minPasswordChars =
|
||||
6
|
||||
|
||||
|
||||
passwordLength : Model -> List Error
|
||||
passwordLength { password } =
|
||||
if String.length password < minPasswordChars then
|
||||
[ ( Password, "password must be at least " ++ toString minPasswordChars ++ " characters long." ) ]
|
||||
else
|
||||
[]
|
||||
|
||||
|
||||
errorsDecoder : Decoder (List String)
|
||||
errorsDecoder =
|
||||
decode (\email username password -> List.concat [ email, username, password ])
|
||||
|
||||
@@ -3,4 +3,4 @@ module Request.Helpers exposing (apiUrl)
|
||||
|
||||
apiUrl : String -> String
|
||||
apiUrl str =
|
||||
"https://conduit.productionready.io/api" ++ str
|
||||
"/api" ++ str
|
||||
|
||||
Reference in New Issue
Block a user