diff --git a/src/Internal/Values/Vault.elm b/src/Internal/Values/Vault.elm index 01b7ad1..aaed701 100644 --- a/src/Internal/Values/Vault.elm +++ b/src/Internal/Values/Vault.elm @@ -6,11 +6,13 @@ It handles all communication with the homeserver. import Internal.Tools.Hashdict as Hashdict exposing (Hashdict) import Internal.Values.Room as Room exposing (IRoom) +import Internal.Values.RoomInvite as Invite exposing (IRoomInvite) type IVault = IVault - { rooms : Hashdict IRoom + { invites : List IRoomInvite + , rooms : Hashdict IRoom , since : Maybe String } @@ -22,6 +24,20 @@ addSince since (IVault data) = IVault { data | since = Just since } +{-| Add a new invite. +-} +addInvite : IRoomInvite -> IVault -> IVault +addInvite invite (IVault data) = + IVault { data | invites = List.append data.invites [ invite ] } + + +{-| Get all the invited rooms of a user. +-} +getInvites : IVault -> List IRoomInvite +getInvites (IVault data) = + data.invites + + {-| Get a room from the Credentials type by the room's id. -} getRoomById : String -> IVault -> Maybe IRoom @@ -48,7 +64,8 @@ getSince (IVault { since }) = init : IVault init = IVault - { rooms = Hashdict.empty Room.roomId + { invites = [] + , rooms = Hashdict.empty Room.roomId , since = Nothing } @@ -59,6 +76,13 @@ This function can hence also be used as an update function for rooms. -} insertRoom : IRoom -> IVault -> IVault -insertRoom room (IVault cred) = +insertRoom room (IVault data) = IVault - { cred | rooms = Hashdict.insert room cred.rooms } + { data | rooms = Hashdict.insert room data.rooms } + + +{-| Remove an invite. This is usually done when the invite has been accepted or rejected. +-} +removeInvite : String -> IVault -> IVault +removeInvite roomId (IVault data) = + IVault { data | invites = List.filter (\i -> Invite.roomId i /= roomId) data.invites } diff --git a/src/Matrix.elm b/src/Matrix.elm new file mode 100644 index 0000000..24497df --- /dev/null +++ b/src/Matrix.elm @@ -0,0 +1,118 @@ +module Matrix exposing (..) + +{-| This is the main module of the SDK. Here, you will find basic functions to +interact with the API. + + +# Create a new Vault + +@docs Vault, fromLoginCredentials, fromAccessToken + + +# Keeping your Vault up-to-date + +@docs sync, VaultUpdate, updateWith + + +# Exploring your vault + +@docs getRooms, getRoomById, accessToken + +-} + +import Internal.Api.VaultUpdate as Api +import Internal.Invite exposing (RoomInvite) +import Internal.Room exposing (Room) +import Internal.Tools.Exceptions as X +import Internal.Vault +import Task exposing (Task) + + +{-| The Matrix API requires you to keep track of a lot of tokens, keys, values and more. +Luckily, you don't need to! + +You can view the `Vault` as a large box of keys that will help you get +the information that you need. The type also caches information that it receives +from the API, so you can also ask it for information that it has seen before. + +-} +type alias Vault = + Internal.Vault.Vault + + +{-| The `VaultUpdate` is a type that helps you keep your `Vault` type up-to-date. +Sometimes, the API will tell you to change certain tokens, and this SDK will +translate those instructions to a `VaultUpdate` that you can feed to your `Vault`. +-} +type alias VaultUpdate = + Api.VaultUpdate + + +{-| Create a new vault based on an access token. +Keep in mind that access tokens might eventually be revoked or expire, +so it is better to use login credentials if you're planning to use a Vault long-term. +-} +fromAccessToken : { accessToken : String, baseUrl : String } -> Vault +fromAccessToken = + Internal.Vault.fromAccessToken + + +{-| Based on a user's username and password, you can create a vault that will automatically +log in if an access token ever happens to run out, expire or lose contact in any other way. +-} +fromLoginCredentials : { baseUrl : String, username : String, password : String } -> Vault +fromLoginCredentials = + Internal.Vault.fromLoginVault + + +{-| Whenever you're asking the Matrix API for information that your Vault doesn't have, +you will receive a `VaultUpdate` type. This will reorganise your Vault with the newly +gained information. + +After having updated your vault, it (usually) has all the information you need. + +-} +updateWith : VaultUpdate -> Vault -> Vault +updateWith = + Internal.Vault.updateWith + + +{-| The Matrix API is always looking for new ways to optimize synchronising events to your client. +Luckily, you don't need to worry about keeping up a connection! + +Your vault is always a snapshot of changes since the last time you updated it. +If you'd like to update it once more, simply run this function and the API will make sure that your Vault has the latest changes. + +-} +sync : Vault -> Task X.Error VaultUpdate +sync = + Internal.Vault.sync + + +{-| Get all the rooms your user has joined, according to your vault. +-} +getRooms : Vault -> List Room +getRooms = + Internal.Vault.rooms + + +{-| Get a Matrix room by its id. +This will only return the room if you have joined the room. +-} +getRoomById : String -> Vault -> Maybe Room +getRoomById = + Internal.Vault.getRoomById + + +{-| Get all invites that the user is invited to. +-} +getInvites : Vault -> List RoomInvite +getInvites = + Internal.Vault.getInvites + + +{-| Join a Matrix room based on its room id. +-} +joinRoomById : String -> Vault -> Task X.Error VaultUpdate +joinRoomById = + Internal.Vault.joinRoomById diff --git a/src/Matrix/RoomInvite.elm b/src/Matrix/RoomInvite.elm new file mode 100644 index 0000000..50bffbe --- /dev/null +++ b/src/Matrix/RoomInvite.elm @@ -0,0 +1,124 @@ +module Matrix.RoomInvite exposing (..) + +{-| Sometimes, your user will be invited to a new room! +This module offers you a few simple handles to deal with such invites - +you can accept them, reject them or inspect them for further information. + + +# Invitations + +@docs RoomInvite, accept, reject, acceptWithReason, rejectWithReason + + +# Exploring invitations + +Sometimes, you may want to display information about the room. + +Be careful though, anyone can invite you to any room! This means that room invites +may contain offensive, shocking or other unwanted content that the user may not +want to see. + +-} + +import Internal.Api.VaultUpdate exposing (VaultUpdate) +import Internal.Invite as Internal +import Internal.Room exposing (Room) +import Internal.Tools.Exceptions as X +import Internal.Values.RoomInvite as IR +import Json.Encode as E +import Task exposing (Task) + + +{-| The `RoomInvite` type serves as an invite to a given room. +-} +type alias RoomInvite = + Internal.RoomInvite + + +{-| If you would like to join a room, you can accept the offer. +-} +accept : RoomInvite -> Task X.Error VaultUpdate +accept invite = + Internal.accept { invite = invite, reason = Nothing } + + +{-| If you don't want to join the room, you can reject the offer. +-} +reject : RoomInvite -> Task X.Error VaultUpdate +reject invite = + Internal.reject { invite = invite, reason = Nothing } + + +{-| If the Matrix server supports it, you can add a reason for accepting an invite. +-} +acceptWithReason : String -> RoomInvite -> Task X.Error VaultUpdate +acceptWithReason reason invite = + Internal.accept { invite = invite, reason = Just reason } + + +{-| If the Matrix server supports it, you can add a reason for rejecting an invite. +-} +rejectWithReason : String -> RoomInvite -> Task X.Error VaultUpdate +rejectWithReason reason invite = + Internal.reject { invite = invite, reason = Just reason } + + +{-| Get the room id of the invited room. +-} +roomId : RoomInvite -> String +roomId = + Internal.getRoomId + + +{-| The `RoomInviteEvent` type represents a stripped event that your user can see while they haven't joined the group yet. + +The invite includes a bunch of these events to tell you what the room looks like, who may be part of it, +and other information that will give you a hint of what kind of room it is. + +-} +type alias RoomInviteEvent = + IR.RoomInviteEvent + + +{-| Get the Matrix user that originally sent this event. +-} +sender : RoomInviteEvent -> String +sender = + IR.sender + + +{-| Get the content of the event. +-} +content : RoomInviteEvent -> E.Value +content = + IR.content + + +{-| Get the event's content type. +-} +contentType : RoomInviteEvent -> String +contentType = + IR.contentType + + +{-| Get the event's state key. +-} +stateKey : RoomInviteEvent -> String +stateKey = + IR.stateKey + + +{-| Get a specific event with a specific event content type and state key, if it exists. +-} +getEvent : { contentType : 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. +-} +getAllEvents : RoomInvite -> List RoomInviteEvent +getAllEvents = + Internal.getAllEvents