Add finished/

This commit is contained in:
Richard Feldman
2018-05-01 21:49:22 -04:00
parent 975a010c1f
commit f17c09108d
575 changed files with 79140 additions and 0 deletions

View File

@@ -0,0 +1,271 @@
module Request.Article
exposing
( FeedConfig
, ListConfig
, create
, defaultFeedConfig
, defaultListConfig
, delete
, feed
, get
, list
, tags
, toggleFavorite
, update
)
import Data.Article as Article exposing (Article, Body, Tag, slugToString)
import Data.Article.Feed as Feed exposing (Feed)
import Data.AuthToken exposing (AuthToken, withAuthorization)
import Data.User as User exposing (Username)
import Http
import HttpBuilder exposing (RequestBuilder, withBody, withExpect, withQueryParams)
import Json.Decode as Decode
import Json.Encode as Encode
import Request.Helpers exposing (apiUrl)
-- SINGLE --
get : Maybe AuthToken -> Article.Slug -> Http.Request (Article Body)
get maybeToken slug =
let
expect =
Article.decoderWithBody
|> Decode.field "article"
|> Http.expectJson
in
apiUrl ("/articles/" ++ Article.slugToString slug)
|> HttpBuilder.get
|> HttpBuilder.withExpect expect
|> withAuthorization maybeToken
|> HttpBuilder.toRequest
-- LIST --
type alias ListConfig =
{ tag : Maybe Tag
, author : Maybe Username
, favorited : Maybe Username
, limit : Int
, offset : Int
}
defaultListConfig : ListConfig
defaultListConfig =
{ tag = Nothing
, author = Nothing
, favorited = Nothing
, limit = 20
, offset = 0
}
list : ListConfig -> Maybe AuthToken -> Http.Request Feed
list config maybeToken =
[ ( "tag", Maybe.map Article.tagToString config.tag )
, ( "author", Maybe.map User.usernameToString config.author )
, ( "favorited", Maybe.map User.usernameToString config.favorited )
, ( "limit", Just (toString config.limit) )
, ( "offset", Just (toString config.offset) )
]
|> List.filterMap maybeVal
|> buildFromQueryParams "/articles"
|> withAuthorization maybeToken
|> HttpBuilder.toRequest
-- FEED --
type alias FeedConfig =
{ limit : Int
, offset : Int
}
defaultFeedConfig : FeedConfig
defaultFeedConfig =
{ limit = 10
, offset = 0
}
feed : FeedConfig -> AuthToken -> Http.Request Feed
feed config token =
[ ( "limit", Just (toString config.limit) )
, ( "offset", Just (toString config.offset) )
]
|> List.filterMap maybeVal
|> buildFromQueryParams "/articles/feed"
|> withAuthorization (Just token)
|> HttpBuilder.toRequest
-- TAGS --
tags : Http.Request (List Tag)
tags =
Decode.field "tags" (Decode.list Article.tagDecoder)
|> Http.get (apiUrl "/tags")
-- FAVORITE --
toggleFavorite : Article a -> AuthToken -> Http.Request (Article ())
toggleFavorite article authToken =
if article.favorited then
unfavorite article.slug authToken
else
favorite article.slug authToken
favorite : Article.Slug -> AuthToken -> Http.Request (Article ())
favorite =
buildFavorite HttpBuilder.post
unfavorite : Article.Slug -> AuthToken -> Http.Request (Article ())
unfavorite =
buildFavorite HttpBuilder.delete
buildFavorite :
(String -> RequestBuilder a)
-> Article.Slug
-> AuthToken
-> Http.Request (Article ())
buildFavorite builderFromUrl slug token =
let
expect =
Article.decoder
|> Decode.field "article"
|> Http.expectJson
in
[ apiUrl "/articles", slugToString slug, "favorite" ]
|> String.join "/"
|> builderFromUrl
|> withAuthorization (Just token)
|> withExpect expect
|> HttpBuilder.toRequest
-- CREATE --
type alias CreateConfig record =
{ record
| title : String
, description : String
, body : String
, tags : List String
}
type alias EditConfig record =
{ record
| title : String
, description : String
, body : String
}
create : CreateConfig record -> AuthToken -> Http.Request (Article Body)
create config token =
let
expect =
Article.decoderWithBody
|> Decode.field "article"
|> Http.expectJson
article =
Encode.object
[ ( "title", Encode.string config.title )
, ( "description", Encode.string config.description )
, ( "body", Encode.string config.body )
, ( "tagList", Encode.list (List.map Encode.string config.tags) )
]
body =
Encode.object [ ( "article", article ) ]
|> Http.jsonBody
in
apiUrl "/articles"
|> HttpBuilder.post
|> withAuthorization (Just token)
|> withBody body
|> withExpect expect
|> HttpBuilder.toRequest
update : Article.Slug -> EditConfig record -> AuthToken -> Http.Request (Article Body)
update slug config token =
let
expect =
Article.decoderWithBody
|> Decode.field "article"
|> Http.expectJson
article =
Encode.object
[ ( "title", Encode.string config.title )
, ( "description", Encode.string config.description )
, ( "body", Encode.string config.body )
]
body =
Encode.object [ ( "article", article ) ]
|> Http.jsonBody
in
apiUrl ("/articles/" ++ slugToString slug)
|> HttpBuilder.put
|> withAuthorization (Just token)
|> withBody body
|> withExpect expect
|> HttpBuilder.toRequest
-- DELETE --
delete : Article.Slug -> AuthToken -> Http.Request ()
delete slug token =
apiUrl ("/articles/" ++ Article.slugToString slug)
|> HttpBuilder.delete
|> withAuthorization (Just token)
|> HttpBuilder.toRequest
-- HELPERS --
maybeVal : ( a, Maybe b ) -> Maybe ( a, b )
maybeVal ( key, value ) =
case value of
Nothing ->
Nothing
Just val ->
Just ( key, val )
buildFromQueryParams : String -> List ( String, String ) -> RequestBuilder Feed
buildFromQueryParams url queryParams =
url
|> apiUrl
|> HttpBuilder.get
|> withExpect (Http.expectJson Feed.decoder)
|> withQueryParams queryParams

View File

@@ -0,0 +1,53 @@
module Request.Article.Comments exposing (delete, list, post)
import Data.Article as Article exposing (Article, Tag, slugToString)
import Data.Article.Comment as Comment exposing (Comment, CommentId)
import Data.AuthToken exposing (AuthToken, withAuthorization)
import Http
import HttpBuilder exposing (RequestBuilder, withExpect, withQueryParams)
import Json.Decode as Decode
import Json.Encode as Encode exposing (Value)
import Request.Helpers exposing (apiUrl)
-- LIST --
list : Maybe AuthToken -> Article.Slug -> Http.Request (List Comment)
list maybeToken slug =
apiUrl ("/articles/" ++ Article.slugToString slug ++ "/comments")
|> HttpBuilder.get
|> HttpBuilder.withExpect (Http.expectJson (Decode.field "comments" (Decode.list Comment.decoder)))
|> withAuthorization maybeToken
|> HttpBuilder.toRequest
-- POST --
post : Article.Slug -> String -> AuthToken -> Http.Request Comment
post slug body token =
apiUrl ("/articles/" ++ Article.slugToString slug ++ "/comments")
|> HttpBuilder.post
|> HttpBuilder.withBody (Http.jsonBody (encodeCommentBody body))
|> HttpBuilder.withExpect (Http.expectJson (Decode.field "comment" Comment.decoder))
|> withAuthorization (Just token)
|> HttpBuilder.toRequest
encodeCommentBody : String -> Value
encodeCommentBody body =
Encode.object [ ( "comment", Encode.object [ ( "body", Encode.string body ) ] ) ]
-- DELETE --
delete : Article.Slug -> CommentId -> AuthToken -> Http.Request ()
delete slug commentId token =
apiUrl ("/articles/" ++ Article.slugToString slug ++ "/comments/" ++ Comment.idToString commentId)
|> HttpBuilder.delete
|> withAuthorization (Just token)
|> HttpBuilder.toRequest

View File

@@ -0,0 +1,6 @@
module Request.Helpers exposing (apiUrl)
apiUrl : String -> String
apiUrl str =
"http://localhost:3000/api" ++ str

View File

@@ -0,0 +1,57 @@
module Request.Profile exposing (get, toggleFollow)
import Data.AuthToken exposing (AuthToken, withAuthorization)
import Data.Profile as Profile exposing (Profile)
import Data.User as User exposing (Username)
import Http
import HttpBuilder exposing (RequestBuilder, withExpect, withQueryParams)
import Json.Decode as Decode
import Request.Helpers exposing (apiUrl)
-- GET --
get : Username -> Maybe AuthToken -> Http.Request Profile
get username maybeToken =
apiUrl ("/profiles/" ++ User.usernameToString username)
|> HttpBuilder.get
|> HttpBuilder.withExpect (Http.expectJson (Decode.field "profile" Profile.decoder))
|> withAuthorization maybeToken
|> HttpBuilder.toRequest
-- FOLLOWING --
toggleFollow : Username -> Bool -> AuthToken -> Http.Request Profile
toggleFollow username following authToken =
if following then
unfollow username authToken
else
follow username authToken
follow : Username -> AuthToken -> Http.Request Profile
follow =
buildFollow HttpBuilder.post
unfollow : Username -> AuthToken -> Http.Request Profile
unfollow =
buildFollow HttpBuilder.delete
buildFollow :
(String -> RequestBuilder a)
-> Username
-> AuthToken
-> Http.Request Profile
buildFollow builderFromUrl username token =
[ apiUrl "/profiles", User.usernameToString username, "follow" ]
|> String.join "/"
|> builderFromUrl
|> withAuthorization (Just token)
|> withExpect (Http.expectJson (Decode.field "profile" Profile.decoder))
|> HttpBuilder.toRequest

View File

@@ -0,0 +1,94 @@
module Request.User exposing (edit, login, register, storeSession)
import Data.AuthToken exposing (AuthToken, withAuthorization)
import Data.User as User exposing (User)
import Http
import HttpBuilder exposing (RequestBuilder, withExpect, withQueryParams)
import Json.Decode as Decode
import Json.Encode as Encode
import Json.Encode.Extra as EncodeExtra
import Ports
import Request.Helpers exposing (apiUrl)
storeSession : User -> Cmd msg
storeSession user =
User.encode user
|> Encode.encode 0
|> Just
|> Ports.storeSession
login : { r | email : String, password : String } -> Http.Request User
login { email, password } =
let
user =
Encode.object
[ ( "email", Encode.string email )
, ( "password", Encode.string password )
]
body =
Encode.object [ ( "user", user ) ]
|> Http.jsonBody
in
Decode.field "user" User.decoder
|> Http.post (apiUrl "/users/login") body
register : { r | username : String, email : String, password : String } -> Http.Request User
register { username, email, password } =
let
user =
Encode.object
[ ( "username", Encode.string username )
, ( "email", Encode.string email )
, ( "password", Encode.string password )
]
body =
Encode.object [ ( "user", user ) ]
|> Http.jsonBody
in
Decode.field "user" User.decoder
|> Http.post (apiUrl "/users") body
edit :
{ r
| username : String
, email : String
, bio : String
, password : Maybe String
, image : Maybe String
}
-> Maybe AuthToken
-> Http.Request User
edit { username, email, bio, password, image } maybeToken =
let
updates =
[ Just ( "username", Encode.string username )
, Just ( "email", Encode.string email )
, Just ( "bio", Encode.string bio )
, Just ( "image", EncodeExtra.maybe Encode.string image )
, Maybe.map (\pass -> ( "password", Encode.string pass )) password
]
|> List.filterMap identity
body =
( "user", Encode.object updates )
|> List.singleton
|> Encode.object
|> Http.jsonBody
expect =
User.decoder
|> Decode.field "user"
|> Http.expectJson
in
apiUrl "/user"
|> HttpBuilder.put
|> HttpBuilder.withExpect expect
|> HttpBuilder.withBody body
|> withAuthorization maybeToken
|> HttpBuilder.toRequest