Add status code errors

pull/1/head
Bram van den Heuvel 2023-04-18 14:55:11 +02:00
parent 3f4508d07c
commit 4aaabe3a0a
13 changed files with 221 additions and 30 deletions

View File

@ -1,6 +1,7 @@
module Internal.Api.Ban.Api exposing (..) module Internal.Api.Ban.Api exposing (..)
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context exposing (Context) import Internal.Tools.Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Json.Decode as D import Json.Decode as D
@ -26,6 +27,7 @@ banV1 { reason, roomId, userId } =
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.bodyOpString "reason" reason , R.bodyOpString "reason" reason
, R.bodyString "user_id" userId , R.bodyString "user_id" userId
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.banNotAllowed })
] ]
>> R.toTask (D.map (always ()) D.value) >> R.toTask (D.map (always ()) D.value)
@ -38,5 +40,6 @@ banV2 { reason, roomId, userId } =
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.bodyOpString "reason" reason , R.bodyOpString "reason" reason
, R.bodyString "user_id" userId , R.bodyString "user_id" userId
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.banNotAllowed })
] ]
>> R.toTask (D.map (always ()) D.value) >> R.toTask (D.map (always ()) D.value)

View File

@ -2,6 +2,7 @@ module Internal.Api.GetEvent.Api exposing (..)
import Internal.Api.GetEvent.V1.SpecObjects as SO1 import Internal.Api.GetEvent.V1.SpecObjects as SO1
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context as Context exposing (Context) import Internal.Tools.Context as Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Task exposing (Task) import Task exposing (Task)
@ -24,5 +25,6 @@ getEventInputV1 data context =
[ R.accessToken [ R.accessToken
, R.replaceInUrl "eventId" (Context.getSentEvent context) , R.replaceInUrl "eventId" (Context.getSentEvent context)
, R.replaceInUrl "roomId" data.roomId , R.replaceInUrl "roomId" data.roomId
, R.onStatusCode 404 (X.M_NOT_FOUND { error = Just SE.eventNotFound })
] ]
|> R.toTask SO1.clientEventDecoder |> R.toTask SO1.clientEventDecoder

View File

@ -5,6 +5,7 @@ import Internal.Api.GetMessages.V2.SpecObjects as SO2
import Internal.Api.GetMessages.V3.SpecObjects as SO3 import Internal.Api.GetMessages.V3.SpecObjects as SO3
import Internal.Api.GetMessages.V4.SpecObjects as SO4 import Internal.Api.GetMessages.V4.SpecObjects as SO4
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context exposing (Context) import Internal.Tools.Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Internal.Tools.SpecEnums as Enums import Internal.Tools.SpecEnums as Enums
@ -75,6 +76,7 @@ getMessagesV1 { direction, from, limit, roomId } =
, R.queryString "dir" (Enums.fromEventOrder direction) , R.queryString "dir" (Enums.fromEventOrder direction)
, R.queryString "from" f , R.queryString "from" f
, R.queryOpInt "limit" limit , R.queryOpInt "limit" limit
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO1.messagesResponseDecoder >> R.toTask SO1.messagesResponseDecoder
@ -94,6 +96,7 @@ getMessagesV2 { direction, from, limit, roomId, to } =
, R.queryString "from" f , R.queryString "from" f
, R.queryOpInt "limit" limit , R.queryOpInt "limit" limit
, R.queryOpString "to" to , R.queryOpString "to" to
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO1.messagesResponseDecoder >> R.toTask SO1.messagesResponseDecoder
@ -114,6 +117,7 @@ getMessagesV3 { direction, filter, from, limit, roomId, to } =
, R.queryOpInt "limit" limit , R.queryOpInt "limit" limit
, R.queryOpString "filter" filter , R.queryOpString "filter" filter
, R.queryOpString "to" to , R.queryOpString "to" to
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO1.messagesResponseDecoder >> R.toTask SO1.messagesResponseDecoder
@ -134,6 +138,7 @@ getMessagesV4 { direction, filter, from, limit, roomId, to } =
, R.queryOpInt "limit" limit , R.queryOpInt "limit" limit
, R.queryOpString "filter" filter , R.queryOpString "filter" filter
, R.queryOpString "to" to , R.queryOpString "to" to
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO2.messagesResponseDecoder >> R.toTask SO2.messagesResponseDecoder
@ -154,6 +159,7 @@ getMessagesV5 { direction, filter, from, limit, roomId, to } =
, R.queryOpInt "limit" limit , R.queryOpInt "limit" limit
, R.queryOpString "filter" filter , R.queryOpString "filter" filter
, R.queryOpString "to" to , R.queryOpString "to" to
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO3.messagesResponseDecoder >> R.toTask SO3.messagesResponseDecoder
@ -174,6 +180,7 @@ getMessagesV6 { direction, filter, from, limit, roomId, to } =
, R.queryOpInt "limit" limit , R.queryOpInt "limit" limit
, R.queryOpString "filter" filter , R.queryOpString "filter" filter
, R.queryOpString "to" to , R.queryOpString "to" to
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO3.messagesResponseDecoder >> R.toTask SO3.messagesResponseDecoder
@ -194,6 +201,7 @@ getMessagesV7 { direction, filter, from, limit, roomId, to } =
, R.queryOpInt "limit" limit , R.queryOpInt "limit" limit
, R.queryOpString "filter" filter , R.queryOpString "filter" filter
, R.queryOpString "to" to , R.queryOpString "to" to
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO4.messagesResponseDecoder >> R.toTask SO4.messagesResponseDecoder
@ -212,5 +220,6 @@ getMessagesV8 { direction, filter, from, limit, roomId, to } =
, R.queryOpInt "limit" limit , R.queryOpInt "limit" limit
, R.queryOpString "filter" filter , R.queryOpString "filter" filter
, R.queryOpString "to" to , R.queryOpString "to" to
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO4.messagesResponseDecoder >> R.toTask SO4.messagesResponseDecoder

View File

@ -1,6 +1,7 @@
module Internal.Api.Invite.Api exposing (..) module Internal.Api.Invite.Api exposing (..)
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context exposing (Context) import Internal.Tools.Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Json.Decode as D import Json.Decode as D
@ -31,6 +32,7 @@ inviteV1 { roomId, userId } =
[ R.accessToken [ R.accessToken
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.bodyString "user_id" userId , R.bodyString "user_id" userId
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.inviteNotAllowed })
] ]
>> R.toTask (D.map (always ()) D.value) >> R.toTask (D.map (always ()) D.value)
@ -43,5 +45,8 @@ inviteV2 { reason, roomId, userId } =
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.bodyString "user_id" userId , R.bodyString "user_id" userId
, R.bodyOpString "reason" reason , R.bodyOpString "reason" reason
, R.onStatusCode 400 (X.M_INVALID_PARAM { error = Just SE.invalidRequest })
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.inviteNotAllowed })
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask (D.map (always ()) D.value) >> R.toTask (D.map (always ()) D.value)

View File

@ -1,6 +1,7 @@
module Internal.Api.JoinRoomById.Api exposing (..) module Internal.Api.JoinRoomById.Api exposing (..)
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context exposing (Context, VBA) import Internal.Tools.Context exposing (Context, VBA)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Json.Decode as D import Json.Decode as D
@ -25,6 +26,8 @@ joinRoomByIdV1 { roomId } =
>> R.withAttributes >> R.withAttributes
[ R.accessToken [ R.accessToken
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.joinNotAllowed })
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask (D.map (\r -> { roomId = r }) (D.field "room_id" D.string)) >> R.toTask (D.map (\r -> { roomId = r }) (D.field "room_id" D.string))
@ -36,5 +39,7 @@ joinRoomByIdV2 { roomId, reason } =
[ R.accessToken [ R.accessToken
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.bodyOpString "reason" reason , R.bodyOpString "reason" reason
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.joinNotAllowed })
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask (D.map (\r -> { roomId = r }) (D.field "room_id" D.string)) >> R.toTask (D.map (\r -> { roomId = r }) (D.field "room_id" D.string))

View File

@ -2,6 +2,7 @@ module Internal.Api.JoinedMembers.Api exposing (..)
import Internal.Api.JoinedMembers.V1.SpecObjects as SO1 import Internal.Api.JoinedMembers.V1.SpecObjects as SO1
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context exposing (Context) import Internal.Tools.Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Task exposing (Task) import Task exposing (Task)
@ -22,6 +23,7 @@ joinedMembersV1 { roomId } =
>> R.withAttributes >> R.withAttributes
[ R.accessToken [ R.accessToken
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO1.roomMemberListDecoder >> R.toTask SO1.roomMemberListDecoder
@ -32,5 +34,6 @@ joinedMembersV2 { roomId } =
>> R.withAttributes >> R.withAttributes
[ R.accessToken [ R.accessToken
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.notInRoom })
] ]
>> R.toTask SO1.roomMemberListDecoder >> R.toTask SO1.roomMemberListDecoder

View File

@ -1,6 +1,7 @@
module Internal.Api.Leave.Api exposing (..) module Internal.Api.Leave.Api exposing (..)
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context exposing (Context) import Internal.Tools.Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Json.Decode as D import Json.Decode as D
@ -25,16 +26,18 @@ leaveV1 { roomId } =
>> R.withAttributes >> R.withAttributes
[ R.accessToken [ R.accessToken
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask (D.map (always ()) D.value) >> R.toTask (D.map (always ()) D.value)
leaveV2 : LeaveInputV2 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error LeaveOutputV1 leaveV2 : LeaveInputV2 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error LeaveOutputV1
leaveV2 { roomId, reason } = leaveV2 { roomId, reason } =
R.callApi "POST" "/_matrix/client/r0/rooms/{roomId}/leave" R.callApi "POST" "/_matrix/client/v3/rooms/{roomId}/leave"
>> R.withAttributes >> R.withAttributes
[ R.accessToken [ R.accessToken
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.bodyOpString "reason" reason , R.bodyOpString "reason" reason
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask (D.map (always ()) D.value) >> R.toTask (D.map (always ()) D.value)

View File

@ -6,6 +6,7 @@ import Internal.Api.LoginWithUsernameAndPassword.V3.SpecObjects as SO3
import Internal.Api.LoginWithUsernameAndPassword.V4.SpecObjects as SO4 import Internal.Api.LoginWithUsernameAndPassword.V4.SpecObjects as SO4
import Internal.Api.LoginWithUsernameAndPassword.V5.Login as SO5 import Internal.Api.LoginWithUsernameAndPassword.V5.Login as SO5
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context exposing (Context) import Internal.Tools.Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Json.Encode as E import Json.Encode as E
@ -53,6 +54,7 @@ loginWithUsernameAndPasswordV1 { username, password } =
[ R.bodyString "password" password [ R.bodyString "password" password
, R.bodyString "type" "m.login.password" , R.bodyString "type" "m.login.password"
, R.bodyString "user" username , R.bodyString "user" username
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask SO1.loggedInResponseDecoder >> R.toTask SO1.loggedInResponseDecoder
@ -66,6 +68,7 @@ loginWithUsernameAndPasswordV2 { deviceId, initialDeviceDisplayName, password, u
, R.bodyString "password" password , R.bodyString "password" password
, R.bodyOpString "device_id" deviceId , R.bodyOpString "device_id" deviceId
, R.bodyOpString "initial_device_display_name" initialDeviceDisplayName , R.bodyOpString "initial_device_display_name" initialDeviceDisplayName
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask SO2.loggedInResponseDecoder >> R.toTask SO2.loggedInResponseDecoder
@ -83,6 +86,7 @@ loginWithUsernameAndPasswordV3 { deviceId, initialDeviceDisplayName, password, u
] ]
|> E.object |> E.object
|> R.bodyValue "identifier" |> R.bodyValue "identifier"
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask SO3.loggedInResponseDecoder >> R.toTask SO3.loggedInResponseDecoder
@ -100,6 +104,7 @@ loginWithUsernameAndPasswordV4 { deviceId, initialDeviceDisplayName, password, u
] ]
|> E.object |> E.object
|> R.bodyValue "identifier" |> R.bodyValue "identifier"
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask SO4.loggedInResponseDecoder >> R.toTask SO4.loggedInResponseDecoder
@ -117,6 +122,7 @@ loginWithUsernameAndPasswordV5 { deviceId, initialDeviceDisplayName, password, u
] ]
|> E.object |> E.object
|> R.bodyValue "identifier" |> R.bodyValue "identifier"
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask SO4.loggedInResponseDecoder >> R.toTask SO4.loggedInResponseDecoder
@ -135,21 +141,6 @@ loginWithUsernameAndPasswordV6 { deviceId, initialDeviceDisplayName, password, u
] ]
|> E.object |> E.object
|> R.bodyValue "identifier" |> R.bodyValue "identifier"
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
] ]
>> R.toTask SO5.loggedInResponseDecoder >> 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,5 +1,9 @@
module Internal.Api.Request exposing (..) module Internal.Api.Request exposing (..)
{-| The request module builds HTTP tasks that are designed around calling the Matrix API.
-}
import Dict exposing (Dict)
import Http import Http
import Internal.Api.Helpers as Helpers import Internal.Api.Helpers as Helpers
import Internal.Tools.Context as Context exposing (Context) import Internal.Tools.Context as Context exposing (Context)
@ -31,6 +35,7 @@ type ContextAttr
| NoAttr | NoAttr
| QueryParam UrlBuilder.QueryParameter | QueryParam UrlBuilder.QueryParameter
| ReplaceInUrl String String | ReplaceInUrl String String
| StatusCodeResponse Int X.Error
| Timeout Float | Timeout Float
| UrlPath String | UrlPath String
@ -97,7 +102,19 @@ toTask decoder (ApiCall data) =
|> E.object |> E.object
) )
|> Http.jsonBody |> Http.jsonBody
, resolver = rawApiCallResolver (always decoder) , resolver =
data.attributes
|> List.filterMap
(\attr ->
case attr of
StatusCodeResponse code err ->
Just ( code, err )
_ ->
Nothing
)
|> Dict.fromList
|> rawApiCallResolver decoder
, timeout = , timeout =
data.attributes data.attributes
|> List.filterMap |> List.filterMap
@ -260,6 +277,14 @@ fullBody value _ =
FullBody value FullBody value
{-| If the Matrix API does not fit the Matrix spec but returns the following status code,
you may interpret it as the given error.
-}
onStatusCode : Int -> X.ServerError -> Attribute a
onStatusCode code err _ =
StatusCodeResponse code (X.ServerException err)
queryBool : String -> Bool -> Attribute a queryBool : String -> Bool -> Attribute a
queryBool key value _ = queryBool key value _ =
(if value then (if value then
@ -332,8 +357,8 @@ withTransactionId =
Context.getTransactionId >> ReplaceInUrl "txnId" Context.getTransactionId >> ReplaceInUrl "txnId"
rawApiCallResolver : (Int -> D.Decoder a) -> Http.Resolver X.Error a rawApiCallResolver : D.Decoder a -> Dict Int X.Error -> Http.Resolver X.Error a
rawApiCallResolver decoder = rawApiCallResolver decoder statusCodeErrors =
Http.stringResolver Http.stringResolver
(\response -> (\response ->
case response of case response of
@ -353,15 +378,19 @@ rawApiCallResolver decoder =
|> Err |> Err
Http.BadStatus_ metadata body -> Http.BadStatus_ metadata body ->
decodeServerResponse (decoder metadata.statusCode) body statusCodeErrors
|> Dict.get metadata.statusCode
|> decodeServerResponse decoder body
Http.GoodStatus_ metadata body -> Http.GoodStatus_ metadata body ->
decodeServerResponse (decoder metadata.statusCode) body statusCodeErrors
|> Dict.get metadata.statusCode
|> decodeServerResponse decoder body
) )
decodeServerResponse : D.Decoder a -> String -> Result X.Error a decodeServerResponse : D.Decoder a -> String -> Maybe X.Error -> Result X.Error a
decodeServerResponse decoder body = decodeServerResponse decoder body statusCodeError =
case D.decodeString D.value body of case D.decodeString D.value body of
Err e -> Err e ->
e e
@ -378,11 +407,17 @@ decodeServerResponse decoder body =
Err err -> Err err ->
-- The response is not valid! -- The response is not valid!
-- Check if it is a valid error type as defined in spec. -- Check if it is a valid error type as defined in spec.
case D.decodeString X.errorCatches body of case ( D.decodeString X.errorCatches body, statusCodeError ) of
Ok v -> ( Ok v, _ ) ->
Err (X.ServerException v) Err (X.ServerException v)
Err _ -> -- It does not compute as a valid spec error. Therefore,
-- we will look at its status code before ultimately giving up
-- on the validity of the response.
( Err _, Just sce ) ->
Err sce
( Err _, Nothing ) ->
err err
|> D.errorToString |> D.errorToString
|> X.ServerReturnsBadJSON |> X.ServerReturnsBadJSON

View File

@ -2,6 +2,7 @@ module Internal.Api.SendStateKey.Api exposing (..)
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Api.SendStateKey.V1.SpecObjects as SO1 import Internal.Api.SendStateKey.V1.SpecObjects as SO1
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context exposing (Context) import Internal.Tools.Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Json.Decode as D import Json.Decode as D
@ -29,6 +30,8 @@ sendStateKeyV1 { content, eventType, roomId, stateKey } =
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.replaceInUrl "stateKey" stateKey , R.replaceInUrl "stateKey" stateKey
, R.fullBody content , R.fullBody content
, R.onStatusCode 400 (X.M_INVALID_PARAM { error = Just SE.invalidRequest })
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.sendNotAllowed })
] ]
>> R.toTask SO1.eventResponseDecoder >> R.toTask SO1.eventResponseDecoder
@ -42,5 +45,7 @@ sendStateKeyV2 { content, eventType, roomId, stateKey } =
, R.replaceInUrl "roomId" roomId , R.replaceInUrl "roomId" roomId
, R.replaceInUrl "stateKey" stateKey , R.replaceInUrl "stateKey" stateKey
, R.fullBody content , R.fullBody content
, R.onStatusCode 400 (X.M_INVALID_PARAM { error = Just SE.invalidRequest })
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.sendNotAllowed })
] ]
>> R.toTask SO1.eventResponseDecoder >> R.toTask SO1.eventResponseDecoder

View File

@ -1,6 +1,7 @@
module Internal.Api.SetAccountData.Api exposing (..) module Internal.Api.SetAccountData.Api exposing (..)
import Internal.Api.Request as R import Internal.Api.Request as R
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context as Context exposing (Context) import Internal.Tools.Context as Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Json.Decode as D import Json.Decode as D
@ -33,6 +34,9 @@ setAccountDataV1 { content, eventType, roomId } context =
, R.replaceInUrl "type" eventType , R.replaceInUrl "type" eventType
, R.replaceInUrl "userId" (Context.getUserId context) , R.replaceInUrl "userId" (Context.getUserId context)
, R.fullBody content , R.fullBody content
, R.onStatusCode 400 (X.M_INVALID_PARAM { error = Just SE.invalidRequest })
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.accountDataSetNotAllowed })
, R.onStatusCode 405 (X.M_BAD_JSON { error = Just SE.accountDataControlledByServer })
] ]
>> R.toTask (D.map (always ()) D.value) >> R.toTask (D.map (always ()) D.value)
|> (|>) context |> (|>) context
@ -53,6 +57,9 @@ setAccountDataV2 { content, eventType, roomId } context =
, R.replaceInUrl "type" eventType , R.replaceInUrl "type" eventType
, R.replaceInUrl "userId" (Context.getUserId context) , R.replaceInUrl "userId" (Context.getUserId context)
, R.fullBody content , R.fullBody content
, R.onStatusCode 400 (X.M_INVALID_PARAM { error = Just SE.invalidRequest })
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.accountDataSetNotAllowed })
, R.onStatusCode 405 (X.M_BAD_JSON { error = Just SE.accountDataControlledByServer })
] ]
>> R.toTask (D.map (always ()) D.value) >> R.toTask (D.map (always ()) D.value)
|> (|>) context |> (|>) context

View File

@ -4,6 +4,7 @@ import Internal.Api.Request as R
import Internal.Api.WhoAmI.V1.SpecObjects as SO1 import Internal.Api.WhoAmI.V1.SpecObjects as SO1
import Internal.Api.WhoAmI.V2.SpecObjects as SO2 import Internal.Api.WhoAmI.V2.SpecObjects as SO2
import Internal.Api.WhoAmI.V3.SpecObjects as SO3 import Internal.Api.WhoAmI.V3.SpecObjects as SO3
import Internal.Config.SpecErrors as SE
import Internal.Tools.Context exposing (Context) import Internal.Tools.Context exposing (Context)
import Internal.Tools.Exceptions as X import Internal.Tools.Exceptions as X
import Task exposing (Task) import Task exposing (Task)
@ -28,19 +29,34 @@ type alias WhoAmIOutputV3 =
whoAmIV1 : WhoAmIInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error WhoAmIOutputV1 whoAmIV1 : WhoAmIInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error WhoAmIOutputV1
whoAmIV1 _ = whoAmIV1 _ =
R.callApi "GET" "/_matrix/client/r0/account/whoami" R.callApi "GET" "/_matrix/client/r0/account/whoami"
>> R.withAttributes [ R.accessToken ] >> R.withAttributes
[ R.accessToken
, R.onStatusCode 401 (X.M_UNKNOWN_TOKEN { error = Just SE.accessTokenNotRecognized, soft_logout = Nothing })
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.appserviceCannotMasquerade })
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
]
>> R.toTask SO1.whoAmIResponseDecoder >> R.toTask SO1.whoAmIResponseDecoder
whoAmIV2 : WhoAmIInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error WhoAmIOutputV2 whoAmIV2 : WhoAmIInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error WhoAmIOutputV2
whoAmIV2 _ = whoAmIV2 _ =
R.callApi "GET" "/_matrix/client/v3/account/whoami" R.callApi "GET" "/_matrix/client/v3/account/whoami"
>> R.withAttributes [ R.accessToken ] >> R.withAttributes
[ R.accessToken
, R.onStatusCode 401 (X.M_UNKNOWN_TOKEN { error = Just SE.accessTokenNotRecognized, soft_logout = Nothing })
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.appserviceCannotMasquerade })
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
]
>> R.toTask SO2.whoAmIResponseDecoder >> R.toTask SO2.whoAmIResponseDecoder
whoAmIV3 : WhoAmIInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error WhoAmIOutputV3 whoAmIV3 : WhoAmIInputV1 -> Context { a | accessToken : (), baseUrl : () } -> Task X.Error WhoAmIOutputV3
whoAmIV3 _ = whoAmIV3 _ =
R.callApi "GET" "/_matrix/client/v3/account/whoami" R.callApi "GET" "/_matrix/client/v3/account/whoami"
>> R.withAttributes [ R.accessToken ] >> R.withAttributes
[ R.accessToken
, R.onStatusCode 401 (X.M_UNKNOWN_TOKEN { error = Just SE.accessTokenNotRecognized, soft_logout = Nothing })
, R.onStatusCode 403 (X.M_FORBIDDEN { error = Just SE.appserviceCannotMasquerade })
, R.onStatusCode 429 (X.M_LIMIT_EXCEEDED { error = Just SE.ratelimited, retryAfterMs = Nothing })
]
>> R.toTask SO3.whoAmIResponseDecoder >> R.toTask SO3.whoAmIResponseDecoder

View File

@ -0,0 +1,107 @@
module Internal.Config.SpecErrors exposing (..)
{-| Sometimes, the Matrix spec suggests to interpret an HTTP response as a certain
error, even if the server doesn't explicitly say so.
In such cases, the following constants are used to indicate that such an error has occurred.
-}
{-| A user attempts to get information but the homeserver does not recognize the access token that the user has provided.
-}
accessTokenNotRecognized : String
accessTokenNotRecognized =
"Unrecognised access token."
{-| A user attempts to change account data that is controlled by the server.
-}
accountDataControlledByServer : String
accountDataControlledByServer =
"You cannot change this account data type as it's controlled by the server."
{-| A user tries to set account data, but they are not allowed to do so.
-}
accountDataSetNotAllowed : String
accountDataSetNotAllowed =
"You are not authorized to set this account data."
{-| The appservice cannot masquerade as the user or has not registered them.
-}
appserviceCannotMasquerade : String
appserviceCannotMasquerade =
"Application service has not registered this user."
{-| The user attempts to ban another user, but they are not allowed to do so.
For example,
- The banner is not currently in the room.
- The banners power level is insufficient to ban users from the room.
-}
banNotAllowed : String
banNotAllowed =
"You do not have permission to ban someone in this room."
{-| A user tries to access to an event, but either it doesn't exist or they lack permission to read it.
-}
eventNotFound : String
eventNotFound =
"The event was not found or you do not have permission to read this event."
{-| A user made a request that is considered invalid. For example:
- The request body is malformed
- The user tried to interact with users from a homeserver that do not support the action
-}
invalidRequest : String
invalidRequest =
"The request is invalid."
{-| A user tries to invite another user to a room, but they lack the permission to do so. Example reasons for rejection are:
- The invitee has been banned from the room.
- The invitee is already a member of the room.
- The inviter is not currently in the room.
- The inviter's power level is insufficient to invite users to the room.
-}
inviteNotAllowed : String
inviteNotAllowed =
"You do not have permission to invite the user to the room."
{-| A user tries to join a room that they're not allowed to join.
-}
joinNotAllowed : String
joinNotAllowed =
"You do not have permission to join the room."
{-| A user tries to access information from a room that they don't have access to.
-}
notInRoom : String
notInRoom =
"You aren't a member of the room."
{-| A user tries to make an HTTP request, but it was ratelimited.
-}
ratelimited : String
ratelimited =
"This request was rate-limited."
{-| A user is trying to send an invite to a room, but they're not allowed to do so.
-}
sendNotAllowed : String
sendNotAllowed =
"You don't have permission to send the event into the room."