diff --git a/src/Internal/Api/CredUpdate.elm b/src/Internal/Api/CredUpdate.elm index dff26f3..7b6fcaa 100644 --- a/src/Internal/Api/CredUpdate.elm +++ b/src/Internal/Api/CredUpdate.elm @@ -41,6 +41,14 @@ type alias FutureTask = Task X.Error CredUpdate +{-| Turn an API Task into a taskchain. +-} +toChain : (cout -> Chain.TaskChainPiece CredUpdate ph1 ph2) -> (Context.Context ph1 -> cin -> Task X.Error cout) -> cin -> TaskChain CredUpdate ph1 ph2 +toChain transform task input context = + task context input + |> Task.map transform + + {-| Turn a chain of tasks into a full executable task. -} toTask : TaskChain CredUpdate {} b -> FutureTask @@ -86,134 +94,79 @@ accessToken ctoken = { username = username, password = password } -type alias GetEventInput = - { eventId : String, roomId : String } - - {-| Get an event from the API. -} -getEvent : GetEventInput -> IdemChain CredUpdate (VBA a) -getEvent { eventId, roomId } context = - let - input = - { accessToken = Context.getAccessToken context - , baseUrl = Context.getBaseUrl context - , eventId = eventId - , roomId = roomId - } - in - input - |> GetEvent.getEvent (Context.getVersions context) - |> Task.map - (\output -> - Chain.TaskChainPiece - { contextChange = identity - , messages = [ GetEvent input output ] - } - ) +getEvent : GetEvent.EventInput -> IdemChain CredUpdate (VBA a) +getEvent input = + toChain + (\output -> + Chain.TaskChainPiece + { contextChange = identity + , messages = [ GetEvent input output ] + } + ) + GetEvent.getEvent + input {-| Get the supported spec versions from the homeserver. -} getVersions : TaskChain CredUpdate { a | baseUrl : () } (VB a) -getVersions context = - let - input = - Context.getBaseUrl context - in - Versions.getVersions input - |> Task.map - (\output -> - Chain.TaskChainPiece - { contextChange = Context.setVersions output.versions - , messages = [ UpdateVersions output ] - } - ) - - -type alias InviteInput = - { reason : Maybe String - , roomId : String - , userId : String - } +getVersions = + toChain + (\output -> + Chain.TaskChainPiece + { contextChange = Context.setVersions output.versions + , messages = [ UpdateVersions output ] + } + ) + (\context _ -> Versions.getVersions context) + () {-| Invite a user to a room. -} -invite : InviteInput -> IdemChain CredUpdate (VBA a) -invite { reason, roomId, userId } context = - let - input = - { accessToken = Context.getAccessToken context - , baseUrl = Context.getBaseUrl context - , reason = reason - , roomId = roomId - , userId = userId - } - in - input - |> Invite.invite (Context.getVersions context) - |> Task.map - (\output -> - Chain.TaskChainPiece - { contextChange = identity - , messages = [ InviteSent input output ] - } - ) +invite : Invite.InviteInput -> IdemChain CredUpdate (VBA a) +invite input = + toChain + (\output -> + Chain.TaskChainPiece + { contextChange = identity + , messages = [ InviteSent input output ] + } + ) + Invite.invite + input -type alias JoinedMembersInput = - { roomId : String } +joinedMembers : JoinedMembers.JoinedMembersInput -> IdemChain CredUpdate (VBA a) +joinedMembers input = + toChain + (\output -> + Chain.TaskChainPiece + { contextChange = identity + , messages = [ JoinedMembersToRoom input output ] + } + ) + JoinedMembers.joinedMembers + input -joinedMembers : JoinedMembersInput -> IdemChain CredUpdate (VBA a) -joinedMembers { roomId } context = - let - input = - { accessToken = Context.getAccessToken context - , baseUrl = Context.getBaseUrl context - , roomId = roomId - } - in - input - |> JoinedMembers.joinedMembers (Context.getVersions context) - |> Task.map - (\output -> - Chain.TaskChainPiece - { contextChange = identity - , messages = [ JoinedMembersToRoom input output ] - } - ) - - -type alias LoginWithUsernameAndPasswordInput = - { password : String - , username : String - } - - -loginWithUsernameAndPassword : LoginWithUsernameAndPasswordInput -> TaskChain CredUpdate (VB a) (VBA a) -loginWithUsernameAndPassword ({ username, password } as data) context = - let - input = - { baseUrl = Context.getBaseUrl context - , username = username - , password = password - } - in - input - |> LoginWithUsernameAndPassword.loginWithUsernameAndPassword (Context.getVersions context) - |> Task.map - (\output -> - Chain.TaskChainPiece - { contextChange = - Context.setAccessToken - { accessToken = output.accessToken - , usernameAndPassword = Just data - } - , messages = [ LoggedInWithUsernameAndPassword input output ] - } - ) +loginWithUsernameAndPassword : LoginWithUsernameAndPassword.LoginWithUsernameAndPasswordInput -> TaskChain CredUpdate (VB a) (VBA a) +loginWithUsernameAndPassword input = + toChain + (\output -> + Chain.TaskChainPiece + { contextChange = + Context.setAccessToken + { accessToken = output.accessToken + , usernameAndPassword = Just input + } + , messages = [ LoggedInWithUsernameAndPassword input output ] + } + ) + LoginWithUsernameAndPassword.loginWithUsernameAndPassword + input {-| Make a VB-context based chain. @@ -244,136 +197,64 @@ makeVBAT toString cred = |> Chain.andThen (withTransactionId toString) -type alias RedactInput = - { eventId : String - , reason : Maybe String - , roomId : String - } - - {-| Redact an event from a room. -} -redact : RedactInput -> TaskChain CredUpdate (VBAT a) (VBA a) -redact { eventId, reason, roomId } context = - let - input = - { accessToken = Context.getAccessToken context - , baseUrl = Context.getBaseUrl context - , eventId = eventId - , reason = reason - , roomId = roomId - , txnId = Context.getTransactionId context - } - in - input - |> Redact.redact (Context.getVersions context) - |> Task.map - (\output -> - Chain.TaskChainPiece - { contextChange = Context.removeTransactionId - , messages = [ RedactedEvent input output ] - } - ) - - -type alias SendMessageEventInput = - { content : E.Value - , eventType : String - , roomId : String - } +redact : Redact.RedactInput -> TaskChain CredUpdate (VBAT a) (VBA a) +redact input = + toChain + (\output -> + Chain.TaskChainPiece + { contextChange = Context.removeTransactionId + , messages = [ RedactedEvent input output ] + } + ) + Redact.redact + input {-| Send a message event to a room. -} -sendMessageEvent : SendMessageEventInput -> TaskChain CredUpdate (VBAT a) (VBA a) -sendMessageEvent { content, eventType, roomId } context = - let - input = - { accessToken = Context.getAccessToken context - , baseUrl = Context.getBaseUrl context - , content = content - , eventType = eventType - , roomId = roomId - , transactionId = Context.getTransactionId context - } - in - input - |> SendMessageEvent.sendMessageEvent (Context.getVersions context) - |> Task.map - (\output -> - Chain.TaskChainPiece - { contextChange = Context.removeTransactionId - , messages = [ MessageEventSent input output ] - } - ) - - -type alias SendStateEventInput = - { content : E.Value - , eventType : String - , roomId : String - , stateKey : String - } +sendMessageEvent : SendMessageEvent.SendMessageEventInput -> TaskChain CredUpdate (VBAT a) (VBA a) +sendMessageEvent input = + toChain + (\output -> + Chain.TaskChainPiece + { contextChange = Context.removeTransactionId + , messages = [ MessageEventSent input output ] + } + ) + SendMessageEvent.sendMessageEvent + input {-| Send a state key event to a room. -} -sendStateEvent : SendStateEventInput -> IdemChain CredUpdate (VBA a) -sendStateEvent { content, eventType, roomId, stateKey } context = - let - input = - { accessToken = Context.getAccessToken context - , baseUrl = Context.getBaseUrl context - , content = content - , eventType = eventType - , roomId = roomId - , stateKey = stateKey - } - in - input - |> SendStateKey.sendStateKey (Context.getVersions context) - |> Task.map - (\output -> - Chain.TaskChainPiece - { contextChange = identity - , messages = [ StateEventSent input output ] - } - ) - - -type alias SyncInput = - { filter : Maybe String - , fullState : Maybe Bool - , setPresence : Maybe Enums.UserPresence - , since : Maybe String - , timeout : Maybe Int - } +sendStateEvent : SendStateKey.SendStateKeyInput -> IdemChain CredUpdate (VBA a) +sendStateEvent input = + toChain + (\output -> + Chain.TaskChainPiece + { contextChange = identity + , messages = [ StateEventSent input output ] + } + ) + SendStateKey.sendStateKey + input {-| Sync the latest updates. -} -sync : SyncInput -> IdemChain CredUpdate (VBA a) -sync data context = - let - input = - { accessToken = Context.getAccessToken context - , baseUrl = Context.getBaseUrl context - , filter = data.filter - , fullState = data.fullState - , setPresence = data.setPresence - , since = data.since - , timeout = data.timeout - } - in - input - |> Sync.sync (Context.getVersions context) - |> Task.map - (\output -> - Chain.TaskChainPiece - { contextChange = identity - , messages = [ SyncUpdate input output ] - } - ) +sync : Sync.SyncInput -> IdemChain CredUpdate (VBA a) +sync input = + toChain + (\output -> + Chain.TaskChainPiece + { contextChange = identity + , messages = [ SyncUpdate input output ] + } + ) + Sync.sync + input {-| Insert versions, or get them if they are not provided. diff --git a/src/Internal/Api/GetEvent/Api.elm b/src/Internal/Api/GetEvent/Api.elm index 9071c6a..d044ffd 100644 --- a/src/Internal/Api/GetEvent/Api.elm +++ b/src/Internal/Api/GetEvent/Api.elm @@ -2,14 +2,13 @@ module Internal.Api.GetEvent.Api exposing (..) import Internal.Api.GetEvent.V1.SpecObjects as SO1 import Internal.Api.Request as R +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Task exposing (Task) type alias GetEventInputV1 = - { accessToken : String - , baseUrl : String - , eventId : String + { eventId : String , roomId : String } @@ -18,19 +17,12 @@ type alias GetEventOutputV1 = SO1.ClientEvent -getEventInputV1 : GetEventInputV1 -> Task X.Error GetEventOutputV1 +getEventInputV1 : GetEventInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error GetEventOutputV1 getEventInputV1 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "GET" - , baseUrl = data.baseUrl - , path = "/_matrix/client/v3/rooms/{roomId}/event/{eventId}" - , pathParams = - [ ( "eventId", data.eventId ) - , ( "roomId", data.roomId ) + R.callApi "GET" "/_matrix/client/v3/rooms/{roomId}/event/{eventId}" + >> R.withAttributes + [ R.accessToken + , R.replaceInUrl "eventId" data.eventId + , R.replaceInUrl "roomId" data.roomId ] - , queryParams = [] - , bodyParams = [] - , timeout = Nothing - , decoder = \_ -> SO1.clientEventDecoder - } + >> R.toTask SO1.clientEventDecoder diff --git a/src/Internal/Api/Invite/Api.elm b/src/Internal/Api/Invite/Api.elm index 4b558d0..63ed950 100644 --- a/src/Internal/Api/Invite/Api.elm +++ b/src/Internal/Api/Invite/Api.elm @@ -1,23 +1,20 @@ module Internal.Api.Invite.Api exposing (..) import Internal.Api.Request as R +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Json.Decode as D import Task exposing (Task) type alias InviteInputV1 = - { accessToken : String - , baseUrl : String - , roomId : String + { roomId : String , userId : String } type alias InviteInputV2 = - { accessToken : String - , baseUrl : String - , reason : Maybe String + { reason : Maybe String , roomId : String , userId : String } @@ -27,40 +24,24 @@ type alias InviteOutputV1 = () -inviteV1 : InviteInputV1 -> Task X.Error InviteOutputV1 -inviteV1 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "POST" - , baseUrl = data.baseUrl - , path = "/_matrix/client/r0/rooms/{roomId}/invite" - , pathParams = - [ ( "roomId", data.roomId ) +inviteV1 : InviteInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error InviteOutputV1 +inviteV1 { roomId, userId } = + R.callApi "POST" "/_matrix/client/r0/rooms/{roomId}/invite" + >> R.withAttributes + [ R.accessToken + , R.replaceInUrl "roomId" roomId + , R.bodyString "user_id" userId ] - , queryParams = [] - , bodyParams = - [ R.RequiredString "user_id" data.userId - ] - , timeout = Nothing - , decoder = always (D.map (always ()) D.value) - } + >> R.toTask (D.map (always ()) D.value) -inviteV2 : InviteInputV2 -> Task X.Error InviteOutputV1 -inviteV2 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "POST" - , baseUrl = data.baseUrl - , path = "/_matrix/client/r0/rooms/{roomId}/invite" - , pathParams = - [ ( "roomId", data.roomId ) +inviteV2 : InviteInputV2 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error InviteOutputV1 +inviteV2 { reason, roomId, userId } = + R.callApi "POST" "/_matrix/client/v3/rooms/{roomId}/invite" + >> R.withAttributes + [ R.accessToken + , R.replaceInUrl "roomId" roomId + , R.bodyString "user_id" userId + , R.bodyOpString "reason" reason ] - , queryParams = [] - , bodyParams = - [ R.RequiredString "user_id" data.userId - , R.OptionalString "reason" data.reason - ] - , timeout = Nothing - , decoder = always (D.map (always ()) D.value) - } + >> R.toTask (D.map (always ()) D.value) diff --git a/src/Internal/Api/Invite/Main.elm b/src/Internal/Api/Invite/Main.elm index 7f6afcb..bcfcd31 100644 --- a/src/Internal/Api/Invite/Main.elm +++ b/src/Internal/Api/Invite/Main.elm @@ -1,13 +1,14 @@ module Internal.Api.Invite.Main exposing (..) import Internal.Api.Invite.Api as Api +import Internal.Tools.Context as Context exposing (Context, VBA) import Internal.Tools.Exceptions as X import Internal.Tools.VersionControl as VC import Task exposing (Task) -invite : List String -> InviteInput -> Task X.Error InviteOutput -invite versions = +invite : Context (VBA a) -> InviteInput -> Task X.Error InviteOutput +invite context input = VC.withBottomLayer { current = Api.inviteV1 , version = "r0.0.0" @@ -23,9 +24,7 @@ invite versions = |> VC.addMiddleLayer { downcast = \data -> - { accessToken = data.accessToken - , baseUrl = data.baseUrl - , roomId = data.roomId + { roomId = data.roomId , userId = data.userId } , current = Api.inviteV2 @@ -36,8 +35,10 @@ invite versions = |> VC.sameForVersion "v1.3" |> VC.sameForVersion "v1.4" |> VC.sameForVersion "v1.5" - |> VC.mostRecentFromVersionList versions - |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) + |> VC.mostRecentFromVersionList (Context.getVersions context) + |> Maybe.withDefault (always <| always <| Task.fail X.UnsupportedSpecVersion) + |> (|>) input + |> (|>) context type alias InviteInput = diff --git a/src/Internal/Api/JoinedMembers/Api.elm b/src/Internal/Api/JoinedMembers/Api.elm index 27d95d8..64172c5 100644 --- a/src/Internal/Api/JoinedMembers/Api.elm +++ b/src/Internal/Api/JoinedMembers/Api.elm @@ -2,14 +2,13 @@ module Internal.Api.JoinedMembers.Api exposing (..) import Internal.Api.JoinedMembers.V1.SpecObjects as SO1 import Internal.Api.Request as R +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Task exposing (Task) type alias JoinedMembersInputV1 = - { accessToken : String - , baseUrl : String - , roomId : String + { roomId : String } @@ -17,35 +16,21 @@ type alias JoinedMembersOutputV1 = SO1.RoomMemberList -joinedMembersV1 : JoinedMembersInputV1 -> Task X.Error JoinedMembersOutputV1 -joinedMembersV1 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "GET" - , baseUrl = data.baseUrl - , path = "/_matrix/client/r0/rooms/{roomId}/joined_members" - , pathParams = - [ ( "roomId", data.roomId ) +joinedMembersV1 : JoinedMembersInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error JoinedMembersOutputV1 +joinedMembersV1 { roomId } = + R.callApi "GET" "/_matrix/client/r0/rooms/{roomId}/joined_members" + >> R.withAttributes + [ R.accessToken + , R.replaceInUrl "roomId" roomId ] - , queryParams = [] - , bodyParams = [] - , timeout = Nothing - , decoder = \_ -> SO1.roomMemberListDecoder - } + >> R.toTask SO1.roomMemberListDecoder -joinedMembersV2 : JoinedMembersInputV1 -> Task X.Error JoinedMembersOutputV1 -joinedMembersV2 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "GET" - , baseUrl = data.baseUrl - , path = "/_matrix/client/v3/rooms/{roomId}/joined_members" - , pathParams = - [ ( "roomId", data.roomId ) +joinedMembersV2 : JoinedMembersInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error JoinedMembersOutputV1 +joinedMembersV2 { roomId } = + R.callApi "GET" "/_matrix/client/v3/rooms/{roomId}/joined_members" + >> R.withAttributes + [ R.accessToken + , R.replaceInUrl "roomId" roomId ] - , queryParams = [] - , bodyParams = [] - , timeout = Nothing - , decoder = \_ -> SO1.roomMemberListDecoder - } + >> R.toTask SO1.roomMemberListDecoder diff --git a/src/Internal/Api/JoinedMembers/Main.elm b/src/Internal/Api/JoinedMembers/Main.elm index 2225f23..859a317 100644 --- a/src/Internal/Api/JoinedMembers/Main.elm +++ b/src/Internal/Api/JoinedMembers/Main.elm @@ -1,13 +1,14 @@ module Internal.Api.JoinedMembers.Main exposing (..) import Internal.Api.JoinedMembers.Api as Api +import Internal.Tools.Context as Context exposing (Context, VBA) import Internal.Tools.Exceptions as X import Internal.Tools.VersionControl as VC import Task exposing (Task) -joinedMembers : List String -> JoinedMembersInput -> Task X.Error JoinedMembersOutput -joinedMembers versions = +joinedMembers : Context (VBA a) -> JoinedMembersInput -> Task X.Error JoinedMembersOutput +joinedMembers context input = VC.withBottomLayer { current = Api.joinedMembersV1 , version = "r0.0.0" @@ -30,8 +31,10 @@ joinedMembers versions = |> VC.sameForVersion "v1.3" |> VC.sameForVersion "v1.4" |> VC.sameForVersion "v1.5" - |> VC.mostRecentFromVersionList versions - |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) + |> VC.mostRecentFromVersionList (Context.getVersions context) + |> Maybe.withDefault (always <| always <| Task.fail X.UnsupportedSpecVersion) + |> (|>) input + |> (|>) context type alias JoinedMembersInput = diff --git a/src/Internal/Api/LoginWithUsernameAndPassword/Api.elm b/src/Internal/Api/LoginWithUsernameAndPassword/Api.elm index a5aa1c8..d4253d2 100644 --- a/src/Internal/Api/LoginWithUsernameAndPassword/Api.elm +++ b/src/Internal/Api/LoginWithUsernameAndPassword/Api.elm @@ -2,14 +2,14 @@ module Internal.Api.LoginWithUsernameAndPassword.Api exposing (..) import Internal.Api.LoginWithUsernameAndPassword.V1.Login as SO import Internal.Api.Request as R +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Json.Encode as E import Task exposing (Task) type alias LoginWithUsernameAndPasswordInputV1 = - { baseUrl : String - , password : String + { password : String , username : String } @@ -18,24 +18,16 @@ type alias LoginWithUsernameAndPasswordOutputV1 = SO.LoggedInResponse -loginWithUsernameAndPasswordV1 : LoginWithUsernameAndPasswordInputV1 -> Task X.Error LoginWithUsernameAndPasswordOutputV1 -loginWithUsernameAndPasswordV1 data = - R.rawApiCall - { headers = R.NoHeaders - , method = "POST" - , baseUrl = data.baseUrl - , path = "/_matrix/client/v3/login" - , pathParams = [] - , queryParams = [] - , bodyParams = +loginWithUsernameAndPasswordV1 : LoginWithUsernameAndPasswordInputV1 -> Context { a | baseUrl : () } -> Task X.Error LoginWithUsernameAndPasswordOutputV1 +loginWithUsernameAndPasswordV1 { username, password } = + R.callApi "POST" "/_matrix/client/v3/login" + >> R.withAttributes [ [ ( "type", E.string "m.id.user" ) - , ( "user", E.string data.username ) + , ( "user", E.string username ) ] |> E.object - |> R.RequiredValue "identifier" - , R.RequiredString "password" data.password - , R.RequiredString "type" "m.login.password" + |> R.bodyValue "identifier" + , R.bodyString "password" password + , R.bodyString "type" "m.login.password" ] - , timeout = Nothing - , decoder = always SO.loggedInResponseDecoder - } + >> R.toTask SO.loggedInResponseDecoder diff --git a/src/Internal/Api/LoginWithUsernameAndPassword/Main.elm b/src/Internal/Api/LoginWithUsernameAndPassword/Main.elm index 8f4940c..e2797e6 100644 --- a/src/Internal/Api/LoginWithUsernameAndPassword/Main.elm +++ b/src/Internal/Api/LoginWithUsernameAndPassword/Main.elm @@ -1,19 +1,22 @@ module Internal.Api.LoginWithUsernameAndPassword.Main exposing (..) import Internal.Api.LoginWithUsernameAndPassword.Api as Api +import Internal.Tools.Context as Context exposing (Context, VBA) import Internal.Tools.Exceptions as X import Internal.Tools.VersionControl as VC import Task exposing (Task) -loginWithUsernameAndPassword : List String -> LoginWithUsernameAndPasswordInput -> Task X.Error LoginWithUsernameAndPasswordOutput -loginWithUsernameAndPassword versions = +loginWithUsernameAndPassword : Context (VBA a) -> LoginWithUsernameAndPasswordInput -> Task X.Error LoginWithUsernameAndPasswordOutput +loginWithUsernameAndPassword context input = VC.withBottomLayer { current = Api.loginWithUsernameAndPasswordV1 , version = "v1.5" } - |> VC.mostRecentFromVersionList versions - |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) + |> VC.mostRecentFromVersionList (Context.getVersions context) + |> Maybe.withDefault (always <| always <| Task.fail X.UnsupportedSpecVersion) + |> (|>) input + |> (|>) context type alias LoginWithUsernameAndPasswordInput = diff --git a/src/Internal/Api/PreApi/Main.elm b/src/Internal/Api/PreApi/Main.elm deleted file mode 100644 index 5a7b41c..0000000 --- a/src/Internal/Api/PreApi/Main.elm +++ /dev/null @@ -1,90 +0,0 @@ -module Internal.Api.PreApi.Main exposing (..) - -{-| Certain values are required knowledge for (almost) every endpoint. -Some values aren't known right away, however. - -This module takes care of values like access tokens, transaction ids and spec version lists -that the credentials type needs to know about before it can make a request. - --} - -import Internal.Api.LoginWithUsernameAndPassword.V1.Login as L -import Internal.Api.Request as R -import Internal.Api.Versions.V1.Versions as V -import Internal.Tools.Exceptions as X -import Internal.Tools.LoginValues exposing (AccessToken(..)) -import Internal.Tools.ValueGetter exposing (ValueGetter) -import Json.Encode as E -import Task -import Time - - -accessToken : String -> AccessToken -> ValueGetter X.Error String -accessToken baseUrl t = - { value = - case t of - NoAccess -> - Nothing - - AccessToken token -> - Just token - - UsernameAndPassword { token } -> - token - , getValue = - case t of - UsernameAndPassword { username, password } -> - R.rawApiCall - { headers = R.NoHeaders - , method = "POST" - , baseUrl = baseUrl - , path = "/_matrix/client/v3/login" - , pathParams = [] - , queryParams = [] - , bodyParams = - [ [ ( "type", E.string "m.id.user" ) - , ( "user", E.string username ) - ] - |> E.object - |> R.RequiredValue "identifier" - , R.RequiredString "password" password - , R.RequiredString "type" "m.login.password" - ] - , timeout = Nothing - , decoder = \_ -> L.loggedInResponseDecoder - } - |> Task.map .accessToken - - _ -> - X.NoAccessToken - |> X.SDKException - |> Task.fail - } - - -transactionId : (Int -> String) -> ValueGetter X.Error String -transactionId seeder = - { value = Nothing - , getValue = - Time.now - |> Task.map Time.posixToMillis - |> Task.map seeder - } - - -versions : String -> Maybe V.Versions -> ValueGetter X.Error V.Versions -versions baseUrl mVersions = - { value = mVersions - , getValue = - R.rawApiCall - { headers = R.NoHeaders - , method = "GET" - , baseUrl = baseUrl - , path = "/_matrix/client/versions" - , pathParams = [] - , queryParams = [] - , bodyParams = [] - , timeout = Nothing - , decoder = \_ -> V.versionsDecoder - } - } diff --git a/src/Internal/Api/Redact/Api.elm b/src/Internal/Api/Redact/Api.elm index 9fda15e..2f9238b 100644 --- a/src/Internal/Api/Redact/Api.elm +++ b/src/Internal/Api/Redact/Api.elm @@ -2,16 +2,14 @@ module Internal.Api.Redact.Api exposing (..) import Internal.Api.Redact.V1.SpecObjects as SO1 import Internal.Api.Request as R +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Task exposing (Task) type alias RedactInputV1 = - { accessToken : String - , baseUrl : String - , roomId : String + { roomId : String , eventId : String - , txnId : String , reason : Maybe String } @@ -20,41 +18,27 @@ type alias RedactOutputV1 = SO1.Redaction -redactV1 : RedactInputV1 -> Task X.Error RedactOutputV1 -redactV1 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "PUT" - , baseUrl = data.baseUrl - , path = "/_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}" - , pathParams = - [ ( "roomId", data.roomId ) - , ( "eventId", data.eventId ) - , ( "txnId", data.txnId ) +redactV1 : RedactInputV1 -> Context { a | accessToken : (), baseUrl : (), transactionId : () } -> Task X.Error RedactOutputV1 +redactV1 { eventId, reason, roomId } = + R.callApi "PUT" "/_matrix/client/r0/rooms/{roomId}/redact/{eventId}/{txnId}" + >> R.withAttributes + [ R.accessToken + , R.withTransactionId + , R.replaceInUrl "eventId" eventId + , R.replaceInUrl "roomId" roomId + , R.bodyOpString "reason" reason ] - , queryParams = [] - , bodyParams = - [ R.OptionalString "reason" data.reason - ] - , timeout = Nothing - , decoder = always SO1.redactionDecoder - } + >> R.toTask SO1.redactionDecoder -redactV2 : RedactInputV1 -> Task X.Error RedactOutputV1 -redactV2 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "PUT" - , baseUrl = data.baseUrl - , path = "/_matrix/client/v3/rooms/{roomId}/redact/{eventId}/{txnId}" - , pathParams = - [ ( "roomId", data.roomId ) - , ( "eventId", data.eventId ) - , ( "txnId", data.txnId ) +redactV2 : RedactInputV1 -> Context { a | accessToken : (), baseUrl : (), transactionId : () } -> Task X.Error RedactOutputV1 +redactV2 { eventId, reason, roomId } = + R.callApi "PUT" "/_matrix/client/v3/rooms/{roomId}/redact/{eventId}/{txnId}" + >> R.withAttributes + [ R.accessToken + , R.withTransactionId + , R.replaceInUrl "eventId" eventId + , R.replaceInUrl "roomId" roomId + , R.bodyOpString "reason" reason ] - , queryParams = [] - , bodyParams = [] - , timeout = Nothing - , decoder = always SO1.redactionDecoder - } + >> R.toTask SO1.redactionDecoder diff --git a/src/Internal/Api/Redact/Main.elm b/src/Internal/Api/Redact/Main.elm index 62cd303..90c35ea 100644 --- a/src/Internal/Api/Redact/Main.elm +++ b/src/Internal/Api/Redact/Main.elm @@ -1,13 +1,14 @@ module Internal.Api.Redact.Main exposing (..) import Internal.Api.Redact.Api as Api +import Internal.Tools.Context as Context exposing (Context, VBAT) import Internal.Tools.Exceptions as X import Internal.Tools.VersionControl as VC import Task exposing (Task) -redact : List String -> RedactInput -> Task X.Error RedactOutput -redact versions = +redact : Context (VBAT a) -> RedactInput -> Task X.Error RedactOutput +redact context input = VC.withBottomLayer { current = Api.redactV1 , version = "r0.0.0" @@ -30,8 +31,10 @@ redact versions = |> VC.sameForVersion "v1.3" |> VC.sameForVersion "v1.4" |> VC.sameForVersion "v1.5" - |> VC.mostRecentFromVersionList versions - |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) + |> VC.mostRecentFromVersionList (Context.getVersions context) + |> Maybe.withDefault (always <| always <| Task.fail X.UnsupportedSpecVersion) + |> (|>) input + |> (|>) context type alias RedactInput = diff --git a/src/Internal/Api/Request.elm b/src/Internal/Api/Request.elm index 3f854f3..5c7cbc4 100644 --- a/src/Internal/Api/Request.elm +++ b/src/Internal/Api/Request.elm @@ -1,229 +1,321 @@ module Internal.Api.Request exposing (..) import Http +import Internal.Tools.Context as Context exposing (Context) import Internal.Tools.Exceptions as X import Json.Decode as D import Json.Encode as E import Process import Task exposing (Task) import Time +import Url import Url.Builder as UrlBuilder -{-| Make a raw API call to a Matrix API. --} -rawApiCall : - { headers : Headers - , method : String - , baseUrl : String - , path : String - , pathParams : List ( String, String ) - , queryParams : List QueryParam - , bodyParams : List BodyParam - , timeout : Maybe Float - , decoder : Int -> D.Decoder a - } - -> Task X.Error a -rawApiCall data = - Http.task - { method = data.method - , headers = fromHeaders data.headers - , url = buildUrl data.baseUrl data.path data.pathParams data.queryParams - , body = toBody data.bodyParams - , resolver = rawApiCallResolver data.decoder - , timeout = data.timeout +type ApiCall ph + = ApiCall + { attributes : List ContextAttr + , baseUrl : String + , context : Context ph + , method : String } -withRateLimits : Int -> Task X.Error a -> Task X.Error a -withRateLimits timeout task = - Time.now - |> Task.onError - (\_ -> X.CouldntGetTimestamp |> X.SDKException |> Task.fail) - |> Task.andThen - (\now -> - task - |> Task.onError - (\err -> - case err of - X.ServerException (X.M_LIMIT_EXCEEDED data) -> - case data.retryAfterMs of - Just t -> - Process.sleep (toFloat t) - |> Task.andThen (\_ -> Time.now) - |> Task.andThen - (\newNow -> - let - diff : Int - diff = - timeout - (Time.posixToMillis newNow - Time.posixToMillis now) - in - if diff <= 0 then - Task.fail err +type alias Attribute a = + Context a -> ContextAttr - else - withRateLimits diff task - ) - Nothing -> - Task.fail err +type ContextAttr + = BodyParam String E.Value + | FullBody E.Value + | Header Http.Header + | NoAttr + | QueryParam UrlBuilder.QueryParameter + | ReplaceInUrl String String + | Timeout Float + | UrlPath String + + +callApi : String -> String -> Context { a | baseUrl : () } -> ApiCall { a | baseUrl : () } +callApi method path context = + ApiCall + { attributes = + [ UrlPath path + ] + , baseUrl = Context.getBaseUrl context + , context = context + , method = method + } + + + +{- GETTING VALUES + + Once a user has finished building the ApiCall, we will build the task. +-} + + +toTask : D.Decoder a -> ApiCall ph -> Task X.Error a +toTask decoder (ApiCall data) = + Http.task + { method = data.method + , headers = + List.filterMap + (\attr -> + case attr of + Header h -> + Just h + + _ -> + Nothing + ) + data.attributes + , url = getUrl (ApiCall data) + , body = + data.attributes + |> List.filterMap + (\attr -> + case attr of + FullBody v -> + Just v + + _ -> + Nothing + ) + |> List.reverse + |> List.head + |> Maybe.withDefault + (List.filterMap + (\attr -> + case attr of + BodyParam key value -> + Just ( key, value ) _ -> - Task.fail err + Nothing ) - ) - - -{-| Potential headers to go along with a Matrix API call. --} -type Headers - = NoHeaders - | WithAccessToken String - | WithContentType String - | WithBoth { accessToken : String, contentType : String } - - -{-| Turn Headers into useful values --} -fromHeaders : Headers -> List Http.Header -fromHeaders h = - (case h of - NoHeaders -> - [ ( "Content-Type", "application/json" ) ] - - WithAccessToken token -> - [ ( "Content-Type", "application/json" ), ( "Authorization", "Bearer " ++ token ) ] - - WithContentType contentType -> - [ ( "Content-Type", contentType ) ] - - WithBoth data -> - [ ( "Content-Type", data.contentType ), ( "Authorization", "Bearer " ++ data.accessToken ) ] - ) - |> List.map (\( a, b ) -> Http.header a b) - - -{-| -} -type QueryParam - = QueryParamString String String - | OpQueryParamString String (Maybe String) - | QueryParamInt String Int - | OpQueryParamInt String (Maybe Int) - | QueryParamBool String Bool - | OpQueryParamBool String (Maybe Bool) - - -fromQueryParam : QueryParam -> Maybe UrlBuilder.QueryParameter -fromQueryParam param = - case param of - QueryParamString key value -> - Just <| UrlBuilder.string key value - - OpQueryParamString key value -> - Maybe.map (UrlBuilder.string key) value - - QueryParamInt key value -> - Just <| UrlBuilder.int key value - - OpQueryParamInt key value -> - Maybe.map (UrlBuilder.int key) value - - QueryParamBool key value -> - if value then - Just <| UrlBuilder.string key "true" - - else - Just <| UrlBuilder.string key "false" - - OpQueryParamBool key value -> - Maybe.andThen (QueryParamBool key >> fromQueryParam) value - - -fromQueryParams : List QueryParam -> List UrlBuilder.QueryParameter -fromQueryParams = - List.map fromQueryParam - >> List.filterMap identity - - -buildUrl : String -> String -> List ( String, String ) -> List QueryParam -> String -buildUrl baseUrl path pathParams queryParams = - let - fullPath : String - fullPath = - List.foldl - (\( a, b ) -> String.replace ("{" ++ a ++ "}") b) - path - pathParams - |> (\s -> - if String.startsWith "/" s then - String.dropLeft 1 s - - else - s - ) - in - UrlBuilder.crossOrigin baseUrl [ fullPath ] (fromQueryParams queryParams) - - -{-| Type that gathers all parameters that go in the request body. --} -type BodyParam - = OptionalString String (Maybe String) - | RequiredString String String - | OptionalInt String (Maybe Int) - | RequiredInt String Int - | OptionalValue String (Maybe E.Value) - | RequiredValue String E.Value - - -encodeBodyParam : BodyParam -> ( String, Maybe E.Value ) -encodeBodyParam b = - case b of - OptionalString h s -> - ( h, Maybe.map E.string s ) - - RequiredString h s -> - ( h, Just <| E.string s ) - - OptionalInt h i -> - ( h, Maybe.map E.int i ) - - RequiredInt h i -> - ( h, Just <| E.int i ) - - OptionalValue h v -> - ( h, v ) - - RequiredValue h v -> - ( h, Just v ) - - -toBody : List BodyParam -> Http.Body -toBody params = - case params of - (RequiredValue "*" v) :: [] -> - Http.jsonBody v - - _ -> - List.map encodeBodyParam params - |> maybeObject + data.attributes + |> E.object + ) |> Http.jsonBody + , resolver = rawApiCallResolver (always decoder) + , timeout = + data.attributes + |> List.filterMap + (\attr -> + case attr of + Timeout t -> + Just t + + _ -> + Nothing + ) + |> List.reverse + |> List.head + } -{-| Create a body object based on optionally provided values. --} -maybeObject : List ( String, Maybe E.Value ) -> E.Value -maybeObject = +getUrl : ApiCall a -> String +getUrl (ApiCall { baseUrl, attributes }) = + UrlBuilder.crossOrigin + baseUrl + (getPath attributes |> List.singleton) + (getQueryParams attributes) + + +getPath : List ContextAttr -> String +getPath = + List.foldl + (\attr prior -> + case attr of + UrlPath posterior -> + posterior + + ReplaceInUrl from to -> + String.replace from to prior + + _ -> + prior + ) + "" + + +getQueryParams : List ContextAttr -> List UrlBuilder.QueryParameter +getQueryParams = List.filterMap - (\( name, value ) -> - case value of - Just v -> - Just ( name, v ) + (\attr -> + case attr of + QueryParam q -> + Just q _ -> Nothing ) - >> E.object + + + +{- ATTRIBUTES + + The following functions can alter how an ApiCall behaves, + and what information it will give to the Matrix API. +-} + + +withAttributes : List (Attribute a) -> ApiCall a -> ApiCall a +withAttributes attrs (ApiCall data) = + ApiCall + { attributes = + attrs + |> List.map (\attr -> attr data.context) + |> List.append data.attributes + , baseUrl = data.baseUrl + , context = data.context + , method = data.method + } + + +accessToken : Attribute { a | accessToken : () } +accessToken = + Context.getAccessToken + >> Http.header "Authorization" + >> Header + + +bodyBool : String -> Bool -> Attribute a +bodyBool key value = + bodyValue key (E.bool value) + + +bodyInt : String -> Int -> Attribute a +bodyInt key value = + bodyValue key (E.int value) + + +bodyOpBool : String -> Maybe Bool -> Attribute a +bodyOpBool key value = + case value of + Just b -> + bodyBool key b + + Nothing -> + always NoAttr + + +bodyOpInt : String -> Maybe Int -> Attribute a +bodyOpInt key value = + case value of + Just i -> + bodyInt key i + + Nothing -> + always NoAttr + + +bodyOpString : String -> Maybe String -> Attribute a +bodyOpString key value = + case value of + Just s -> + bodyString key s + + Nothing -> + always NoAttr + + +bodyOpValue : String -> Maybe E.Value -> Attribute a +bodyOpValue key value = + case value of + Just v -> + bodyValue key v + + Nothing -> + always NoAttr + + +bodyString : String -> String -> Attribute a +bodyString key value = + bodyValue key (E.string value) + + +bodyValue : String -> E.Value -> Attribute a +bodyValue key value _ = + BodyParam key value + + +fullBody : E.Value -> Attribute a +fullBody value _ = + FullBody value + + +queryBool : String -> Bool -> Attribute a +queryBool key value _ = + (if value then + "true" + + else + "false" + ) + |> UrlBuilder.string key + |> QueryParam + + +queryOpBool : String -> Maybe Bool -> Attribute a +queryOpBool key value = + case value of + Just b -> + queryBool key b + + Nothing -> + always NoAttr + + +queryInt : String -> Int -> Attribute a +queryInt key value _ = + QueryParam <| UrlBuilder.int key value + + +queryOpInt : String -> Maybe Int -> Attribute a +queryOpInt key value = + case value of + Just i -> + queryInt key i + + Nothing -> + always NoAttr + + +queryOpString : String -> Maybe String -> Attribute a +queryOpString key value = + case value of + Just s -> + queryString key s + + Nothing -> + always NoAttr + + +queryString : String -> String -> Attribute a +queryString key value _ = + QueryParam <| UrlBuilder.string key value + + +replaceInUrl : String -> String -> Attribute a +replaceInUrl key value _ = + ReplaceInUrl ("{" ++ key ++ "}") (Url.percentEncode value) + + +timeout : Maybe Float -> Attribute a +timeout mf _ = + case mf of + Just f -> + Timeout f + + Nothing -> + NoAttr + + +withTransactionId : Attribute { a | transactionId : () } +withTransactionId = + Context.getTransactionId >> ReplaceInUrl "txnId" rawApiCallResolver : (Int -> D.Decoder a) -> Http.Resolver X.Error a diff --git a/src/Internal/Api/SendMessageEvent/Api.elm b/src/Internal/Api/SendMessageEvent/Api.elm index b640dbf..63f26f6 100644 --- a/src/Internal/Api/SendMessageEvent/Api.elm +++ b/src/Internal/Api/SendMessageEvent/Api.elm @@ -2,18 +2,16 @@ module Internal.Api.SendMessageEvent.Api exposing (SendMessageEventInputV1, Send import Internal.Api.Request as R import Internal.Api.SendMessageEvent.V1.SpecObjects as SO1 +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Json.Decode as D import Task exposing (Task) type alias SendMessageEventInputV1 = - { accessToken : String - , baseUrl : String - , content : D.Value + { content : D.Value , eventType : String , roomId : String - , transactionId : String } @@ -21,39 +19,27 @@ type alias SendMessageEventOutputV1 = SO1.EventResponse -sendMessageEventV1 : SendMessageEventInputV1 -> Task X.Error SendMessageEventOutputV1 -sendMessageEventV1 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "PUT" - , baseUrl = data.baseUrl - , path = "/_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}" - , pathParams = - [ ( "eventType", data.eventType ) - , ( "roomId", data.roomId ) - , ( "txnId", data.transactionId ) +sendMessageEventV1 : SendMessageEventInputV1 -> Context { a | accessToken : (), baseUrl : (), transactionId : () } -> Task X.Error SendMessageEventOutputV1 +sendMessageEventV1 { content, eventType, roomId } = + R.callApi "PUT" "/_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}" + >> R.withAttributes + [ R.accessToken + , R.withTransactionId + , R.replaceInUrl "eventType" eventType + , R.replaceInUrl "roomId" roomId + , R.fullBody content ] - , queryParams = [] - , bodyParams = [ R.RequiredValue "*" data.content ] - , timeout = Nothing - , decoder = \_ -> SO1.eventResponseDecoder - } + >> R.toTask SO1.eventResponseDecoder -sendMessageEventV2 : SendMessageEventInputV1 -> Task X.Error SendMessageEventOutputV1 -sendMessageEventV2 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "PUT" - , baseUrl = data.baseUrl - , path = "/_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}" - , pathParams = - [ ( "eventType", data.eventType ) - , ( "roomId", data.roomId ) - , ( "txnId", data.transactionId ) +sendMessageEventV2 : SendMessageEventInputV1 -> Context { a | accessToken : (), baseUrl : (), transactionId : () } -> Task X.Error SendMessageEventOutputV1 +sendMessageEventV2 { content, eventType, roomId } = + R.callApi "PUT" "/_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}" + >> R.withAttributes + [ R.accessToken + , R.withTransactionId + , R.replaceInUrl "eventType" eventType + , R.replaceInUrl "roomId" roomId + , R.fullBody content ] - , queryParams = [] - , bodyParams = [ R.RequiredValue "*" data.content ] - , timeout = Nothing - , decoder = \_ -> SO1.eventResponseDecoder - } + >> R.toTask SO1.eventResponseDecoder diff --git a/src/Internal/Api/SendMessageEvent/Main.elm b/src/Internal/Api/SendMessageEvent/Main.elm index 22428d2..2b727ba 100644 --- a/src/Internal/Api/SendMessageEvent/Main.elm +++ b/src/Internal/Api/SendMessageEvent/Main.elm @@ -1,13 +1,14 @@ module Internal.Api.SendMessageEvent.Main exposing (..) import Internal.Api.SendMessageEvent.Api as Api +import Internal.Tools.Context as Context exposing (Context, VBAT) import Internal.Tools.Exceptions as X import Internal.Tools.VersionControl as VC import Task exposing (Task) -sendMessageEvent : List String -> SendMessageEventInput -> Task X.Error SendMessageEventOutput -sendMessageEvent versions = +sendMessageEvent : Context (VBAT a) -> SendMessageEventInput -> Task X.Error SendMessageEventOutput +sendMessageEvent context input = VC.withBottomLayer { current = Api.sendMessageEventV1 , version = "r0.0.0" @@ -30,8 +31,10 @@ sendMessageEvent versions = |> VC.sameForVersion "v1.3" |> VC.sameForVersion "v1.4" |> VC.sameForVersion "v1.5" - |> VC.mostRecentFromVersionList versions - |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) + |> VC.mostRecentFromVersionList (Context.getVersions context) + |> Maybe.withDefault (always <| always <| Task.fail X.UnsupportedSpecVersion) + |> (|>) input + |> (|>) context type alias SendMessageEventInput = diff --git a/src/Internal/Api/SendStateKey/Api.elm b/src/Internal/Api/SendStateKey/Api.elm index 13ebd25..c8b29b4 100644 --- a/src/Internal/Api/SendStateKey/Api.elm +++ b/src/Internal/Api/SendStateKey/Api.elm @@ -2,15 +2,14 @@ module Internal.Api.SendStateKey.Api exposing (..) import Internal.Api.Request as R import Internal.Api.SendStateKey.V1.SpecObjects as SO1 +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Json.Decode as D import Task exposing (Task) type alias SendStateKeyInputV1 = - { accessToken : String - , baseUrl : String - , content : D.Value + { content : D.Value , eventType : String , roomId : String , stateKey : String @@ -21,39 +20,27 @@ type alias SendStateKeyOutputV1 = SO1.EventResponse -sendStateKeyV1 : SendStateKeyInputV1 -> Task X.Error SendStateKeyOutputV1 -sendStateKeyV1 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "PUT" - , baseUrl = data.baseUrl - , path = "/_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}" - , pathParams = - [ ( "eventType", data.eventType ) - , ( "roomId", data.roomId ) - , ( "stateKey", data.stateKey ) +sendStateKeyV1 : SendStateKeyInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error SendStateKeyOutputV1 +sendStateKeyV1 { content, eventType, roomId, stateKey } = + R.callApi "PUT" "/_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}" + >> R.withAttributes + [ R.accessToken + , R.replaceInUrl "eventType" eventType + , R.replaceInUrl "roomId" roomId + , R.replaceInUrl "stateKey" stateKey + , R.fullBody content ] - , queryParams = [] - , bodyParams = [ R.RequiredValue "*" data.content ] - , timeout = Nothing - , decoder = \_ -> SO1.eventResponseDecoder - } + >> R.toTask SO1.eventResponseDecoder -sendStateKeyV2 : SendStateKeyInputV1 -> Task X.Error SendStateKeyOutputV1 -sendStateKeyV2 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "PUT" - , baseUrl = data.baseUrl - , path = "/_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}" - , pathParams = - [ ( "eventType", data.eventType ) - , ( "roomId", data.roomId ) - , ( "stateKey", data.stateKey ) +sendStateKeyV2 : SendStateKeyInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error SendStateKeyOutputV1 +sendStateKeyV2 { content, eventType, roomId, stateKey } = + R.callApi "PUT" "/_matrix/client/v3/rooms/{roomId}/state/{eventType}/{stateKey}" + >> R.withAttributes + [ R.accessToken + , R.replaceInUrl "eventType" eventType + , R.replaceInUrl "roomId" roomId + , R.replaceInUrl "stateKey" stateKey + , R.fullBody content ] - , queryParams = [] - , bodyParams = [ R.RequiredValue "*" data.content ] - , timeout = Nothing - , decoder = \_ -> SO1.eventResponseDecoder - } + >> R.toTask SO1.eventResponseDecoder diff --git a/src/Internal/Api/SendStateKey/Main.elm b/src/Internal/Api/SendStateKey/Main.elm index 92adc3c..47c17cb 100644 --- a/src/Internal/Api/SendStateKey/Main.elm +++ b/src/Internal/Api/SendStateKey/Main.elm @@ -1,13 +1,14 @@ module Internal.Api.SendStateKey.Main exposing (..) import Internal.Api.SendStateKey.Api as Api +import Internal.Tools.Context as Context exposing (Context, VBA) import Internal.Tools.Exceptions as X import Internal.Tools.VersionControl as VC import Task exposing (Task) -sendStateKey : List String -> SendStateKeyInput -> Task X.Error SendStateKeyOutput -sendStateKey versions = +sendStateKey : Context (VBA a) -> SendStateKeyInput -> Task X.Error SendStateKeyOutput +sendStateKey context input = VC.withBottomLayer { current = Api.sendStateKeyV1 , version = "r0.0.0" @@ -30,8 +31,10 @@ sendStateKey versions = |> VC.sameForVersion "v1.3" |> VC.sameForVersion "v1.4" |> VC.sameForVersion "v1.5" - |> VC.mostRecentFromVersionList versions - |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) + |> VC.mostRecentFromVersionList (Context.getVersions context) + |> Maybe.withDefault (always <| always <| Task.fail X.UnsupportedSpecVersion) + |> (|>) input + |> (|>) context type alias SendStateKeyInput = diff --git a/src/Internal/Api/Sync/Api.elm b/src/Internal/Api/Sync/Api.elm index 5b29faa..3b48102 100644 --- a/src/Internal/Api/Sync/Api.elm +++ b/src/Internal/Api/Sync/Api.elm @@ -3,15 +3,14 @@ module Internal.Api.Sync.Api exposing (..) import Internal.Api.Request as R import Internal.Api.Sync.V1.SpecObjects as SO1 import Internal.Api.Sync.V2.SpecObjects as SO2 +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Internal.Tools.SpecEnums as Enums import Task exposing (Task) type alias SyncInputV1 = - { accessToken : String - , baseUrl : String - , filter : Maybe String + { filter : Maybe String , fullState : Maybe Bool , setPresence : Maybe Enums.UserPresence , since : Maybe String @@ -27,49 +26,31 @@ type alias SyncOutputV2 = SO2.Sync -syncV1 : SyncInputV1 -> Task X.Error SyncOutputV1 +syncV1 : SyncInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error SyncOutputV1 syncV1 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "GET" - , baseUrl = data.baseUrl - , path = "/_matrix/client/v3/sync" - , pathParams = [] - , queryParams = - [ R.OpQueryParamString "filter" data.filter - , R.OpQueryParamBool "full_state" data.fullState - , R.OpQueryParamString "set_presence" (Maybe.map Enums.fromUserPresence data.setPresence) - , R.OpQueryParamString "since" data.since - , R.OpQueryParamInt "timeout" data.timeout + R.callApi "GET" "/_matrix/client/v3/sync" + >> R.withAttributes + [ R.accessToken + , R.queryOpString "filter" data.filter + , R.queryOpBool "full_state" data.fullState + , R.queryOpString "set_presence" (Maybe.map Enums.fromUserPresence data.setPresence) + , R.queryOpString "since" data.since + , R.queryOpInt "timeout" data.timeout + , R.timeout <| Maybe.map ((*) 1000 >> toFloat) <| data.timeout ] - , bodyParams = [] - , timeout = - data.timeout - |> Maybe.map ((*) 1000) - |> Maybe.map toFloat - , decoder = \_ -> SO1.syncDecoder - } + >> R.toTask SO1.syncDecoder -syncV2 : SyncInputV1 -> Task X.Error SyncOutputV2 +syncV2 : SyncInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error SyncOutputV2 syncV2 data = - R.rawApiCall - { headers = R.WithAccessToken data.accessToken - , method = "GET" - , baseUrl = data.baseUrl - , path = "/_matrix/client/v3/sync" - , pathParams = [] - , queryParams = - [ R.OpQueryParamString "filter" data.filter - , R.OpQueryParamBool "full_state" data.fullState - , R.OpQueryParamString "set_presence" (Maybe.map Enums.fromUserPresence data.setPresence) - , R.OpQueryParamString "since" data.since - , R.OpQueryParamInt "timeout" data.timeout + R.callApi "GET" "/_matrix/client/v3/sync" + >> R.withAttributes + [ R.accessToken + , R.queryOpString "filter" data.filter + , R.queryOpBool "full_state" data.fullState + , R.queryOpString "set_presence" (Maybe.map Enums.fromUserPresence data.setPresence) + , R.queryOpString "since" data.since + , R.queryOpInt "timeout" data.timeout + , R.timeout <| Maybe.map ((*) 1000 >> toFloat) <| data.timeout ] - , bodyParams = [] - , timeout = - data.timeout - |> Maybe.map ((*) 1000) - |> Maybe.map toFloat - , decoder = \_ -> SO2.syncDecoder - } + >> R.toTask SO2.syncDecoder diff --git a/src/Internal/Api/Sync/Main.elm b/src/Internal/Api/Sync/Main.elm index c78718b..e32afdb 100644 --- a/src/Internal/Api/Sync/Main.elm +++ b/src/Internal/Api/Sync/Main.elm @@ -2,13 +2,14 @@ module Internal.Api.Sync.Main exposing (..) import Internal.Api.Sync.Api as Api import Internal.Api.Sync.V2.Upcast as U2 +import Internal.Tools.Context as Context exposing (Context, VBA) import Internal.Tools.Exceptions as X import Internal.Tools.VersionControl as VC import Task exposing (Task) -sync : List String -> SyncInput -> Task X.Error SyncOutput -sync versions = +sync : Context (VBA a) -> SyncInput -> Task X.Error SyncOutput +sync context input = VC.withBottomLayer { current = Api.syncV1 , version = "v1.2" @@ -21,8 +22,10 @@ sync versions = , version = "v1.4" } |> VC.sameForVersion "v1.5" - |> VC.mostRecentFromVersionList versions - |> Maybe.withDefault (always <| Task.fail X.UnsupportedSpecVersion) + |> VC.mostRecentFromVersionList (Context.getVersions context) + |> Maybe.withDefault (always <| always <| Task.fail X.UnsupportedSpecVersion) + |> (|>) input + |> (|>) context type alias SyncInput = diff --git a/src/Internal/Api/Versions/Api.elm b/src/Internal/Api/Versions/Api.elm index 93b3383..cb7d27e 100644 --- a/src/Internal/Api/Versions/Api.elm +++ b/src/Internal/Api/Versions/Api.elm @@ -2,20 +2,12 @@ module Internal.Api.Versions.Api exposing (..) import Internal.Api.Request as R import Internal.Api.Versions.V1.Versions as SO +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Task exposing (Task) -versionsV1 : { baseUrl : String } -> Task X.Error SO.Versions -versionsV1 data = - R.rawApiCall - { headers = R.NoHeaders - , method = "GET" - , baseUrl = data.baseUrl - , path = "/_matrix/client/versions" - , pathParams = [] - , queryParams = [] - , bodyParams = [] - , timeout = Nothing - , decoder = always SO.versionsDecoder - } +versionsV1 : Context { a | baseUrl : () } -> Task X.Error SO.Versions +versionsV1 = + R.callApi "GET" "/_matrix/client/versions" + >> R.toTask SO.versionsDecoder diff --git a/src/Internal/Api/Versions/Main.elm b/src/Internal/Api/Versions/Main.elm index b50886d..e37e6d8 100644 --- a/src/Internal/Api/Versions/Main.elm +++ b/src/Internal/Api/Versions/Main.elm @@ -2,18 +2,19 @@ module Internal.Api.Versions.Main exposing (..) import Internal.Api.Versions.Api as Api import Internal.Api.Versions.V1.Versions as SO +import Internal.Tools.Context exposing (Context) import Internal.Tools.Exceptions as X import Task exposing (Task) type alias VersionsInput = - String + () type alias VersionsOutput = SO.Versions -getVersions : VersionsInput -> Task X.Error VersionsOutput -getVersions baseUrl = - Api.versionsV1 { baseUrl = baseUrl } +getVersions : Context { a | baseUrl : () } -> Task X.Error VersionsOutput +getVersions context = + Api.versionsV1 context