Finish /login API endpoint

4-compiler-bug
Bram 2024-05-24 15:15:44 +02:00
parent c84bb2a1ef
commit 3b0b3264de
4 changed files with 827 additions and 9 deletions

View File

@ -1,4 +1,4 @@
module Internal.Api.LoginWithUsernameAndPassword.Api exposing (Phantom)
module Internal.Api.LoginWithUsernameAndPassword.Api exposing (Phantom, loginWithUsernameAndPassword)
{-|
@ -7,24 +7,52 @@ module Internal.Api.LoginWithUsernameAndPassword.Api exposing (Phantom)
This module allows the user to log in using a username and password.
@docs Phantom
@docs Phantom, loginWithUsernameAndPassword
-}
import Internal.Api.Api as A
import Internal.Api.Request as R
import Internal.Config.Leaks as L
import Internal.Tools.Json as Json
import Internal.Values.Context as Context
import Internal.Values.Envelope as E
import Internal.Values.User as User exposing (User)
import Internal.Values.Vault as V
import Json.Encode as E
loginWithUsernameAndPassword : LoginWithUsernameAndPasswordInput -> A.TaskChain (Phantom a) (Phantom { a | accessToken : () })
loginWithUsernameAndPassword =
A.startWithVersion "r0.0.0" loginWithUsernameAndPasswordV1
|> A.sameForVersion "r0.0.1"
|> A.sameForVersion "r0.1.0"
|> A.sameForVersion "r0.2.0"
|> A.forVersion "r0.3.0" loginWithUsernameAndPasswordV2
|> A.forVersion "r0.4.0" loginWithUsernameAndPasswordV3
|> A.forVersion "r0.5.0" loginWithUsernameAndPasswordV4
|> A.sameForVersion "r0.6.0"
|> A.sameForVersion "r0.6.1"
|> A.forVersion "v1.1" loginWithUsernameAndPasswordV5
|> A.sameForVersion "v1.2"
|> A.forVersion "v1.3" loginWithUsernameAndPasswordV6
|> A.forVersion "v1.4" loginWithUsernameAndPasswordV7
|> A.sameForVersion "v1.5"
|> A.sameForVersion "v1.6"
|> A.sameForVersion "v1.7"
|> A.sameForVersion "v1.8"
|> A.sameForVersion "v1.9"
|> A.sameForVersion "v1.10"
|> A.versionChain
type alias Phantom a =
{ a | baseUrl : (), versions : () }
type alias LoginWithUsernameAndPassword =
type alias LoginWithUsernameAndPasswordInput =
{ deviceId : Maybe String
, enableRefreshToken : Maybe Bool
, initialDeviceDisplayName : Maybe String
, password : String
, username : String
@ -47,25 +75,96 @@ type alias LoginWithUsernameAndPasswordInputV2 a =
}
type alias LoginWithUsernameAndPasswordInputV3 a =
{ a
| deviceId : Maybe String
, enableRefreshToken : Maybe Bool
, initialDeviceDisplayName : Maybe String
, password : String
, username : String
}
type alias LoginWithUsernameAndPasswordOutputV1 =
{ accessToken : String
{ accessToken : String -- Even though it is not required, we do not want it to be omitted.
, homeserver : String
, refreshToken : Maybe String
, user : User
, user : Maybe User
}
type alias LoginWithUsernameAndPasswordOutputV2 =
{ accessToken : String -- Even though it is not required, we do not want it to be omitted.
, deviceId : Maybe String
, homeserver : String
, user : Maybe User
}
type alias LoginWithUsernameAndPasswordOutputV3 =
{ accessToken : String -- Even though it is not required, we do not want it to be omitted.
, deviceId : Maybe String
, homeserver : Maybe String
, user : Maybe User
}
type alias LoginWithUsernameAndPasswordOutputV4 =
{ accessToken : String -- Even though it is not required, we do not want it to be omitted.
, deviceId : Maybe String
, homeserver : Maybe String
, user : Maybe User
, wellKnown : Maybe DiscoveryInformationV1
}
type alias LoginWithUsernameAndPasswordOutputV5 =
{ accessToken : String -- Even though it is not required, we do not want it to be omitted.
, deviceId : Maybe String
, expiresInMs : Maybe Int
, homeserver : Maybe String
, refreshToken : Maybe String
, user : Maybe User
, wellKnown : Maybe DiscoveryInformationV1
}
type alias LoginWithUsernameAndPasswordOutputV6 =
{ accessToken : String
, deviceId : String
, expiresInMs : Maybe Int
, homeserver : Maybe String
, refreshToken : Maybe String
, user : User
, wellKnown : Maybe DiscoveryInformationV1
}
type alias DiscoveryInformationV1 =
{ homeserver : HomeserverInformation
, identityServer : Maybe IdentityServerInformation
}
type alias HomeserverInformation =
{ baseUrl : String }
type alias IdentityServerInformation =
{ baseUrl : String }
type alias PhantomV1 a =
{ a | baseUrl : (), now : () }
loginWithUsernameAndPasswordV1 : LoginWithUsernameAndPasswordInputV1 a -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
loginWithUsernameAndPasswordV1 : LoginWithUsernameAndPasswordInputV1 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
loginWithUsernameAndPasswordV1 { username, password } context =
A.request
{ attributes =
[ R.bodyString "password" password
, R.bodyString "type" "m.login.password"
, R.bodyString "username" username
, R.bodyString "user" username
, R.onStatusCode 400 "M_UNKNOWN"
, R.onStatusCode 403 "M_FORBIDDEN"
]
@ -84,6 +183,304 @@ loginWithUsernameAndPasswordV1 { username, password } context =
, refresh = out.refreshToken
, value = out.accessToken
}
, out.user
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|> E.Optional
]
, []
)
}
context
loginWithUsernameAndPasswordV2 : LoginWithUsernameAndPasswordInputV2 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
loginWithUsernameAndPasswordV2 { deviceId, initialDeviceDisplayName, username, password } context =
A.request
{ attributes =
[ R.bodyOpString "device_id" deviceId
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, R.bodyString "password" password
, R.bodyString "type" "m.login.password"
, R.bodyString "user" username
, R.onStatusCode 400 "M_UNKNOWN"
, R.onStatusCode 403 "M_FORBIDDEN"
, R.onStatusCode 429 "string" -- Yup. That's what it says.
]
, coder = coderV2
, method = "POST"
, path = [ "_matrix", "client", "r0", "login" ]
, contextChange =
\out -> Context.setAccessToken out.accessToken
, toUpdate =
\out ->
( E.More
[ E.SetAccessToken
{ created = Context.getNow context
, expiryMs = Nothing
, lastUsed = Context.getNow context
, refresh = Nothing
, value = out.accessToken
}
, out.user
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|> E.Optional
, out.deviceId
|> Maybe.map E.SetDeviceId
|> E.Optional
]
, []
)
}
context
loginWithUsernameAndPasswordV3 : LoginWithUsernameAndPasswordInputV2 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
loginWithUsernameAndPasswordV3 { deviceId, initialDeviceDisplayName, username, password } context =
A.request
{ attributes =
[ R.bodyOpString "address" Nothing
, R.bodyOpString "device_id" deviceId
, R.bodyValue "identifier"
(E.object
[ ( "type", E.string "m.id.user" )
, ( "user", E.string username )
]
)
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, R.bodyString "password" password
, R.bodyString "type" "m.login.password"
, R.bodyString "user" username
, R.onStatusCode 400 "M_UNKNOWN"
, R.onStatusCode 403 "M_FORBIDDEN"
, R.onStatusCode 429 "M_LIMIT_EXCEEDED"
]
, coder = coderV3
, method = "POST"
, path = [ "_matrix", "client", "r0", "login" ]
, contextChange =
\out -> Context.setAccessToken out.accessToken
, toUpdate =
\out ->
( E.More
[ E.SetAccessToken
{ created = Context.getNow context
, expiryMs = Nothing
, lastUsed = Context.getNow context
, refresh = Nothing
, value = out.accessToken
}
, out.user
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|> E.Optional
, out.deviceId
|> Maybe.map E.SetDeviceId
|> E.Optional
]
, []
)
}
context
loginWithUsernameAndPasswordV4 : LoginWithUsernameAndPasswordInputV2 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
loginWithUsernameAndPasswordV4 { deviceId, initialDeviceDisplayName, username, password } context =
A.request
{ attributes =
[ R.bodyOpString "address" Nothing
, R.bodyOpString "device_id" deviceId
, R.bodyValue "identifier"
(E.object
[ ( "type", E.string "m.id.user" )
, ( "user", E.string username )
]
)
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, R.bodyString "password" password
, R.bodyString "type" "m.login.password"
, R.bodyString "user" username
, R.onStatusCode 400 "M_UNKNOWN"
, R.onStatusCode 403 "M_FORBIDDEN"
, R.onStatusCode 429 "M_LIMIT_EXCEEDED"
]
, coder = coderV4
, method = "POST"
, path = [ "_matrix", "client", "r0", "login" ]
, contextChange =
\out -> Context.setAccessToken out.accessToken
, toUpdate =
\out ->
( E.More
[ E.SetAccessToken
{ created = Context.getNow context
, expiryMs = Nothing
, lastUsed = Context.getNow context
, refresh = Nothing
, value = out.accessToken
}
, out.user
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|> E.Optional
, out.wellKnown
|> Maybe.map (.homeserver >> .baseUrl)
|> Maybe.map E.SetBaseUrl
|> E.Optional
, out.deviceId
|> Maybe.map E.SetDeviceId
|> E.Optional
]
, []
)
}
context
loginWithUsernameAndPasswordV5 : LoginWithUsernameAndPasswordInputV2 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
loginWithUsernameAndPasswordV5 { deviceId, initialDeviceDisplayName, username, password } context =
A.request
{ attributes =
[ R.bodyOpString "address" Nothing
, R.bodyOpString "device_id" deviceId
, R.bodyValue "identifier"
(E.object
[ ( "type", E.string "m.id.user" )
, ( "user", E.string username )
]
)
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, R.bodyString "password" password
, R.bodyString "type" "m.login.password"
, R.bodyString "user" username
, R.onStatusCode 400 "M_UNKNOWN"
, R.onStatusCode 403 "M_FORBIDDEN"
, R.onStatusCode 429 "M_LIMIT_EXCEEDED"
]
, coder = coderV4
, method = "POST"
, path = [ "_matrix", "client", "v3", "login" ]
, contextChange =
\out -> Context.setAccessToken out.accessToken
, toUpdate =
\out ->
( E.More
[ E.SetAccessToken
{ created = Context.getNow context
, expiryMs = Nothing
, lastUsed = Context.getNow context
, refresh = Nothing
, value = out.accessToken
}
, out.user
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|> E.Optional
, out.wellKnown
|> Maybe.map (.homeserver >> .baseUrl)
|> Maybe.map E.SetBaseUrl
|> E.Optional
, out.deviceId
|> Maybe.map E.SetDeviceId
|> E.Optional
]
, []
)
}
context
loginWithUsernameAndPasswordV6 : LoginWithUsernameAndPasswordInputV3 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
loginWithUsernameAndPasswordV6 { deviceId, enableRefreshToken, initialDeviceDisplayName, username, password } context =
A.request
{ attributes =
[ R.bodyOpString "address" Nothing
, R.bodyOpString "device_id" deviceId
, R.bodyValue "identifier"
(E.object
[ ( "type", E.string "m.id.user" )
, ( "user", E.string username )
]
)
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, R.bodyString "password" password
, R.bodyOpBool "refresh_token" enableRefreshToken
, R.bodyString "type" "m.login.password"
, R.bodyString "user" username
, R.onStatusCode 400 "M_UNKNOWN"
, R.onStatusCode 403 "M_FORBIDDEN"
, R.onStatusCode 429 "M_LIMIT_EXCEEDED"
]
, coder = coderV5
, method = "POST"
, path = [ "_matrix", "client", "v3", "login" ]
, contextChange =
\out -> Context.setAccessToken out.accessToken
, toUpdate =
\out ->
( E.More
[ E.SetAccessToken
{ created = Context.getNow context
, expiryMs = out.expiresInMs
, lastUsed = Context.getNow context
, refresh = out.refreshToken
, value = out.accessToken
}
, out.user
|> Maybe.map (V.SetUser >> E.ContentUpdate)
|> E.Optional
, out.wellKnown
|> Maybe.map (.homeserver >> .baseUrl)
|> Maybe.map E.SetBaseUrl
|> E.Optional
, out.deviceId
|> Maybe.map E.SetDeviceId
|> E.Optional
]
, []
)
}
context
loginWithUsernameAndPasswordV7 : LoginWithUsernameAndPasswordInputV3 i -> A.TaskChain (PhantomV1 a) (PhantomV1 { a | accessToken : () })
loginWithUsernameAndPasswordV7 { deviceId, enableRefreshToken, initialDeviceDisplayName, username, password } context =
A.request
{ attributes =
[ R.bodyOpString "address" Nothing
, R.bodyOpString "device_id" deviceId
, R.bodyValue "identifier"
(E.object
[ ( "type", E.string "m.id.user" )
, ( "user", E.string username )
]
)
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, R.bodyString "password" password
, R.bodyOpBool "refresh_token" enableRefreshToken
, R.bodyString "type" "m.login.password"
, R.bodyString "user" username
, R.onStatusCode 400 "M_UNKNOWN"
, R.onStatusCode 403 "M_FORBIDDEN"
, R.onStatusCode 429 "M_LIMIT_EXCEEDED"
]
, coder = coderV6
, method = "POST"
, path = [ "_matrix", "client", "v3", "login" ]
, contextChange =
\out -> Context.setAccessToken out.accessToken
, toUpdate =
\out ->
( E.More
[ E.SetAccessToken
{ created = Context.getNow context
, expiryMs = out.expiresInMs
, lastUsed = Context.getNow context
, refresh = out.refreshToken
, value = out.accessToken
}
, E.ContentUpdate (V.SetUser out.user)
, out.wellKnown
|> Maybe.map (.homeserver >> .baseUrl)
|> Maybe.map E.SetBaseUrl
|> E.Optional
, E.SetDeviceId out.deviceId
]
, []
)
@ -128,6 +525,300 @@ coderV1 =
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "user_id"
, toField = .user
, description =
[ "The fully-qualified Matrix ID that has been registered."
]
, coder = User.coder
}
)
coderV2 : Json.Coder LoginWithUsernameAndPasswordOutputV2
coderV2 =
Json.object4
{ name = "Login Response"
, description =
[ "Authenticates the user by password, and issues an access token they can use to authorize themself in subsequent requests."
, "https://spec.matrix.org/legacy/client_server/r0.3.0.html#post-matrix-client-r0-login"
]
, init = LoginWithUsernameAndPasswordOutputV2
}
(Json.field.required
{ fieldName = "access_token"
, toField = .accessToken
, description =
[ "An access token for the account. This access token can then be used to authorize other requests."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "device_id"
, toField = .deviceId
, description =
[ "ID of the logged-in device. Will be the same as the corresponding parameter in the request, if one was specified."
]
, coder = Json.string
}
)
(Json.field.required
{ fieldName = "home_server"
, toField = .homeserver
, description =
[ "The hostname of the homeserver on which the account has been registered."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "user_id"
, toField = .user
, description =
[ "The fully-qualified Matrix ID that has been registered."
]
, coder = User.coder
}
)
coderV3 : Json.Coder LoginWithUsernameAndPasswordOutputV3
coderV3 =
Json.object4
{ name = "Login Response"
, description =
[ "Authenticates the user by password, and issues an access token they can use to authorize themself in subsequent requests."
, "https://spec.matrix.org/legacy/client_server/r0.3.0.html#post-matrix-client-r0-login"
]
, init = LoginWithUsernameAndPasswordOutputV3
}
(Json.field.required
{ fieldName = "access_token"
, toField = .accessToken
, description =
[ "An access token for the account. This access token can then be used to authorize other requests."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "device_id"
, toField = .deviceId
, description =
[ "ID of the logged-in device. Will be the same as the corresponding parameter in the request, if one was specified."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "home_server"
, toField = .homeserver
, description =
[ "The hostname of the homeserver on which the account has been registered."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "user_id"
, toField = .user
, description =
[ "The fully-qualified Matrix ID that has been registered."
]
, coder = User.coder
}
)
coderV4 : Json.Coder LoginWithUsernameAndPasswordOutputV4
coderV4 =
Json.object5
{ name = "Login Response"
, description =
[ "Authenticates the user by password, and issues an access token they can use to authorize themself in subsequent requests."
, "https://spec.matrix.org/legacy/client_server/r0.5.0.html#post-matrix-client-r0-login"
]
, init = LoginWithUsernameAndPasswordOutputV4
}
(Json.field.required
{ fieldName = "access_token"
, toField = .accessToken
, description =
[ "An access token for the account. This access token can then be used to authorize other requests."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "device_id"
, toField = .deviceId
, description =
[ "ID of the logged-in device. Will be the same as the corresponding parameter in the request, if one was specified."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "home_server"
, toField = .homeserver
, description =
[ "The hostname of the homeserver on which the account has been registered."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "user_id"
, toField = .user
, description =
[ "The fully-qualified Matrix ID that has been registered."
]
, coder = User.coder
}
)
(Json.field.optional.value
{ fieldName = "well_known"
, toField = .wellKnown
, description =
[ "Optional client configuration provided by the server. If present, clients SHOULD use the provided object to reconfigure themselves, optionally validating the URLs within. This object takes the same form as the one returned from .well-known autodiscovery."
]
, coder = disoveryInformationCoderV1
}
)
coderV5 : Json.Coder LoginWithUsernameAndPasswordOutputV5
coderV5 =
Json.object7
{ name = "Login Response"
, description =
[ "Authenticates the user by password, and issues an access token they can use to authorize themself in subsequent requests."
, "https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3login"
]
, init = LoginWithUsernameAndPasswordOutputV5
}
(Json.field.required
{ fieldName = "access_token"
, toField = .accessToken
, description =
[ "An access token for the account. This access token can then be used to authorize other requests."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "device_id"
, toField = .deviceId
, description =
[ "ID of the logged-in device. Will be the same as the corresponding parameter in the request, if one was specified."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "expires_in_ms"
, toField = .expiresInMs
, description =
[ "The lifetime of the access token, in milliseconds. Once the access token has expired a new access token can be obtained by using the provided refresh token. If no refresh token is provided, the client will need to re-log in to obtain a new access token. If not given, the client can assume that the access token will not expire. "
]
, coder = Json.int
}
)
(Json.field.optional.value
{ fieldName = "home_server"
, toField = .homeserver
, description =
[ "The hostname of the homeserver on which the account has been registered."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "refresh_token"
, toField = .refreshToken
, description =
[ "A refresh token for the account. This token can be used to obtain a new access token when it expires by calling the /refresh endpoint."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "user_id"
, toField = .user
, description =
[ "The fully-qualified Matrix ID that has been registered."
]
, coder = User.coder
}
)
(Json.field.optional.value
{ fieldName = "well_known"
, toField = .wellKnown
, description =
[ "Optional client configuration provided by the server. If present, clients SHOULD use the provided object to reconfigure themselves, optionally validating the URLs within. This object takes the same form as the one returned from .well-known autodiscovery."
]
, coder = disoveryInformationCoderV1
}
)
coderV6 : Json.Coder LoginWithUsernameAndPasswordOutputV6
coderV6 =
Json.object7
{ name = "Login Response"
, description =
[ "Authenticates the user by password, and issues an access token they can use to authorize themself in subsequent requests."
, "https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3login"
]
, init = LoginWithUsernameAndPasswordOutputV6
}
(Json.field.required
{ fieldName = "access_token"
, toField = .accessToken
, description =
[ "An access token for the account. This access token can then be used to authorize other requests."
]
, coder = Json.string
}
)
(Json.field.required
{ fieldName = "device_id"
, toField = .deviceId
, description =
[ "ID of the logged-in device. Will be the same as the corresponding parameter in the request, if one was specified."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "expires_in_ms"
, toField = .expiresInMs
, description =
[ "The lifetime of the access token, in milliseconds. Once the access token has expired a new access token can be obtained by using the provided refresh token. If no refresh token is provided, the client will need to re-log in to obtain a new access token. If not given, the client can assume that the access token will not expire. "
]
, coder = Json.int
}
)
(Json.field.optional.value
{ fieldName = "home_server"
, toField = .homeserver
, description =
[ "The hostname of the homeserver on which the account has been registered."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "refresh_token"
, toField = .refreshToken
, description =
[ "A refresh token for the account. This token can be used to obtain a new access token when it expires by calling the /refresh endpoint."
]
, coder = Json.string
}
)
(Json.field.required
{ fieldName = "user_id"
, toField = .user
@ -137,3 +828,97 @@ coderV1 =
, coder = User.coder
}
)
(Json.field.optional.value
{ fieldName = "well_known"
, toField = .wellKnown
, description =
[ "Optional client configuration provided by the server. If present, clients SHOULD use the provided object to reconfigure themselves, optionally validating the URLs within. This object takes the same form as the one returned from .well-known autodiscovery."
]
, coder = disoveryInformationCoderV1
}
)
disoveryInformationCoderV1 : Json.Coder DiscoveryInformationV1
disoveryInformationCoderV1 =
Json.object2
{ name = "Discovery Information"
, description =
[ "Gets discovery information about the domain. The file may include additional keys, which MUST follow the Java package naming convention, e.g. com.example.myapp.property. This ensures property names are suitably namespaced for each application and reduces the risk of clashes."
, "Note that this endpoint is not necessarily handled by the homeserver, but by another webserver, to be used for discovering the homeserver URL."
, "https://spec.matrix.org/v1.10/client-server-api/#getwell-knownmatrixclient"
]
, init = DiscoveryInformationV1
}
(Json.field.required
{ fieldName = "m.homeserver"
, toField = .homeserver
, coder =
Json.object2
{ name = "Homeserver Information"
, description =
[ "Used by clients to discover homeserver information."
]
, init = \a _ -> { baseUrl = a }
}
(Json.field.required
{ fieldName = "base_url"
, toField = .baseUrl
, description =
[ "The base URL for the homeserver for client-server connections."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = L.field
, toField = always Nothing
, description =
[ "The Elm SDK always expects objects to have at least two fields."
, "Otherwise, what's the point of hiding the value in an object?"
, "For this reason, this empty placeholder key will always be ignored."
]
, coder = Json.value
}
)
, description =
[ "Used by clients to discover homeserver information."
]
}
)
(Json.field.optional.value
{ fieldName = "m.identity_server"
, toField = .identityServer
, coder =
Json.object2
{ name = "Homeserver Information"
, description =
[ "Used by clients to discover homeserver information."
]
, init = \a _ -> { baseUrl = a }
}
(Json.field.required
{ fieldName = "base_url"
, toField = .baseUrl
, description =
[ "The base URL for the homeserver for client-server connections."
]
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = L.field
, toField = always Nothing
, description =
[ "The Elm SDK always expects objects to have at least two fields."
, "Otherwise, what's the point of hiding the value in an object?"
, "For this reason, this empty placeholder key will always be ignored."
]
, coder = Json.value
}
)
, description =
[ "Used by clients to discover identity server information."
]
}
)

View File

@ -83,6 +83,7 @@ static and hence can be passed on easily.
type alias Context =
{ accessTokens : Hashdict AccessToken
, baseUrl : Maybe String
, deviceId : Maybe String
, now : Maybe Timestamp
, password : Maybe String
, refreshToken : Maybe String
@ -139,7 +140,7 @@ fromApiFormat (APIContext c) =
-}
coder : Json.Coder Context
coder =
Json.object9
Json.object10
{ name = Text.docs.context.name
, description = Text.docs.context.description
, init = Context
@ -158,6 +159,13 @@ coder =
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "deviceId"
, toField = .deviceId
, description = Debug.todo "Needs docs"
, coder = Json.string
}
)
(Json.field.optional.value
{ fieldName = "now"
, toField = .now
@ -275,6 +283,7 @@ init : String -> Context
init sn =
{ accessTokens = Hashdict.empty .value
, baseUrl = Nothing
, deviceId = Nothing
, now = Nothing
, refreshToken = Nothing
, password = Nothing

View File

@ -75,9 +75,11 @@ type EnvelopeUpdate a
= ContentUpdate a
| HttpRequest (Request.Request ( Request.Error, List Log ) ( EnvelopeUpdate a, List Log ))
| More (List (EnvelopeUpdate a))
| Optional (Maybe (EnvelopeUpdate a))
| RemoveAccessToken String
| SetAccessToken AccessToken
| SetBaseUrl String
| SetDeviceId String
| SetRefreshToken String
| SetVersions Versions
@ -298,6 +300,12 @@ update updateContent eu ({ context } as data) =
More items ->
List.foldl (update updateContent) data items
Optional (Just u) ->
update updateContent u data
Optional Nothing ->
data
RemoveAccessToken token ->
{ data | context = { context | accessTokens = Hashdict.removeKey token context.accessTokens } }
@ -307,6 +315,9 @@ update updateContent eu ({ context } as data) =
SetBaseUrl b ->
{ data | context = { context | baseUrl = Just b } }
SetDeviceId d ->
{ data | context = { context | deviceId = Just d } }
SetRefreshToken r ->
{ data | context = { context | refreshToken = Just r } }

View File

@ -39,6 +39,7 @@ import Internal.Config.Text as Text
import Internal.Tools.Hashdict as Hashdict exposing (Hashdict)
import Internal.Tools.Json as Json
import Internal.Values.Room as Room exposing (Room)
import Internal.Values.User as User exposing (User)
{-| This is the Vault type.
@ -46,6 +47,7 @@ import Internal.Values.Room as Room exposing (Room)
type alias Vault =
{ accountData : Dict String Json.Value
, rooms : Hashdict Room
, user : User
}
@ -57,11 +59,12 @@ type VaultUpdate
| MapRoom String Room.RoomUpdate
| More (List VaultUpdate)
| SetAccountData String Json.Value
| SetUser User
coder : Json.Coder Vault
coder =
Json.object2
Json.object3
{ name = Text.docs.vault.name
, description = Text.docs.vault.description
, init = Vault
@ -80,6 +83,13 @@ coder =
, coder = Hashdict.coder .roomId Room.coder
}
)
(Json.field.required
{ fieldName = "user"
, toField = .user
, description = Debug.todo "Needs description"
, coder = User.coder
}
)
{-| Get a given room by its room id.
@ -136,3 +146,6 @@ update vu vault =
SetAccountData key value ->
setAccountData key value vault
SetUser user ->
{ vault | user = user }