Refactor Credentials to Snackbar

The Snackbar type is a type of candies (tokens) that is brought along with any data type that may be passed on to the user.
pull/1/head
Bram van den Heuvel 2023-04-12 15:36:56 +02:00
parent 66383551d1
commit 619cd53a3a
10 changed files with 312 additions and 281 deletions

View File

@ -0,0 +1,110 @@
module Internal.Api.Snackbar exposing (..)
{-| The snackbar module helps wraps relevant credentials, access tokens, refresh tokens and more around internal types.
Vault, Room and Event types don't need access to API tokens,
but a user may way to redact an event, leave a room or reject an invite.
In such a case, the `Snackbar` type is a bowl of token candies that you can wrap
around any data type.
That way, you can both access the type within AND carry the tokens on every type
without needing to update every data type whenever any of the tokens change.
-}
import Internal.Api.Versions.V1.Versions as V
import Internal.Tools.LoginValues as Login exposing (AccessToken(..))
type Snackbar a
= Snackbar
{ access : AccessToken
, content : a
, homeserver : String
, vs : Maybe V.Versions
}
accessToken : Snackbar a -> AccessToken
accessToken (Snackbar { access }) =
access
addToken : String -> Snackbar a -> Snackbar a
addToken token (Snackbar ({ access } as data)) =
Snackbar { data | access = Login.addToken token access }
addUsernameAndPassword : { username : String, password : String } -> Snackbar a -> Snackbar a
addUsernameAndPassword uap (Snackbar ({ access } as data)) =
Snackbar { data | access = Login.addUsernameAndPassword uap access }
addVersions : V.Versions -> Snackbar a -> Snackbar a
addVersions vs (Snackbar data) =
Snackbar { data | vs = Just vs }
addWhoAmI : { w | userId : String, deviceId : Maybe String } -> Snackbar a -> Snackbar a
addWhoAmI whoami (Snackbar ({ access } as data)) =
Snackbar { data | access = Login.addWhoAmI whoami access }
baseUrl : Snackbar a -> String
baseUrl (Snackbar { homeserver }) =
homeserver
init : { baseUrl : String, content : a } -> Snackbar a
init data =
Snackbar
{ access = NoAccess
, content = data.content
, homeserver = data.baseUrl
, vs = Nothing
}
map : (a -> b) -> Snackbar a -> Snackbar b
map f (Snackbar data) =
Snackbar
{ access = data.access
, content = f data.content
, homeserver = data.homeserver
, vs = data.vs
}
mapList : (a -> List b) -> Snackbar a -> List (Snackbar b)
mapList f (Snackbar data) =
List.map (withCandyFrom (Snackbar data)) (f data.content)
mapMaybe : (a -> Maybe b) -> Snackbar a -> Maybe (Snackbar b)
mapMaybe f (Snackbar data) =
Maybe.map (withCandyFrom (Snackbar data)) (f data.content)
removedAccessToken : Snackbar a -> AccessToken
removedAccessToken (Snackbar { access }) =
Login.removeToken access
userId : Snackbar a -> Maybe String
userId (Snackbar { access }) =
Login.getUserId access
versions : Snackbar a -> Maybe V.Versions
versions (Snackbar { vs }) =
vs
withCandyFrom : Snackbar b -> a -> Snackbar a
withCandyFrom snackbar x =
map (always x) snackbar
withoutCandy : Snackbar a -> a
withoutCandy (Snackbar { content }) =
content

View File

@ -5,7 +5,6 @@ module Internal.Api.Task exposing (..)
import Hash
import Internal.Api.Chain as Chain
import Internal.Api.Credentials as Cred exposing (Credentials)
import Internal.Api.GetEvent.Main exposing (EventInput)
import Internal.Api.GetMessages.Main exposing (GetMessagesInput)
import Internal.Api.Invite.Main exposing (InviteInput)
@ -14,6 +13,7 @@ import Internal.Api.JoinedMembers.Main exposing (JoinedMembersInput)
import Internal.Api.Leave.Main exposing (LeaveInput)
import Internal.Api.SendStateKey.Main exposing (SendStateKeyInput)
import Internal.Api.SetAccountData.Main exposing (SetAccountInput)
import Internal.Api.Snackbar as Snackbar exposing (Snackbar)
import Internal.Api.Sync.Main exposing (SyncInput)
import Internal.Api.VaultUpdate as C
import Json.Encode as E
@ -29,7 +29,7 @@ type alias EventInput =
}
getEvent : EventInput -> Credentials -> FutureTask
getEvent : EventInput -> Snackbar a -> FutureTask
getEvent { eventId, roomId } cred =
C.makeVBA cred
|> Chain.andThen (C.withSentEvent eventId)
@ -37,35 +37,35 @@ getEvent { eventId, roomId } cred =
|> C.toTask
getMessages : GetMessagesInput -> Credentials -> FutureTask
getMessages : GetMessagesInput -> Snackbar a -> FutureTask
getMessages data cred =
C.makeVBA cred
|> Chain.andThen (C.getMessages data)
|> C.toTask
invite : InviteInput -> Credentials -> FutureTask
invite : InviteInput -> Snackbar a -> FutureTask
invite data cred =
C.makeVBA cred
|> Chain.andThen (C.invite data)
|> C.toTask
joinedMembers : JoinedMembersInput -> Credentials -> FutureTask
joinedMembers : JoinedMembersInput -> Snackbar a -> FutureTask
joinedMembers data cred =
C.makeVBA cred
|> Chain.andThen (C.joinedMembers data)
|> C.toTask
joinRoomById : JoinRoomByIdInput -> Credentials -> FutureTask
joinRoomById : JoinRoomByIdInput -> Snackbar a -> FutureTask
joinRoomById data cred =
C.makeVBA cred
|> Chain.andThen (C.joinRoomById data)
|> C.toTask
leave : LeaveInput -> Credentials -> FutureTask
leave : LeaveInput -> Snackbar a -> FutureTask
leave data cred =
C.makeVBA cred
|> Chain.andThen (C.leave data)
@ -80,7 +80,7 @@ type alias RedactInput =
}
redact : RedactInput -> Credentials -> FutureTask
redact : RedactInput -> Snackbar a -> FutureTask
redact { eventId, extraTransactionNoise, reason, roomId } cred =
cred
|> C.makeVBAT
@ -109,7 +109,7 @@ type alias SendMessageEventInput =
}
sendMessageEvent : SendMessageEventInput -> Credentials -> FutureTask
sendMessageEvent : SendMessageEventInput -> Snackbar a -> FutureTask
sendMessageEvent { content, eventType, extraTransactionNoise, roomId } cred =
cred
|> C.makeVBAT
@ -130,7 +130,7 @@ sendMessageEvent { content, eventType, extraTransactionNoise, roomId } cred =
|> C.toTask
sendStateEvent : SendStateKeyInput -> Credentials -> FutureTask
sendStateEvent : SendStateKeyInput -> Snackbar a -> FutureTask
sendStateEvent data cred =
C.makeVBA cred
|> Chain.andThen C.getTimestamp
@ -140,24 +140,24 @@ sendStateEvent data cred =
|> C.toTask
setAccountData : SetAccountInput -> Credentials -> FutureTask
setAccountData : SetAccountInput -> Snackbar a -> FutureTask
setAccountData data cred =
C.makeVBA cred
|> Chain.andThen (C.setAccountData data)
|> C.toTask
sync : SyncInput -> Credentials -> FutureTask
sync : SyncInput -> Snackbar a -> FutureTask
sync data cred =
C.makeVBA cred
|> Chain.andThen (C.sync data)
|> C.toTask
loginMaybeSync : SyncInput -> Credentials -> FutureTask
loginMaybeSync : SyncInput -> Snackbar a -> FutureTask
loginMaybeSync data cred =
C.makeVB cred
|> Chain.andThen (C.accessToken (Cred.refreshedAccessToken cred))
|> Chain.andThen (C.accessToken (Snackbar.removedAccessToken cred))
|> Chain.andThen
(Chain.maybe <| C.sync data)
|> C.toTask

View File

@ -2,7 +2,6 @@ module Internal.Api.VaultUpdate exposing (..)
import Internal.Api.Ban.Main as Ban
import Internal.Api.Chain as Chain exposing (IdemChain, TaskChain)
import Internal.Api.Credentials as Credentials exposing (Credentials)
import Internal.Api.GetEvent.Main as GetEvent
import Internal.Api.GetMessages.Main as GetMessages
import Internal.Api.Invite.Main as Invite
@ -14,6 +13,7 @@ import Internal.Api.Redact.Main as Redact
import Internal.Api.SendMessageEvent.Main as SendMessageEvent
import Internal.Api.SendStateKey.Main as SendStateKey
import Internal.Api.SetAccountData.Main as SetAccountData
import Internal.Api.Snackbar as Snackbar exposing (Snackbar)
import Internal.Api.Sync.Main as Sync
import Internal.Api.Versions.Main as Versions
import Internal.Api.Versions.V1.Versions as V
@ -296,28 +296,28 @@ loginWithUsernameAndPassword input =
{-| Make a VB-context based chain.
-}
makeVB : Credentials -> TaskChain VaultUpdate {} (VB {})
makeVB cred =
cred
|> Credentials.baseUrl
makeVB : Snackbar a -> TaskChain VaultUpdate {} (VB {})
makeVB snackbar =
snackbar
|> Snackbar.baseUrl
|> withBaseUrl
|> Chain.andThen (versions (Credentials.versions cred))
|> Chain.andThen (versions (Snackbar.versions snackbar))
{-| Make a VBA-context based chain.
-}
makeVBA : Credentials -> TaskChain VaultUpdate {} (VBA { userId : () })
makeVBA cred =
cred
makeVBA : Snackbar a -> TaskChain VaultUpdate {} (VBA { userId : () })
makeVBA snackbar =
snackbar
|> makeVB
|> Chain.andThen (accessToken (Credentials.accessToken cred))
|> Chain.andThen (accessToken (Snackbar.accessToken snackbar))
{-| Make a VBAT-context based chain.
-}
makeVBAT : (Int -> String) -> Credentials -> TaskChain VaultUpdate {} (VBAT { userId : () })
makeVBAT toString cred =
cred
makeVBAT : (Int -> String) -> Snackbar a -> TaskChain VaultUpdate {} (VBAT { userId : () })
makeVBAT toString snackbar =
snackbar
|> makeVBA
|> Chain.andThen (withTransactionId toString)

View File

@ -7,10 +7,10 @@ resend other events or forward them elsewhere.
-}
import Internal.Api.Credentials exposing (Credentials)
import Internal.Api.GetEvent.Main as GetEvent
import Internal.Api.GetEvent.V1.SpecObjects as GetEventSO
import Internal.Api.GetMessages.V4.SpecObjects as GetMessagesSO
import Internal.Api.Snackbar as Snackbar exposing (Snackbar)
import Internal.Api.Sync.V2.SpecObjects as SyncSO
import Internal.Tools.Timestamp exposing (Timestamp)
import Internal.Values.Event as Internal
@ -19,22 +19,8 @@ import Json.Encode as E
{-| The central event type. This type will be used by the user and will be directly interacted with.
-}
type Event
= Event
{ event : Internal.IEvent
, context : Credentials
}
{-| Using the credentials' background information and an internal event type,
create an interactive event type.
-}
withCredentials : Credentials -> Internal.IEvent -> Event
withCredentials context event =
Event
{ event = event
, context = context
}
type alias Event =
Snackbar Internal.IEvent
{-| Create an internal event type from an API endpoint event object.
@ -115,67 +101,58 @@ initFromClientEventWithoutRoomId rId output =
}
{-| Get the internal event type that is hidden in the interactive event type.
-}
withoutCredentials : Event -> Internal.IEvent
withoutCredentials (Event { event }) =
event
{- GETTER FUNCTIONS -}
content : Event -> E.Value
content =
withoutCredentials >> Internal.content
Snackbar.withoutCandy >> Internal.content
eventId : Event -> String
eventId =
withoutCredentials >> Internal.eventId
Snackbar.withoutCandy >> Internal.eventId
originServerTs : Event -> Timestamp
originServerTs =
withoutCredentials >> Internal.originServerTs
Snackbar.withoutCandy >> Internal.originServerTs
roomId : Event -> String
roomId =
withoutCredentials >> Internal.roomId
Snackbar.withoutCandy >> Internal.roomId
sender : Event -> String
sender =
withoutCredentials >> Internal.sender
Snackbar.withoutCandy >> Internal.sender
stateKey : Event -> Maybe String
stateKey =
withoutCredentials >> Internal.stateKey
Snackbar.withoutCandy >> Internal.stateKey
eventType : Event -> String
eventType =
withoutCredentials >> Internal.eventType
Snackbar.withoutCandy >> Internal.eventType
age : Event -> Maybe Int
age =
withoutCredentials >> Internal.age
Snackbar.withoutCandy >> Internal.age
redactedBecause : Event -> Maybe Event
redactedBecause (Event data) =
data.event
redactedBecause event =
event
|> Snackbar.withoutCandy
|> Internal.redactedBecause
|> Maybe.map
(\event ->
Event { data | event = event }
)
|> Maybe.map (Snackbar.withCandyFrom event)
transactionId : Event -> Maybe String
transactionId =
withoutCredentials >> Internal.transactionId
Snackbar.withoutCandy >> Internal.transactionId

View File

@ -3,7 +3,7 @@ module Internal.Invite exposing (..)
{-| An invite is an Elm type that informs the user they've been invited to a room.
-}
import Internal.Api.Credentials exposing (Credentials)
import Internal.Api.Snackbar as Snackbar exposing (Snackbar)
import Internal.Api.Sync.V2.SpecObjects exposing (StrippedStateEvent)
import Internal.Api.Task as Api
import Internal.Api.VaultUpdate exposing (VaultUpdate(..))
@ -12,16 +12,32 @@ import Internal.Values.RoomInvite as Internal
import Task exposing (Task)
type RoomInvite
= RoomInvite
{ invite : Internal.IRoomInvite
, context : Credentials
type alias RoomInvite =
Snackbar Internal.IRoomInvite
accept : { invite : RoomInvite, reason : Maybe String } -> Task X.Error VaultUpdate
accept { invite, reason } =
Api.joinRoomById
{ roomId = roomId invite
, reason = reason
}
invite
getRoomId : RoomInvite -> String
getRoomId =
withoutCredentials >> Internal.roomId
roomId : RoomInvite -> String
roomId =
Snackbar.withoutCandy >> Internal.roomId
getEvent : { eventType : String, stateKey : String } -> RoomInvite -> Maybe Internal.RoomInviteEvent
getEvent data =
Snackbar.withoutCandy >> Internal.getEvent data
getAllEvents : RoomInvite -> List Internal.RoomInviteEvent
getAllEvents =
Snackbar.withoutCandy >> Internal.getAllEvents
initFromStrippedStateEvent : { roomId : String, events : List StrippedStateEvent } -> Internal.IRoomInvite
@ -29,47 +45,12 @@ initFromStrippedStateEvent =
Internal.init
withCredentials : Credentials -> Internal.IRoomInvite -> RoomInvite
withCredentials context invite =
RoomInvite { context = context, invite = invite }
withoutCredentials : RoomInvite -> Internal.IRoomInvite
withoutCredentials (RoomInvite { invite }) =
invite
getEvent : { eventType : String, stateKey : String } -> RoomInvite -> Maybe Internal.RoomInviteEvent
getEvent data =
withoutCredentials >> Internal.getEvent data
getAllEvents : RoomInvite -> List Internal.RoomInviteEvent
getAllEvents =
withoutCredentials >> Internal.getAllEvents
{-| Accept an invite and join the room.
-}
accept : { invite : RoomInvite, reason : Maybe String } -> Task X.Error VaultUpdate
accept { invite, reason } =
case invite of
RoomInvite data ->
Api.joinRoomById
{ roomId = Internal.roomId data.invite
, reason = reason
}
data.context
{-| Reject the invite and do not join the room.
-}
reject : { invite : RoomInvite, reason : Maybe String } -> Task X.Error VaultUpdate
reject { invite, reason } =
case invite of
RoomInvite data ->
Api.leave
{ roomId = Internal.roomId data.invite
, reason = reason
}
data.context
Api.leave
{ roomId = roomId invite
, reason = reason
}
invite

View File

@ -4,7 +4,7 @@ module Internal.Room exposing (..)
-}
import Dict
import Internal.Api.Credentials exposing (Credentials)
import Internal.Api.Snackbar as Snackbar exposing (Snackbar)
import Internal.Api.Sync.V2.SpecObjects as Sync
import Internal.Api.Task as Api
import Internal.Api.VaultUpdate exposing (VaultUpdate(..))
@ -28,11 +28,8 @@ The `Room` type contains utilities to inquire about the room and send messages
to it.
-}
type Room
= Room
{ room : Internal.IRoom
, context : Credentials
}
type alias Room =
Snackbar Internal.IRoom
{-| Create a new object from a joined room.
@ -89,24 +86,22 @@ initFromJoinedRoom data jroom =
accountData : String -> Room -> Maybe E.Value
accountData key =
withoutCredentials >> Internal.accountData key
Snackbar.withoutCandy >> Internal.accountData key
{-| Add account data to the room.
-}
addAccountData : String -> E.Value -> Room -> Room
addAccountData eventType content (Room { room, context }) =
room
|> Internal.addAccountData eventType content
|> withCredentials context
addAccountData eventType content =
Snackbar.map (Internal.addAccountData eventType content)
{-| Adds an internal event to the `Room`. An internal event is a custom event
that has been generated by the client.
-}
addInternalEvent : IEvent.IEvent -> Room -> Room
addInternalEvent ievent (Room ({ room } as data)) =
Room { data | room = Internal.addEvent ievent room }
addInternalEvent ievent =
Snackbar.map (Internal.addEvent ievent)
{-| Adds an `Event` object to the `Room`. An `Event` is a value from the
@ -114,39 +109,21 @@ addInternalEvent ievent (Room ({ room } as data)) =
-}
addEvent : Event -> Room -> Room
addEvent =
Event.withoutCredentials >> addInternalEvent
{-| Creates a new `Room` object with the given parameters.
-}
withCredentials : Credentials -> Internal.IRoom -> Room
withCredentials context room =
Room
{ context = context
, room = room
}
{-| Retrieves the `Internal.IRoom` type contained within the given `Room`.
-}
withoutCredentials : Room -> Internal.IRoom
withoutCredentials (Room { room }) =
room
Snackbar.withoutCandy >> addInternalEvent
{-| Get a given state event.
-}
getStateEvent : { eventType : String, stateKey : String } -> Room -> Maybe Event
getStateEvent data (Room { room, context }) =
Internal.getStateEvent data room
|> Maybe.map (Event.withCredentials context)
getStateEvent data =
Snackbar.mapMaybe (Internal.getStateEvent data)
{-| Get older events from the Matrix API.
-}
getOlderEvents : { limit : Maybe Int } -> Room -> Task X.Error VaultUpdate
getOlderEvents { limit } (Room { context, room }) =
case Internal.latestGap room of
findOlderEvents : { limit : Maybe Int } -> Room -> Task X.Error VaultUpdate
findOlderEvents { limit } room =
case Internal.latestGap (Snackbar.withoutCandy room) of
Nothing ->
Task.succeed (MultipleUpdates [])
@ -156,54 +133,52 @@ getOlderEvents { limit } (Room { context, room }) =
, filter = Nothing
, from = Just to
, limit = limit
, roomId = Internal.roomId room
, roomId = roomId room
, to = from
}
context
room
{-| Get the most recent events.
-}
mostRecentEvents : Room -> List Event
mostRecentEvents (Room { context, room }) =
room
|> Internal.mostRecentEvents
|> List.map (Event.withCredentials context)
mostRecentEvents =
Snackbar.mapList Internal.mostRecentEvents
{-| Retrieves the ID of the Matrix room associated with the given `Room`.
-}
roomId : Room -> String
roomId =
withoutCredentials >> Internal.roomId
Snackbar.withoutCandy >> Internal.roomId
{-| Sends a new event to the Matrix room associated with the given `Room`.
-}
sendEvent : { content : E.Value, eventType : String, stateKey : Maybe String } -> Room -> Task X.Error VaultUpdate
sendEvent { eventType, content, stateKey } (Room { context, room }) =
sendEvent { eventType, content, stateKey } room =
case stateKey of
Nothing ->
Api.sendMessageEvent
{ content = content
, eventType = eventType
, extraTransactionNoise = "send-one-message"
, roomId = Internal.roomId room
, roomId = roomId room
}
context
room
Just s ->
Api.sendStateEvent
{ content = content
, eventType = eventType
, stateKey = s
, roomId = Internal.roomId room
, roomId = roomId room
}
context
room
sendEvents : List { content : E.Value, eventType : String, stateKey : Maybe String } -> Room -> List (Task X.Error VaultUpdate)
sendEvents events (Room { context, room }) =
sendEvents events room =
List.indexedMap Tuple.pair events
|> List.map
(\( i, { eventType, content, stateKey } ) ->
@ -213,25 +188,25 @@ sendEvents events (Room { context, room }) =
{ content = content
, eventType = eventType
, extraTransactionNoise = "send-message-" ++ String.fromInt i
, roomId = Internal.roomId room
, roomId = roomId room
}
context
room
Just s ->
Api.sendStateEvent
{ content = content
, eventType = eventType
, stateKey = s
, roomId = Internal.roomId room
, roomId = roomId room
}
context
room
)
{-| Sends a new text message to the Matrix room associated with the given `Room`.
-}
sendMessage : String -> Room -> Task X.Error VaultUpdate
sendMessage text (Room { context, room }) =
sendMessage text room =
Api.sendMessageEvent
{ content =
E.object
@ -240,13 +215,13 @@ sendMessage text (Room { context, room }) =
]
, eventType = "m.room.message"
, extraTransactionNoise = "literal-message:" ++ text
, roomId = Internal.roomId room
, roomId = roomId room
}
context
room
sendMessages : List String -> Room -> List (Task X.Error VaultUpdate)
sendMessages pieces (Room { context, room }) =
sendMessages pieces room =
pieces
|> List.indexedMap Tuple.pair
|> List.map
@ -259,21 +234,21 @@ sendMessages pieces (Room { context, room }) =
]
, eventType = "m.room.message"
, extraTransactionNoise = "literal-message-" ++ String.fromInt i ++ ":" ++ piece
, roomId = Internal.roomId room
, roomId = roomId room
}
context
room
)
{-| Leave this room.
-}
leave : Room -> Task X.Error VaultUpdate
leave ((Room { context }) as r) =
Api.leave { roomId = roomId r, reason = Nothing } context
leave room =
Api.leave { roomId = roomId room, reason = Nothing } room
{-| Set account data.
-}
setAccountData : String -> E.Value -> Room -> Task X.Error VaultUpdate
setAccountData key value ((Room { context }) as r) =
Api.setAccountData { content = value, eventType = key, roomId = Just (roomId r) } context
setAccountData key value room =
Api.setAccountData { content = value, eventType = key, roomId = Just (roomId room) } room

View File

@ -8,7 +8,7 @@ This file combines the internal functions with the API endpoints to create a ful
-}
import Dict
import Internal.Api.Credentials as Credentials exposing (Credentials)
import Internal.Api.Snackbar as Snackbar exposing (Snackbar)
import Internal.Api.Sync.Main exposing (SyncInput)
import Internal.Api.Task as Api
import Internal.Api.VaultUpdate exposing (VaultUpdate(..))
@ -30,11 +30,15 @@ and Elm will figure out which key to use.
If you pass the `Vault` into any function, then the library will look for
the right keys and tokens to get the right information.
-}
type Vault
= Vault
{ cred : Internal.IVault
, context : Credentials
}
type alias Vault =
Snackbar Internal.IVault
{-| Get personal account data linked to an account.
-}
accountData : String -> Vault -> Maybe E.Value
accountData key =
Snackbar.withoutCandy >> Internal.accountData key
{-| Get a Vault type based on an unknown access token.
@ -45,77 +49,66 @@ when the access token expires, is revoked or something else happens.
-}
fromAccessToken : { baseUrl : String, accessToken : String } -> Vault
fromAccessToken { baseUrl, accessToken } =
Credentials.fromBaseUrl baseUrl
|> Credentials.addToken accessToken
|> (\context ->
{ cred = Internal.init, context = context }
)
|> Vault
Snackbar.init
{ baseUrl = baseUrl
, content = Internal.init
}
|> Snackbar.addToken accessToken
{-| Get a Vault type using a username and password.
-}
fromLoginVault : { username : String, password : String, baseUrl : String } -> Vault
fromLoginVault { username, password, baseUrl } =
Credentials.fromBaseUrl baseUrl
|> Credentials.addUsernameAndPassword
Snackbar.init
{ baseUrl = baseUrl
, content = Internal.init
}
|> Snackbar.addUsernameAndPassword
{ username = username
, password = password
}
|> (\context ->
{ cred = Internal.init, context = context }
)
|> Vault
{-| Get personal account data linked to an account.
-}
accountData : String -> Vault -> Maybe E.Value
accountData key (Vault { cred }) =
Internal.accountData key cred
{-| Get a user's invited rooms.
-}
getInvites : Vault -> List Invite.RoomInvite
getInvites (Vault { cred, context }) =
Internal.getInvites cred
|> List.map (Invite.withCredentials context)
invites : Vault -> List Invite.RoomInvite
invites =
Snackbar.mapList Internal.getInvites
{-| Get a room based on its id.
-}
getRoomById : String -> Vault -> Maybe Room.Room
getRoomById roomId (Vault { cred, context }) =
Internal.getRoomById roomId cred
|> Maybe.map (Room.withCredentials context)
getRoomById roomId =
Snackbar.mapMaybe (Internal.getRoomById roomId)
{-| Insert an internal room type into the credentials.
{-| Insert an internal room type into the vault.
-}
insertInternalRoom : IRoom.IRoom -> Vault -> Vault
insertInternalRoom iroom (Vault data) =
Vault { data | cred = Internal.insertRoom iroom data.cred }
insertInternalRoom iroom =
Snackbar.map (Internal.insertRoom iroom)
{-| Internal a full room type into the credentials.
{-| Internal a full room type into the vault.
-}
insertRoom : Room.Room -> Vault -> Vault
insertRoom =
Room.withoutCredentials >> insertInternalRoom
Snackbar.withoutCandy >> insertInternalRoom
{-| Join a Matrix room by its id.
-}
joinRoomById : String -> Vault -> Task X.Error VaultUpdate
joinRoomById roomId (Vault { context }) =
Api.joinRoomById { roomId = roomId, reason = Nothing } context
joinRoomById roomId vault =
Api.joinRoomById { roomId = roomId, reason = Nothing } vault
{-| Update the Vault type with new values
-}
updateWith : VaultUpdate -> Vault -> Vault
updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
updateWith vaultUpdate vault =
case vaultUpdate of
MultipleUpdates updates ->
List.foldl updateWith vault updates
@ -143,7 +136,7 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
vault
CurrentTimestamp t ->
Vault { cred = Internal.insertTimestamp t cred, context = context }
Snackbar.map (Internal.insertTimestamp t) vault
GetEvent input output ->
case getRoomById input.roomId vault of
@ -192,7 +185,7 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
case ( getRoomById input.roomId vault, nextBatch ) of
( Just room, Just nb ) ->
room
|> Room.withoutCredentials
|> Snackbar.withoutCandy
|> IRoom.insertEvents
{ events =
output.chunk
@ -210,8 +203,8 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
, stateDelta = Just <| StateManager.fromEventList (List.map Event.initFromGetMessages output.state)
}
|> Internal.insertRoom
|> (|>) cred
|> (\v -> Vault { cred = v, context = context })
|> Snackbar.map
|> (|>) vault
_ ->
vault
@ -226,35 +219,29 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
-- TODO
JoinedRoom input _ ->
cred
|> Internal.removeInvite input.roomId
|> (\x -> { cred = x, context = context })
|> Vault
Snackbar.map (Internal.removeInvite input.roomId) vault
-- TODO
LeftRoom input () ->
cred
|> Internal.removeInvite input.roomId
|> (\x -> { cred = x, context = context })
|> Vault
Snackbar.map (Internal.removeInvite input.roomId) vault
MessageEventSent { content, eventType, roomId } { eventId } ->
Maybe.map2
(\room sender ->
room
|> Room.withoutCredentials
|> Snackbar.withoutCandy
|> IRoom.addTemporaryEvent
{ content = content
, eventType = eventType
, eventId = eventId
, originServerTs = Internal.lastUpdate cred
, originServerTs = Internal.lastUpdate (Snackbar.withoutCandy vault)
, sender = sender
, stateKey = Nothing
}
)
(getRoomById roomId vault)
(getUsername vault)
|> Maybe.map (Room.withCredentials context >> insertRoom >> (|>) vault)
|> Maybe.map (Snackbar.withCandyFrom vault >> insertRoom >> (|>) vault)
|> Maybe.withDefault vault
-- TODO
@ -265,19 +252,19 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
Maybe.map2
(\room sender ->
room
|> Room.withoutCredentials
|> Snackbar.withoutCandy
|> IRoom.addTemporaryEvent
{ content = content
, eventType = eventType
, eventId = eventId
, originServerTs = Internal.lastUpdate cred
, originServerTs = Internal.lastUpdate (Snackbar.withoutCandy vault)
, sender = sender
, stateKey = Just stateKey
}
)
(getRoomById roomId vault)
(getUsername vault)
|> Maybe.map (Room.withCredentials context >> insertRoom >> (|>) vault)
|> Maybe.map (Snackbar.withCandyFrom vault >> insertRoom >> (|>) vault)
|> Maybe.withDefault vault
SyncUpdate input output ->
@ -303,7 +290,7 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
(case jroom.timeline of
Just timeline ->
room
|> Room.withoutCredentials
|> Snackbar.withoutCandy
|> IRoom.addEvents
{ events =
List.map
@ -325,7 +312,7 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
}
Nothing ->
Room.withoutCredentials room
Snackbar.withoutCandy room
)
|> (\r ->
jroom.accountData
@ -342,8 +329,8 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
|> Room.initFromJoinedRoom { nextBatch = output.nextBatch, roomId = roomId }
)
invites : List IRoomInvite
invites =
inviteList : List IRoomInvite
inviteList =
output.rooms
|> Maybe.map .invite
|> Maybe.withDefault Dict.empty
@ -354,61 +341,62 @@ updateWith vaultUpdate ((Vault ({ cred, context } as data)) as vault) =
|> List.map (\( roomId, events ) -> { roomId = roomId, events = events })
|> List.map Invite.initFromStrippedStateEvent
in
cred
-- Add global account data
|> (\c -> List.foldl Internal.insertAccountData c accData)
-- Add new since token
|> Internal.addSince output.nextBatch
-- Add joined rooms
|> List.foldl Internal.insertRoom
|> (|>) jRooms
-- Add invites
|> List.foldl Internal.addInvite
|> (|>) invites
|> (\x -> { cred = x, context = context })
|> Vault
Snackbar.map
(\ivault ->
ivault
-- Add global account data
|> (\c -> List.foldl Internal.insertAccountData c accData)
-- Add new since token
|> Internal.addSince output.nextBatch
-- Add joined rooms
|> List.foldl Internal.insertRoom
|> (|>) jRooms
-- Add invites
|> List.foldl Internal.addInvite
|> (|>) inviteList
)
vault
UpdateAccessToken token ->
Vault { data | context = Credentials.addToken token context }
Snackbar.addToken token vault
UpdateVersions versions ->
Vault { data | context = Credentials.addVersions versions context }
Snackbar.addVersions versions vault
UpdateWhoAmI whoami ->
Vault { data | context = Credentials.addWhoAmI whoami context }
Snackbar.addWhoAmI whoami vault
-- TODO: Save ALL info
LoggedInWithUsernameAndPassword _ output ->
Vault { data | context = Credentials.addToken output.accessToken context }
Snackbar.addToken output.accessToken vault
getUsername : Vault -> Maybe String
getUsername (Vault { context }) =
Credentials.getUserId context
getUsername =
Snackbar.userId
{-| Set personal account data
-}
setAccountData : String -> E.Value -> Vault -> Task X.Error VaultUpdate
setAccountData key value (Vault { context }) =
Api.setAccountData { content = value, eventType = key, roomId = Nothing } context
setAccountData key value vault =
Api.setAccountData { content = value, eventType = key, roomId = Nothing } vault
{-| Synchronize vault
-}
sync : Vault -> Task X.Error VaultUpdate
sync (Vault { cred, context }) =
sync vault =
let
syncInput : SyncInput
syncInput =
{ filter = Nothing
, fullState = Nothing
, setPresence = Nothing
, since = Internal.getSince cred
, since = Internal.getSince (Snackbar.withoutCandy vault)
, timeout = Just 30
}
in
Api.sync syncInput context
Api.sync syncInput vault
-- TODO: The sync function is described as "updating all the tokens".
-- TODO: For this reason, (only) the sync function should handle errors
-- TODO: that indicate that the user's access tokens have expired.
@ -428,10 +416,10 @@ sync (Vault { cred, context }) =
-- TODO: The login should be different when soft_logout.
-- TODO: Add support for refresh token.
X.ServerException (X.M_UNKNOWN_TOKEN _) ->
Api.loginMaybeSync syncInput context
Api.loginMaybeSync syncInput vault
X.ServerException (X.M_MISSING_TOKEN _) ->
Api.loginMaybeSync syncInput context
Api.loginMaybeSync syncInput vault
X.ServerException _ ->
Task.fail err
@ -441,7 +429,5 @@ sync (Vault { cred, context }) =
{-| Get a list of all synchronised rooms.
-}
rooms : Vault -> List Room.Room
rooms (Vault { cred, context }) =
cred
|> Internal.getRooms
|> List.map (Room.withCredentials context)
rooms =
Snackbar.mapList Internal.getRooms

View File

@ -119,7 +119,7 @@ getRoomById =
-}
getInvites : Vault -> List RoomInvite
getInvites =
Internal.Vault.getInvites
Internal.Vault.invites
{-| Account data is personal information that the homeserver will remember for you.

View File

@ -107,7 +107,7 @@ this inserts more events at the start of the `[mostRecentEvents](#mostRecentEven
-}
findOlderEvents : { limit : Maybe Int, room : Room } -> Task X.Error VaultUpdate
findOlderEvents { limit, room } =
Internal.getOlderEvents { limit = limit } room
Internal.findOlderEvents { limit = limit } room
{-| This function will always display the most recent events from the Matrix room.

View File

@ -76,7 +76,7 @@ rejectWithReason reason invite =
-}
roomId : RoomInvite -> String
roomId =
Internal.getRoomId
Internal.roomId
{-| The `RoomInviteEvent` type represents a stripped event that your user can see while they haven't joined the group yet.
@ -117,13 +117,15 @@ stateKey =
IR.stateKey
{-| Get a specific event with a specific event content type and state key, if it exists.
-}
getEvent : { eventType : String, stateKey : String } -> RoomInvite -> Maybe RoomInviteEvent
getEvent data invite =
invite
|> Internal.withoutCredentials
|> IR.getEvent data
-- -- TODO: Fix this
-- {-| Get a specific event with a specific event content type and state key, if it exists.
-- -}
-- getEvent : { eventType : String, stateKey : String } -> RoomInvite -> Maybe RoomInviteEvent
-- getEvent data invite =
-- invite
-- |> Internal.withoutCredentials
-- |> IR.getEvent data
{-| Instead of looking at just one event, get all events in a list.