From af4ad8e46b0565fee8b7f590a306c3fab5da2ec3 Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Sat, 5 May 2018 05:41:45 -0400 Subject: [PATCH] Update part10 --- part10/elm-package.json | 2 +- part10/elm-stuff/exact-dependencies.json | 2 +- .../elm-validate/{2.0.0 => 3.0.0}/.gitignore | 0 .../{2.0.0 => 3.0.0}/CHANGELOG.md | 0 .../elm-validate/{2.0.0 => 3.0.0}/LICENSE | 0 .../elm-validate/{2.0.0 => 3.0.0}/README.md | 12 +-- .../{2.0.0 => 3.0.0}/elm-package.json | 2 +- .../{2.0.0 => 3.0.0}/examples/SignupForm.elm | 0 .../examples/elm-package.json | 0 .../{2.0.0 => 3.0.0}/src/Validate.elm | 101 +++++++++++++++--- .../{2.0.0 => 3.0.0}/tests/ValidateTests.elm | 0 .../{2.0.0 => 3.0.0}/tests/elm-package.json | 0 .../tests/elm-verify-examples.json | 0 part10/src/Data/Article/Author.elm | 4 +- part10/src/Data/User.elm | 8 +- part10/src/Data/UserPhoto.elm | 10 +- part10/src/Page/Article/Editor.elm | 10 +- part10/src/Page/Profile.elm | 37 ++----- part10/src/Page/Register.elm | 15 ++- part10/src/Request/Helpers.elm | 2 +- 20 files changed, 132 insertions(+), 73 deletions(-) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/.gitignore (100%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/CHANGELOG.md (100%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/LICENSE (100%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/README.md (86%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/elm-package.json (94%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/examples/SignupForm.elm (100%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/examples/elm-package.json (100%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/src/Validate.elm (75%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/tests/ValidateTests.elm (100%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/tests/elm-package.json (100%) rename part10/elm-stuff/packages/rtfeldman/elm-validate/{2.0.0 => 3.0.0}/tests/elm-verify-examples.json (100%) diff --git a/part10/elm-package.json b/part10/elm-package.json index 2a97361..7c979f1 100644 --- a/part10/elm-package.json +++ b/part10/elm-package.json @@ -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" diff --git a/part10/elm-stuff/exact-dependencies.json b/part10/elm-stuff/exact-dependencies.json index 0298d1a..77b48b4 100644 --- a/part10/elm-stuff/exact-dependencies.json +++ b/part10/elm-stuff/exact-dependencies.json @@ -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", diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/.gitignore b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/.gitignore similarity index 100% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/.gitignore rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/.gitignore diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/CHANGELOG.md b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/CHANGELOG.md similarity index 100% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/CHANGELOG.md rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/CHANGELOG.md diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/LICENSE b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/LICENSE similarity index 100% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/LICENSE rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/LICENSE diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/README.md b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/README.md similarity index 86% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/README.md rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/README.md index be1baf7..423e1b7 100644 --- a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/README.md +++ b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/README.md @@ -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." ) + --> ] ``` diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/elm-package.json b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/elm-package.json similarity index 94% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/elm-package.json rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/elm-package.json index 395c724..3afc2ea 100644 --- a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/elm-package.json +++ b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/elm-package.json @@ -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", diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/examples/SignupForm.elm b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/examples/SignupForm.elm similarity index 100% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/examples/SignupForm.elm rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/examples/SignupForm.elm diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/examples/elm-package.json b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/examples/elm-package.json similarity index 100% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/examples/elm-package.json rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/examples/elm-package.json diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/src/Validate.elm b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/src/Validate.elm similarity index 75% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/src/Validate.elm rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/src/Validate.elm index 211abfa..4d1b4a1 100644 --- a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/src/Validate.elm +++ b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/src/Validate.elm @@ -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. diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/tests/ValidateTests.elm b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/tests/ValidateTests.elm similarity index 100% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/tests/ValidateTests.elm rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/tests/ValidateTests.elm diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/tests/elm-package.json b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/tests/elm-package.json similarity index 100% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/tests/elm-package.json rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/tests/elm-package.json diff --git a/part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/tests/elm-verify-examples.json b/part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/tests/elm-verify-examples.json similarity index 100% rename from part10/elm-stuff/packages/rtfeldman/elm-validate/2.0.0/tests/elm-verify-examples.json rename to part10/elm-stuff/packages/rtfeldman/elm-validate/3.0.0/tests/elm-verify-examples.json diff --git a/part10/src/Data/Article/Author.elm b/part10/src/Data/Article/Author.elm index ab8f108..a632508 100644 --- a/part10/src/Data/Article/Author.elm +++ b/part10/src/Data/Article/Author.elm @@ -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 = diff --git a/part10/src/Data/User.elm b/part10/src/Data/User.elm index 40f6338..aa60a0c 100644 --- a/part10/src/Data/User.elm +++ b/part10/src/Data/User.elm @@ -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 ) ] diff --git a/part10/src/Data/UserPhoto.elm b/part10/src/Data/UserPhoto.elm index a97715c..bf7f768 100644 --- a/part10/src/Data/UserPhoto.elm +++ b/part10/src/Data/UserPhoto.elm @@ -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" diff --git a/part10/src/Page/Article/Editor.elm b/part10/src/Page/Article/Editor.elm index bb1c579..8ba8e27 100644 --- a/part10/src/Page/Article/Editor.elm +++ b/part10/src/Page/Article/Editor.elm @@ -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 ] diff --git a/part10/src/Page/Profile.elm b/part10/src/Page/Profile.elm index aa3d809..c3c81e4 100644 --- a/part10/src/Page/Profile.elm +++ b/part10/src/Page/Profile.elm @@ -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 - profile.username - profile.following - user.token - |> Http.send FollowCompleted - in - ( model, cmd ) + user.token + |> Request.Profile.toggleFollow + profile.username + profile.following + |> Http.send FollowCompleted + |> pair model FollowCompleted (Ok newProfile) -> ( { model | profile = newProfile }, Cmd.none ) diff --git a/part10/src/Page/Register.elm b/part10/src/Page/Register.elm index 3349060..e1e09a2 100644 --- a/part10/src/Page/Register.elm +++ b/part10/src/Page/Register.elm @@ -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 ]) diff --git a/part10/src/Request/Helpers.elm b/part10/src/Request/Helpers.elm index b4cee34..e9a0bc2 100644 --- a/part10/src/Request/Helpers.elm +++ b/part10/src/Request/Helpers.elm @@ -3,4 +3,4 @@ module Request.Helpers exposing (apiUrl) apiUrl : String -> String apiUrl str = - "https://conduit.productionready.io/api" ++ str + "/api" ++ str