Update login for all spec versions

The currently officially supported/legacy spec versions, at least.
pull/1/head
Bram van den Heuvel 2023-03-19 16:45:56 +01:00
parent 5dfd95196b
commit e0086daa59
23 changed files with 827 additions and 182 deletions

View File

@ -219,7 +219,13 @@ def main(in_file, out_file):
@property @property
def encoder(self): def encoder(self):
if self.required or self.default is not None: if self.required == 'never':
return 'Nothing'
elif self.required == 'now':
return (
'Maybe.map ' + encapsulate(self.field.encoder) + ' data.' + self.elm_name
)
elif self.required or self.default is not None:
return ( return (
'Just <| ' + self.field.encoder + ' data.' + self.elm_name 'Just <| ' + self.field.encoder + ' data.' + self.elm_name
) )
@ -232,7 +238,11 @@ def main(in_file, out_file):
@property @property
def decoder(self): def decoder(self):
if self.required: if self.required == 'never':
return 'D.succeed Nothing'
elif self.required == 'now':
field = f'D.map Just <| D.field "{self.key}"'
elif self.required:
field = f'D.field "{self.key}"' field = f'D.field "{self.key}"'
elif self.default is None: elif self.default is None:
field = f'opField "{self.key}"' field = f'opField "{self.key}"'
@ -243,7 +253,9 @@ def main(in_file, out_file):
@property @property
def type_definition(self): def type_definition(self):
if self.required or self.default is not None: if self.required in ['now', 'never']:
return 'Maybe ' + encapsulate(self.field.type_name)
elif self.required or self.default is not None:
return self.field.type_name return self.field.type_name
else: else:
return 'Maybe ' + encapsulate(self.field.type_name) return 'Maybe ' + encapsulate(self.field.type_name)
@ -330,11 +342,11 @@ def main(in_file, out_file):
if 'Dict' in content: if 'Dict' in content:
write("import Dict exposing (Dict)\n") write("import Dict exposing (Dict)\n")
if 'opField' in content and 'opFieldWithDefault' in content: if 'opField ' in content and 'opFieldWithDefault ' in content:
write("import Internal.Tools.DecodeExtra exposing (opField, opFieldWithDefault)\n") write("import Internal.Tools.DecodeExtra exposing (opField, opFieldWithDefault)\n")
elif 'opFieldWithDefault' in content: elif 'opFieldWithDefault ' in content:
write("import Internal.Tools.DecodeExtra exposing (opField)\n") write("import Internal.Tools.DecodeExtra exposing (opFieldWithDefault)\n")
elif 'opField' in content: elif 'opField ' in content:
write("import Internal.Tools.DecodeExtra exposing (opField)\n") write("import Internal.Tools.DecodeExtra exposing (opField)\n")
if 'maybeObject' in content: if 'maybeObject' in content:

View File

@ -1,6 +1,10 @@
module Internal.Api.LoginWithUsernameAndPassword.Api exposing (..) module Internal.Api.LoginWithUsernameAndPassword.Api exposing (..)
import Internal.Api.LoginWithUsernameAndPassword.V1.Login as SO import Internal.Api.LoginWithUsernameAndPassword.V1.Login as SO1
import Internal.Api.LoginWithUsernameAndPassword.V2.SpecObjects as SO2
import Internal.Api.LoginWithUsernameAndPassword.V3.SpecObjects as SO3
import Internal.Api.LoginWithUsernameAndPassword.V4.SpecObjects as SO4
import Internal.Api.LoginWithUsernameAndPassword.V5.Login as SO5
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Tools.Context exposing (Context) import Internal.Tools.Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
@ -14,20 +18,138 @@ type alias LoginWithUsernameAndPasswordInputV1 =
} }
type alias LoginWithUsernameAndPasswordInputV2 =
{ deviceId : Maybe String
, initialDeviceDisplayName : Maybe String
, password : String
, username : String
}
type alias LoginWithUsernameAndPasswordOutputV1 = type alias LoginWithUsernameAndPasswordOutputV1 =
SO.LoggedInResponse SO1.LoggedInResponse
type alias LoginWithUsernameAndPasswordOutputV2 =
SO2.LoggedInResponse
type alias LoginWithUsernameAndPasswordOutputV3 =
SO3.LoggedInResponse
type alias LoginWithUsernameAndPasswordOutputV4 =
SO4.LoggedInResponse
type alias LoginWithUsernameAndPasswordOutputV5 =
SO5.LoggedInResponse
loginWithUsernameAndPasswordV1 : LoginWithUsernameAndPasswordInputV1 -> Context { a | baseUrl : () } -> Task X.Error LoginWithUsernameAndPasswordOutputV1 loginWithUsernameAndPasswordV1 : LoginWithUsernameAndPasswordInputV1 -> Context { a | baseUrl : () } -> Task X.Error LoginWithUsernameAndPasswordOutputV1
loginWithUsernameAndPasswordV1 { username, password } = loginWithUsernameAndPasswordV1 { username, password } =
R.callApi "POST" "/_matrix/client/v3/login" R.callApi "POST" "/_matrix/client/r0/login"
>> R.withAttributes >> R.withAttributes
[ [ ( "type", E.string "m.id.user" ) [ R.bodyString "password" password
, R.bodyString "type" "m.login.password"
, R.bodyString "user" username
]
>> R.toTask SO1.loggedInResponseDecoder
loginWithUsernameAndPasswordV2 : LoginWithUsernameAndPasswordInputV2 -> Context { a | baseUrl : () } -> Task X.Error LoginWithUsernameAndPasswordOutputV2
loginWithUsernameAndPasswordV2 { deviceId, initialDeviceDisplayName, password, username } =
R.callApi "POST" "/_matrix/client/r0/login"
>> R.withAttributes
[ R.bodyString "type" "m.login.password"
, R.bodyString "user" username
, R.bodyString "password" password
, R.bodyOpString "device_id" deviceId
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
]
>> R.toTask SO2.loggedInResponseDecoder
loginWithUsernameAndPasswordV3 : LoginWithUsernameAndPasswordInputV2 -> Context { a | baseUrl : () } -> Task X.Error LoginWithUsernameAndPasswordOutputV3
loginWithUsernameAndPasswordV3 { deviceId, initialDeviceDisplayName, password, username } =
R.callApi "POST" "/_matrix/client/r0/login"
>> R.withAttributes
[ R.bodyString "type" "m.login.password"
, R.bodyString "password" password
, R.bodyOpString "device_id" deviceId
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, [ ( "type", E.string "m.id.user" )
, ( "user", E.string username ) , ( "user", E.string username )
] ]
|> E.object |> E.object
|> R.bodyValue "identifier" |> R.bodyValue "identifier"
, R.bodyString "password" password
, R.bodyString "type" "m.login.password"
] ]
>> R.toTask SO.loggedInResponseDecoder >> R.toTask SO3.loggedInResponseDecoder
loginWithUsernameAndPasswordV4 : LoginWithUsernameAndPasswordInputV2 -> Context { a | baseUrl : () } -> Task X.Error LoginWithUsernameAndPasswordOutputV4
loginWithUsernameAndPasswordV4 { deviceId, initialDeviceDisplayName, password, username } =
R.callApi "POST" "/_matrix/client/r0/login"
>> R.withAttributes
[ R.bodyString "type" "m.login.password"
, R.bodyString "password" password
, R.bodyOpString "device_id" deviceId
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, [ ( "type", E.string "m.id.user" )
, ( "user", E.string username )
]
|> E.object
|> R.bodyValue "identifier"
]
>> R.toTask SO4.loggedInResponseDecoder
loginWithUsernameAndPasswordV5 : LoginWithUsernameAndPasswordInputV2 -> Context { a | baseUrl : () } -> Task X.Error LoginWithUsernameAndPasswordOutputV4
loginWithUsernameAndPasswordV5 { deviceId, initialDeviceDisplayName, password, username } =
R.callApi "POST" "/_matrix/client/v3/login"
>> R.withAttributes
[ R.bodyString "type" "m.login.password"
, R.bodyString "password" password
, R.bodyOpString "device_id" deviceId
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, [ ( "type", E.string "m.id.user" )
, ( "user", E.string username )
]
|> E.object
|> R.bodyValue "identifier"
]
>> R.toTask SO4.loggedInResponseDecoder
loginWithUsernameAndPasswordV6 : LoginWithUsernameAndPasswordInputV2 -> Context { a | baseUrl : () } -> Task X.Error LoginWithUsernameAndPasswordOutputV5
loginWithUsernameAndPasswordV6 { deviceId, initialDeviceDisplayName, password, username } =
R.callApi "POST" "/_matrix/client/v3/login"
>> R.withAttributes
[ R.bodyString "type" "m.login.password"
, R.bodyString "password" password
, R.bodyOpString "device_id" deviceId
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, R.bodyBool "refresh_token" True
, [ ( "type", E.string "m.id.user" )
, ( "user", E.string username )
]
|> E.object
|> R.bodyValue "identifier"
]
>> R.toTask SO5.loggedInResponseDecoder
-- loginWithUsernameAndPasswordV5 : LoginWithUsernameAndPasswordInputV1 -> Context { a | baseUrl : () } -> Task X.Error LoginWithUsernameAndPasswordOutputV5
-- loginWithUsernameAndPasswordV5 { username, password } =
-- R.callApi "POST" "/_matrix/client/v3/login"
-- >> R.withAttributes
-- [ [ ( "type", E.string "m.id.user" )
-- , ( "user", E.string username )
-- ]
-- |> E.object
-- |> R.bodyValue "identifier"
-- , R.bodyString "password" password
-- , R.bodyString "type" "m.login.password"
-- ]
-- >> R.toTask SO.loggedInResponseDecoder

View File

@ -1,6 +1,10 @@
module Internal.Api.LoginWithUsernameAndPassword.Main exposing (..) module Internal.Api.LoginWithUsernameAndPassword.Main exposing (..)
import Internal.Api.LoginWithUsernameAndPassword.Api as Api import Internal.Api.LoginWithUsernameAndPassword.Api as Api
import Internal.Api.LoginWithUsernameAndPassword.V2.Upcast as U2
import Internal.Api.LoginWithUsernameAndPassword.V3.Upcast as U3
import Internal.Api.LoginWithUsernameAndPassword.V4.Upcast as U4
import Internal.Api.LoginWithUsernameAndPassword.V5.Upcast as U5
import Internal.Tools.Context as Context exposing (Context, VB) import Internal.Tools.Context as Context exposing (Context, VB)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Internal.Tools.VersionControl as VC import Internal.Tools.VersionControl as VC
@ -11,8 +15,54 @@ loginWithUsernameAndPassword : Context (VB a) -> LoginWithUsernameAndPasswordInp
loginWithUsernameAndPassword context input = loginWithUsernameAndPassword context input =
VC.withBottomLayer VC.withBottomLayer
{ current = Api.loginWithUsernameAndPasswordV1 { current = Api.loginWithUsernameAndPasswordV1
, version = "v1.5" , version = "r0.0.0"
} }
|> VC.sameForVersion "r0.0.1"
|> VC.sameForVersion "r0.1.0"
|> VC.sameForVersion "r0.2.0"
|> VC.addMiddleLayer
{ downcast = \{ username, password } -> { username = username, password = password }
, current = Api.loginWithUsernameAndPasswordV2
, upcast =
\f c ->
Task.map U2.upcastLoggedInResponse (f c)
, version = "r0.3.0"
}
|> VC.addMiddleLayer
{ downcast = identity
, current = Api.loginWithUsernameAndPasswordV3
, upcast =
\f c ->
Task.map U3.upcastLoggedInResponse (f c)
, version = "r0.4.0"
}
|> VC.addMiddleLayer
{ downcast = identity
, current = Api.loginWithUsernameAndPasswordV4
, upcast =
\f c ->
Task.map U4.upcastLoggedInResponse (f c)
, version = "r0.5.0"
}
|> VC.sameForVersion "r0.6.0"
|> VC.sameForVersion "r0.6.1"
|> VC.addMiddleLayer
{ downcast = identity
, current = Api.loginWithUsernameAndPasswordV5
, upcast = identity
, version = "v1.1"
}
|> VC.sameForVersion "v1.2"
|> VC.addMiddleLayer
{ downcast = identity
, current = Api.loginWithUsernameAndPasswordV6
, upcast =
\f c ->
Task.map U5.upcastLoggedInResponse (f c)
, version = "v1.3"
}
|> VC.sameForVersion "v1.4"
|> VC.sameForVersion "v1.5"
|> VC.sameForVersion "v1.6" |> VC.sameForVersion "v1.6"
|> VC.mostRecentFromVersionList (Context.getVersions context) |> VC.mostRecentFromVersionList (Context.getVersions context)
|> Maybe.withDefault (always <| always <| Task.fail X.UnsupportedSpecVersion) |> Maybe.withDefault (always <| always <| Task.fail X.UnsupportedSpecVersion)
@ -21,8 +71,8 @@ loginWithUsernameAndPassword context input =
type alias LoginWithUsernameAndPasswordInput = type alias LoginWithUsernameAndPasswordInput =
Api.LoginWithUsernameAndPasswordInputV1 Api.LoginWithUsernameAndPasswordInputV2
type alias LoginWithUsernameAndPasswordOutput = type alias LoginWithUsernameAndPasswordOutput =
Api.LoginWithUsernameAndPasswordOutputV1 Api.LoginWithUsernameAndPasswordOutputV5

View File

@ -1,21 +1,12 @@
module Internal.Api.LoginWithUsernameAndPassword.V1.Login exposing module Internal.Api.LoginWithUsernameAndPassword.V1.Login exposing
( DiscoveryInformation ( LoggedInResponse
, HomeserverInformation
, IdentityServerInformation
, LoggedInResponse
, discoveryInformationDecoder
, encodeDiscoveryInformation
, encodeHomeserverInformation
, encodeIdentityServerInformation
, encodeLoggedInResponse , encodeLoggedInResponse
, homeserverInformationDecoder
, identityServerInformationDecoder
, loggedInResponseDecoder , loggedInResponseDecoder
) )
{-| Automatically generated 'Login' {-| Automatically generated 'Login'
Last generated at Unix time 1677859025 Last generated at Unix time 1679075857
-} -}
@ -25,87 +16,13 @@ import Json.Decode as D
import Json.Encode as E import Json.Encode as E
{-| Information that overwrites the credential's base url and more. {-| Confirmation that the user successfully logged in.
-}
type alias DiscoveryInformation =
{ mHomeserver : HomeserverInformation
, mIdentityServer : Maybe IdentityServerInformation
}
encodeDiscoveryInformation : DiscoveryInformation -> E.Value
encodeDiscoveryInformation data =
maybeObject
[ ( "m.homeserver", Just <| encodeHomeserverInformation data.mHomeserver )
, ( "m.identity_server", Maybe.map encodeIdentityServerInformation data.mIdentityServer )
]
discoveryInformationDecoder : D.Decoder DiscoveryInformation
discoveryInformationDecoder =
D.map2
(\a b ->
{ mHomeserver = a, mIdentityServer = b }
)
(D.field "m.homeserver" homeserverInformationDecoder)
(opField "m.identity_server" identityServerInformationDecoder)
{-| Used by clients to discover homeserver information.
-}
type alias HomeserverInformation =
{ baseUrl : String
}
encodeHomeserverInformation : HomeserverInformation -> E.Value
encodeHomeserverInformation data =
maybeObject
[ ( "base_url", Just <| E.string data.baseUrl )
]
homeserverInformationDecoder : D.Decoder HomeserverInformation
homeserverInformationDecoder =
D.map
(\a ->
{ baseUrl = a }
)
(D.field "base_url" D.string)
{-| Used by clients to discover identity server information.
-}
type alias IdentityServerInformation =
{ baseUrl : String
}
encodeIdentityServerInformation : IdentityServerInformation -> E.Value
encodeIdentityServerInformation data =
maybeObject
[ ( "base_url", Just <| E.string data.baseUrl )
]
identityServerInformationDecoder : D.Decoder IdentityServerInformation
identityServerInformationDecoder =
D.map
(\a ->
{ baseUrl = a }
)
(D.field "base_url" D.string)
{-| Confirmation that the user has successfully logged in.
-} -}
type alias LoggedInResponse = type alias LoggedInResponse =
{ accessToken : String { accessToken : String
, deviceId : String , homeServer : String
, expiresInMs : Maybe Int
, refreshToken : Maybe String , refreshToken : Maybe String
, userId : String , userId : String
, wellKnown : Maybe DiscoveryInformation
} }
@ -113,23 +30,19 @@ encodeLoggedInResponse : LoggedInResponse -> E.Value
encodeLoggedInResponse data = encodeLoggedInResponse data =
maybeObject maybeObject
[ ( "access_token", Just <| E.string data.accessToken ) [ ( "access_token", Just <| E.string data.accessToken )
, ( "device_id", Just <| E.string data.deviceId ) , ( "home_server", Just <| E.string data.homeServer )
, ( "expires_in_ms", Maybe.map E.int data.expiresInMs )
, ( "refresh_token", Maybe.map E.string data.refreshToken ) , ( "refresh_token", Maybe.map E.string data.refreshToken )
, ( "user_id", Just <| E.string data.userId ) , ( "user_id", Just <| E.string data.userId )
, ( "well_known", Maybe.map encodeDiscoveryInformation data.wellKnown )
] ]
loggedInResponseDecoder : D.Decoder LoggedInResponse loggedInResponseDecoder : D.Decoder LoggedInResponse
loggedInResponseDecoder = loggedInResponseDecoder =
D.map6 D.map4
(\a b c d e f -> (\a b c d ->
{ accessToken = a, deviceId = b, expiresInMs = c, refreshToken = d, userId = e, wellKnown = f } { accessToken = a, homeServer = b, refreshToken = c, userId = d }
) )
(D.field "access_token" D.string) (D.field "access_token" D.string)
(D.field "device_id" D.string) (D.field "home_server" D.string)
(opField "expires_in_ms" D.int)
(opField "refresh_token" D.string) (opField "refresh_token" D.string)
(D.field "user_id" D.string) (D.field "user_id" D.string)
(opField "well_known" discoveryInformationDecoder)

View File

@ -2,44 +2,17 @@ version: V_1
name: Login name: Login
objects: objects:
LoggedInResponse: LoggedInResponse:
description: Confirmation that the user has successfully logged in. description: Confirmation that the user successfully logged in.
fields: fields:
access_token: access_token:
type: string type: string
required: true required: true
device_id: home_server:
type: string type: string
required: true required: true
expires_in_ms:
type: int
required: false
refresh_token: refresh_token:
type: string type: string
required: false required: false
user_id: user_id:
type: string type: string
required: true required: true
well_known:
type: DiscoveryInformation
required: false
DiscoveryInformation:
description: Information that overwrites the credential's base url and more.
fields:
m.homeserver:
type: HomeserverInformation
required: true
m.identity_server:
type: IdentityServerInformation
required: false
HomeserverInformation:
description: Used by clients to discover homeserver information.
fields:
base_url:
type: string
required: true
IdentityServerInformation:
description: Used by clients to discover identity server information.
fields:
base_url:
type: string
required: true

View File

@ -0,0 +1,50 @@
module Internal.Api.LoginWithUsernameAndPassword.V2.SpecObjects exposing
( LoggedInResponse
, encodeLoggedInResponse
, loggedInResponseDecoder
)
{-| Automatically generated 'Login'
Last generated at Unix time 1679075857
-}
import Internal.Tools.EncodeExtra exposing (maybeObject)
import Json.Decode as D
import Json.Encode as E
{-| Confirmation that the user successfully logged in.
-}
type alias LoggedInResponse =
{ accessToken : String
, deviceId : Maybe String
, homeServer : String
, refreshToken : Maybe String
, userId : String
}
encodeLoggedInResponse : LoggedInResponse -> E.Value
encodeLoggedInResponse data =
maybeObject
[ ( "access_token", Just <| E.string data.accessToken )
, ( "device_id", Maybe.map E.string data.deviceId )
, ( "home_server", Just <| E.string data.homeServer )
, ( "refresh_token", Nothing )
, ( "user_id", Just <| E.string data.userId )
]
loggedInResponseDecoder : D.Decoder LoggedInResponse
loggedInResponseDecoder =
D.map5
(\a b c d e ->
{ accessToken = a, deviceId = b, homeServer = c, refreshToken = d, userId = e }
)
(D.field "access_token" D.string)
(D.map Just <| D.field "device_id" D.string)
(D.field "home_server" D.string)
(D.succeed Nothing)
(D.field "user_id" D.string)

View File

@ -0,0 +1,21 @@
version: V_2
name: Login
objects:
LoggedInResponse:
description: Confirmation that the user successfully logged in.
fields:
access_token:
type: string
required: true
device_id:
type: string
required: now
home_server:
type: string
required: true
refresh_token:
type: string
required: never
user_id:
type: string
required: true

View File

@ -0,0 +1,14 @@
module Internal.Api.LoginWithUsernameAndPassword.V2.Upcast exposing (..)
import Internal.Api.LoginWithUsernameAndPassword.V1.Login as PO
import Internal.Api.LoginWithUsernameAndPassword.V2.SpecObjects as SO
upcastLoggedInResponse : PO.LoggedInResponse -> SO.LoggedInResponse
upcastLoggedInResponse old =
{ accessToken = old.accessToken
, deviceId = Nothing
, homeServer = old.homeServer
, refreshToken = old.refreshToken
, userId = old.userId
}

View File

@ -0,0 +1,50 @@
module Internal.Api.LoginWithUsernameAndPassword.V3.SpecObjects exposing
( LoggedInResponse
, encodeLoggedInResponse
, loggedInResponseDecoder
)
{-| Automatically generated 'Login'
Last generated at Unix time 1679075857
-}
import Internal.Tools.EncodeExtra exposing (maybeObject)
import Json.Decode as D
import Json.Encode as E
{-| Confirmation that the user successfully logged in.
-}
type alias LoggedInResponse =
{ accessToken : String
, deviceId : Maybe String
, homeServer : Maybe String
, refreshToken : Maybe String
, userId : String
}
encodeLoggedInResponse : LoggedInResponse -> E.Value
encodeLoggedInResponse data =
maybeObject
[ ( "access_token", Just <| E.string data.accessToken )
, ( "device_id", Maybe.map E.string data.deviceId )
, ( "home_server", Nothing )
, ( "refresh_token", Nothing )
, ( "user_id", Just <| E.string data.userId )
]
loggedInResponseDecoder : D.Decoder LoggedInResponse
loggedInResponseDecoder =
D.map5
(\a b c d e ->
{ accessToken = a, deviceId = b, homeServer = c, refreshToken = d, userId = e }
)
(D.field "access_token" D.string)
(D.map Just <| D.field "device_id" D.string)
(D.succeed Nothing)
(D.succeed Nothing)
(D.field "user_id" D.string)

View File

@ -0,0 +1,21 @@
version: V_3
name: Login
objects:
LoggedInResponse:
description: Confirmation that the user successfully logged in.
fields:
access_token:
type: string
required: true
device_id:
type: string
required: now
home_server:
type: string
required: never
refresh_token:
type: string
required: never
user_id:
type: string
required: true

View File

@ -0,0 +1,14 @@
module Internal.Api.LoginWithUsernameAndPassword.V3.Upcast exposing (..)
import Internal.Api.LoginWithUsernameAndPassword.V2.SpecObjects as PO
import Internal.Api.LoginWithUsernameAndPassword.V3.SpecObjects as SO
upcastLoggedInResponse : PO.LoggedInResponse -> SO.LoggedInResponse
upcastLoggedInResponse old =
{ accessToken = old.accessToken
, deviceId = Nothing
, homeServer = Just old.homeServer
, refreshToken = old.refreshToken
, userId = old.userId
}

View File

@ -0,0 +1,135 @@
module Internal.Api.LoginWithUsernameAndPassword.V4.SpecObjects exposing
( DiscoveryInformation
, HomeserverInformation
, IdentityServerInformation
, LoggedInResponse
, discoveryInformationDecoder
, encodeDiscoveryInformation
, encodeHomeserverInformation
, encodeIdentityServerInformation
, encodeLoggedInResponse
, homeserverInformationDecoder
, identityServerInformationDecoder
, loggedInResponseDecoder
)
{-| Automatically generated 'Login'
Last generated at Unix time 1679075857
-}
import Internal.Tools.DecodeExtra exposing (opField)
import Internal.Tools.EncodeExtra exposing (maybeObject)
import Json.Decode as D
import Json.Encode as E
{-| Information that overwrites the credential's base url and more.
-}
type alias DiscoveryInformation =
{ mHomeserver : HomeserverInformation
, mIdentityServer : Maybe IdentityServerInformation
}
encodeDiscoveryInformation : DiscoveryInformation -> E.Value
encodeDiscoveryInformation data =
maybeObject
[ ( "m.homeserver", Just <| encodeHomeserverInformation data.mHomeserver )
, ( "m.identity_server", Maybe.map encodeIdentityServerInformation data.mIdentityServer )
]
discoveryInformationDecoder : D.Decoder DiscoveryInformation
discoveryInformationDecoder =
D.map2
(\a b ->
{ mHomeserver = a, mIdentityServer = b }
)
(D.field "m.homeserver" homeserverInformationDecoder)
(opField "m.identity_server" identityServerInformationDecoder)
{-| Used by clients to discover homeserver information.
-}
type alias HomeserverInformation =
{ baseUrl : String
}
encodeHomeserverInformation : HomeserverInformation -> E.Value
encodeHomeserverInformation data =
maybeObject
[ ( "base_url", Just <| E.string data.baseUrl )
]
homeserverInformationDecoder : D.Decoder HomeserverInformation
homeserverInformationDecoder =
D.map
(\a ->
{ baseUrl = a }
)
(D.field "base_url" D.string)
{-| Used by clients to discover identity server information.
-}
type alias IdentityServerInformation =
{ baseUrl : String
}
encodeIdentityServerInformation : IdentityServerInformation -> E.Value
encodeIdentityServerInformation data =
maybeObject
[ ( "base_url", Just <| E.string data.baseUrl )
]
identityServerInformationDecoder : D.Decoder IdentityServerInformation
identityServerInformationDecoder =
D.map
(\a ->
{ baseUrl = a }
)
(D.field "base_url" D.string)
{-| Confirmation that the user successfully logged in.
-}
type alias LoggedInResponse =
{ accessToken : String
, deviceId : Maybe String
, homeServer : Maybe String
, refreshToken : Maybe String
, userId : String
, wellKnown : Maybe DiscoveryInformation
}
encodeLoggedInResponse : LoggedInResponse -> E.Value
encodeLoggedInResponse data =
maybeObject
[ ( "access_token", Just <| E.string data.accessToken )
, ( "device_id", Maybe.map E.string data.deviceId )
, ( "home_server", Nothing )
, ( "refresh_token", Nothing )
, ( "user_id", Just <| E.string data.userId )
, ( "well_known", Maybe.map encodeDiscoveryInformation data.wellKnown )
]
loggedInResponseDecoder : D.Decoder LoggedInResponse
loggedInResponseDecoder =
D.map6
(\a b c d e f ->
{ accessToken = a, deviceId = b, homeServer = c, refreshToken = d, userId = e, wellKnown = f }
)
(D.field "access_token" D.string)
(D.map Just <| D.field "device_id" D.string)
(D.succeed Nothing)
(D.succeed Nothing)
(D.field "user_id" D.string)
(opField "well_known" discoveryInformationDecoder)

View File

@ -0,0 +1,45 @@
version: V_3
name: Login
objects:
LoggedInResponse:
description: Confirmation that the user successfully logged in.
fields:
access_token:
type: string
required: true
device_id:
type: string
required: now
home_server:
type: string
required: never
refresh_token:
type: string
required: never
user_id:
type: string
required: true
well_known:
type: DiscoveryInformation
required: false
DiscoveryInformation:
description: Information that overwrites the credential's base url and more.
fields:
m.homeserver:
type: HomeserverInformation
required: true
m.identity_server:
type: IdentityServerInformation
required: false
HomeserverInformation:
description: Used by clients to discover homeserver information.
fields:
base_url:
type: string
required: true
IdentityServerInformation:
description: Used by clients to discover identity server information.
fields:
base_url:
type: string
required: true

View File

@ -0,0 +1,15 @@
module Internal.Api.LoginWithUsernameAndPassword.V4.Upcast exposing (..)
import Internal.Api.LoginWithUsernameAndPassword.V3.SpecObjects as PO
import Internal.Api.LoginWithUsernameAndPassword.V4.SpecObjects as SO
upcastLoggedInResponse : PO.LoggedInResponse -> SO.LoggedInResponse
upcastLoggedInResponse old =
{ accessToken = old.accessToken
, deviceId = old.deviceId
, homeServer = old.homeServer
, refreshToken = old.refreshToken
, userId = old.userId
, wellKnown = Nothing
}

View File

@ -0,0 +1,138 @@
module Internal.Api.LoginWithUsernameAndPassword.V5.Login exposing
( DiscoveryInformation
, HomeserverInformation
, IdentityServerInformation
, LoggedInResponse
, discoveryInformationDecoder
, encodeDiscoveryInformation
, encodeHomeserverInformation
, encodeIdentityServerInformation
, encodeLoggedInResponse
, homeserverInformationDecoder
, identityServerInformationDecoder
, loggedInResponseDecoder
)
{-| Automatically generated 'Login'
Last generated at Unix time 1679075857
-}
import Internal.Tools.DecodeExtra exposing (opField)
import Internal.Tools.EncodeExtra exposing (maybeObject)
import Json.Decode as D
import Json.Encode as E
{-| Information that overwrites the credential's base url and more.
-}
type alias DiscoveryInformation =
{ mHomeserver : HomeserverInformation
, mIdentityServer : Maybe IdentityServerInformation
}
encodeDiscoveryInformation : DiscoveryInformation -> E.Value
encodeDiscoveryInformation data =
maybeObject
[ ( "m.homeserver", Just <| encodeHomeserverInformation data.mHomeserver )
, ( "m.identity_server", Maybe.map encodeIdentityServerInformation data.mIdentityServer )
]
discoveryInformationDecoder : D.Decoder DiscoveryInformation
discoveryInformationDecoder =
D.map2
(\a b ->
{ mHomeserver = a, mIdentityServer = b }
)
(D.field "m.homeserver" homeserverInformationDecoder)
(opField "m.identity_server" identityServerInformationDecoder)
{-| Used by clients to discover homeserver information.
-}
type alias HomeserverInformation =
{ baseUrl : String
}
encodeHomeserverInformation : HomeserverInformation -> E.Value
encodeHomeserverInformation data =
maybeObject
[ ( "base_url", Just <| E.string data.baseUrl )
]
homeserverInformationDecoder : D.Decoder HomeserverInformation
homeserverInformationDecoder =
D.map
(\a ->
{ baseUrl = a }
)
(D.field "base_url" D.string)
{-| Used by clients to discover identity server information.
-}
type alias IdentityServerInformation =
{ baseUrl : String
}
encodeIdentityServerInformation : IdentityServerInformation -> E.Value
encodeIdentityServerInformation data =
maybeObject
[ ( "base_url", Just <| E.string data.baseUrl )
]
identityServerInformationDecoder : D.Decoder IdentityServerInformation
identityServerInformationDecoder =
D.map
(\a ->
{ baseUrl = a }
)
(D.field "base_url" D.string)
{-| Confirmation that the user has successfully logged in.
-}
type alias LoggedInResponse =
{ accessToken : String
, deviceId : Maybe String
, expiresInMs : Maybe Int
, homeServer : Maybe String
, refreshToken : Maybe String
, userId : String
, wellKnown : Maybe DiscoveryInformation
}
encodeLoggedInResponse : LoggedInResponse -> E.Value
encodeLoggedInResponse data =
maybeObject
[ ( "access_token", Just <| E.string data.accessToken )
, ( "device_id", Maybe.map E.string data.deviceId )
, ( "expires_in_ms", Maybe.map E.int data.expiresInMs )
, ( "home_server", Nothing )
, ( "refresh_token", Maybe.map E.string data.refreshToken )
, ( "user_id", Just <| E.string data.userId )
, ( "well_known", Maybe.map encodeDiscoveryInformation data.wellKnown )
]
loggedInResponseDecoder : D.Decoder LoggedInResponse
loggedInResponseDecoder =
D.map7
(\a b c d e f g ->
{ accessToken = a, deviceId = b, expiresInMs = c, homeServer = d, refreshToken = e, userId = f, wellKnown = g }
)
(D.field "access_token" D.string)
(D.map Just <| D.field "device_id" D.string)
(opField "expires_in_ms" D.int)
(D.succeed Nothing)
(opField "refresh_token" D.string)
(D.field "user_id" D.string)
(opField "well_known" discoveryInformationDecoder)

View File

@ -0,0 +1,48 @@
version: V_1
name: Login
objects:
LoggedInResponse:
description: Confirmation that the user has successfully logged in.
fields:
access_token:
type: string
required: true
device_id:
type: string
required: now
expires_in_ms:
type: int
required: false
home_server:
type: string
required: never
refresh_token:
type: string
required: false
user_id:
type: string
required: true
well_known:
type: DiscoveryInformation
required: false
DiscoveryInformation:
description: Information that overwrites the credential's base url and more.
fields:
m.homeserver:
type: HomeserverInformation
required: true
m.identity_server:
type: IdentityServerInformation
required: false
HomeserverInformation:
description: Used by clients to discover homeserver information.
fields:
base_url:
type: string
required: true
IdentityServerInformation:
description: Used by clients to discover identity server information.
fields:
base_url:
type: string
required: true

View File

@ -0,0 +1,16 @@
module Internal.Api.LoginWithUsernameAndPassword.V5.Upcast exposing (..)
import Internal.Api.LoginWithUsernameAndPassword.V4.SpecObjects as PO
import Internal.Api.LoginWithUsernameAndPassword.V5.Login as SO
upcastLoggedInResponse : PO.LoggedInResponse -> SO.LoggedInResponse
upcastLoggedInResponse old =
{ accessToken = old.accessToken
, deviceId = old.deviceId
, expiresInMs = Nothing
, homeServer = old.homeServer
, refreshToken = old.refreshToken
, userId = old.userId
, wellKnown = old.wellKnown
}

View File

@ -79,21 +79,25 @@ accessToken ctoken =
|> always |> always
AccessToken t -> AccessToken t ->
{ contextChange = Context.setAccessToken { accessToken = t, usernameAndPassword = Nothing } { contextChange = Context.setAccessToken { accessToken = t, loginParts = Nothing }
, messages = [] , messages = []
} }
|> Chain.TaskChainPiece |> Chain.TaskChainPiece
|> Task.succeed |> Task.succeed
|> always |> always
UsernameAndPassword { username, password, token } -> UsernameAndPassword { username, password, token, deviceId, initialDeviceDisplayName } ->
case token of case token of
Just t -> Just t ->
accessToken (AccessToken t) accessToken (AccessToken t)
Nothing -> Nothing ->
loginWithUsernameAndPassword loginWithUsernameAndPassword
{ username = username, password = password } { username = username
, password = password
, deviceId = deviceId
, initialDeviceDisplayName = initialDeviceDisplayName
}
{-| Get an event from the API. {-| Get an event from the API.
@ -188,7 +192,7 @@ loginWithUsernameAndPassword input =
{ contextChange = { contextChange =
Context.setAccessToken Context.setAccessToken
{ accessToken = output.accessToken { accessToken = output.accessToken
, usernameAndPassword = Just input , loginParts = Just input
} }
, messages = [ LoggedInWithUsernameAndPassword input output ] , messages = [ LoggedInWithUsernameAndPassword input output ]
} }

View File

@ -6,12 +6,12 @@ module Internal.Api.Versions.V1.Versions exposing
{-| Automatically generated 'Versions' {-| Automatically generated 'Versions'
Last generated at Unix time 1677064309 Last generated at Unix time 1679075857
-} -}
import Dict exposing (Dict) import Dict exposing (Dict)
import Internal.Tools.DecodeExtra exposing (opField, opFieldWithDefault) import Internal.Tools.DecodeExtra exposing (opFieldWithDefault)
import Internal.Tools.EncodeExtra exposing (maybeObject) import Internal.Tools.EncodeExtra exposing (maybeObject)
import Json.Decode as D import Json.Decode as D
import Json.Encode as E import Json.Encode as E

View File

@ -24,13 +24,17 @@ type Context a
, baseUrl : String , baseUrl : String
, sentEvent : String , sentEvent : String
, transactionId : String , transactionId : String
, usernameAndPassword : Maybe UsernameAndPassword , loginParts : Maybe LoginParts
, versions : List String , versions : List String
} }
type alias UsernameAndPassword = type alias LoginParts =
{ username : String, password : String } { deviceId : Maybe String
, initialDeviceDisplayName : Maybe String
, password : String
, username : String
}
type alias VB a = type alias VB a =
@ -54,7 +58,7 @@ init =
, baseUrl = L.baseUrl , baseUrl = L.baseUrl
, sentEvent = L.eventId , sentEvent = L.eventId
, transactionId = L.transactionId , transactionId = L.transactionId
, usernameAndPassword = Nothing , loginParts = Nothing
, versions = L.versions , versions = L.versions
} }
@ -89,9 +93,9 @@ getTransactionId (Context { transactionId }) =
{-| Get the username and password of the user, if present. {-| Get the username and password of the user, if present.
-} -}
getUsernameAndPassword : Context { a | accessToken : () } -> Maybe UsernameAndPassword getLoginParts : Context { a | accessToken : () } -> Maybe LoginParts
getUsernameAndPassword (Context { usernameAndPassword }) = getLoginParts (Context { loginParts }) =
usernameAndPassword loginParts
{-| Get the supported spec versions from the Context. {-| Get the supported spec versions from the Context.
@ -103,9 +107,9 @@ getVersions (Context { versions }) =
{-| Insert an access token into the context. {-| Insert an access token into the context.
-} -}
setAccessToken : { accessToken : String, usernameAndPassword : Maybe UsernameAndPassword } -> Context a -> Context { a | accessToken : () } setAccessToken : { accessToken : String, loginParts : Maybe LoginParts } -> Context a -> Context { a | accessToken : () }
setAccessToken { accessToken, usernameAndPassword } (Context data) = setAccessToken { accessToken, loginParts } (Context data) =
Context { data | accessToken = accessToken, usernameAndPassword = usernameAndPassword } Context { data | accessToken = accessToken, loginParts = loginParts }
{-| Insert a base url into the context. {-| Insert a base url into the context.

View File

@ -4,7 +4,13 @@ module Internal.Tools.LoginValues exposing (..)
type AccessToken type AccessToken
= NoAccess = NoAccess
| AccessToken String | AccessToken String
| UsernameAndPassword { username : String, password : String, token : Maybe String } | UsernameAndPassword
{ deviceId : Maybe String
, initialDeviceDisplayName : Maybe String
, password : String
, token : Maybe String
, username : String
}
defaultAccessToken : AccessToken defaultAccessToken : AccessToken
@ -23,6 +29,8 @@ fromUsernameAndPassword username password =
{ username = username { username = username
, password = password , password = password
, token = Nothing , token = Nothing
, deviceId = Nothing
, initialDeviceDisplayName = Nothing
} }
@ -48,37 +56,29 @@ addToken s t =
AccessToken _ -> AccessToken _ ->
AccessToken s AccessToken s
UsernameAndPassword { username, password } -> UsernameAndPassword data ->
UsernameAndPassword UsernameAndPassword
{ username = username { data | token = Just s }
, password = password
, token = Just s
}
addUsernameAndPassword : { username : String, password : String } -> AccessToken -> AccessToken addUsernameAndPassword : { username : String, password : String } -> AccessToken -> AccessToken
addUsernameAndPassword { username, password } t = addUsernameAndPassword { username, password } t =
case t of case t of
NoAccess -> NoAccess ->
UsernameAndPassword fromUsernameAndPassword username password
{ username = username
, password = password
, token = Nothing
}
AccessToken a -> AccessToken a ->
UsernameAndPassword UsernameAndPassword
{ username = username { username = username
, password = password , password = password
, token = Just a , token = Just a
, deviceId = Nothing
, initialDeviceDisplayName = Nothing
} }
UsernameAndPassword { token } -> UsernameAndPassword data ->
UsernameAndPassword UsernameAndPassword
{ username = username { data | username = username, password = password }
, password = password
, token = token
}
removeToken : AccessToken -> AccessToken removeToken : AccessToken -> AccessToken
@ -90,9 +90,6 @@ removeToken t =
AccessToken _ -> AccessToken _ ->
NoAccess NoAccess
UsernameAndPassword { username, password } -> UsernameAndPassword data ->
UsernameAndPassword UsernameAndPassword
{ username = username { data | token = Nothing }
, password = password
, token = Nothing
}

View File

@ -4,7 +4,6 @@ module Internal.Values.RoomInvite exposing (..)
-} -}
import Dict exposing (Dict) import Dict exposing (Dict)
import Internal.Values.Room exposing (IRoom)
import Json.Encode as E import Json.Encode as E

View File

@ -1,4 +1,8 @@
module Matrix.RoomInvite exposing (RoomInvite, accept, reject, acceptWithReason, rejectWithReason) module Matrix.RoomInvite exposing
( RoomInvite, accept, reject, acceptWithReason, rejectWithReason
, roomId
, sender, stateKey, contentType, content
)
{-| Sometimes, your user will be invited to a new room! {-| Sometimes, your user will be invited to a new room!
This module offers you a few simple handles to deal with such invites - This module offers you a few simple handles to deal with such invites -
@ -18,7 +22,7 @@ Be careful though, anyone can invite you to any room! This means that room invit
may contain offensive, shocking or other unwanted content that the user may not may contain offensive, shocking or other unwanted content that the user may not
want to see. want to see.
@docs RoomInviteEvent getEvent, getAllEvents @docs roomId, RoomInviteEvent, getEvent, getAllEvents
Once you have the event you want, you can explore it with the following functions. Once you have the event you want, you can explore it with the following functions.