summary refs log tree commit diff
path: root/MatrixInviteLogger/InviteLogger.cs
blob: 1a31ed2c6b01c0bcb08a839f448e4fa7f2beb436 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
using System.Text.Json;
using System.Text.Json.Nodes;
using ArcaneLibs;
using ArcaneLibs.Extensions;
using LibMatrix.EventTypes.Spec.State.RoomInfo;
using LibMatrix.Helpers;
using LibMatrix.Utilities.Bot.Services;
using MatrixInviteLogger;

public class InviteLogger(ILogger<InviteLogger> logger, InviteLoggerConfiguration config) : InviteHandlerHostedService.IInviteHandler
{
    public async Task HandleInviteAsync(InviteHandlerHostedService.InviteEventArgs invite)
    {
        logger.LogInformation("Received invite to room {}", invite.RoomId);
        var logRoom = invite.Homeserver.GetRoom(config.LogRoom);
        var inviterName = await GetInviterNameAsync(invite);
        string roomName = await GetRoomNameAsync(invite);

        logger.LogInformation("Inviter: {}, Room: {}", inviterName, roomName);

        var message = new MessageBuilder()
            .WithBody("Received invite to ").WithMention(invite.RoomId, roomName).WithBody(" from ").WithMention(invite.MemberEvent.Sender!, inviterName)
            .Build();

        // TODO: can we filter this somehow to stay within event size limits?
        // var serialisedInviteData = JsonNode.Parse(invite.InviteData.ToJson(ignoreNull: true));
        // message.AdditionalData!["gay.rory.invite_logger.invite_data"] = serialisedInviteData!;

        var inviteData = invite.InviteData.ToJsonUtf8Bytes(ignoreNull: true);
        var inviteDataFileUri = await invite.Homeserver.UploadFile(invite.RoomId + ".json", inviteData, "application/json");
        logger.LogInformation("Uploaded invite data ({}) to {}", Util.BytesToString(inviteData.Length), inviteDataFileUri);
        
        // Dictionary<string, JsonElement>
        message.AdditionalData!["gay.rory.invite_logger.invite_data_uri"] = JsonDocument.Parse($"\"{inviteDataFileUri}\"").RootElement;

        await logRoom.SendMessageEventAsync(message);

        if (config.SendInviteDataAsFile)
        {
            await logRoom.SendMessageEventAsync(new()
            {
                MessageType = "m.file",
                Body = invite.RoomId + ".json",
                FileName = invite.RoomId + ".json",
                Url = inviteDataFileUri,
                FileInfo = new() { Size = inviteData.Length, MimeType = "application/json" }
            });
        }
    }

    private async Task<string> GetInviterNameAsync(InviteHandlerHostedService.InviteEventArgs invite)
    {
        var name = invite.InviteData.InviteState?.Events?
            .FirstOrDefault(evt => evt is { Type: RoomMemberEventContent.EventId } && evt.StateKey == invite.MemberEvent.Sender)?
            .ContentAs<RoomMemberEventContent>()?.DisplayName;

        if (!string.IsNullOrWhiteSpace(name))
            return name;

        try
        {
            await invite.Homeserver.GetProfileAsync(invite.MemberEvent.Sender!);
        }
        catch
        {
            //ignored
        }

        return invite.MemberEvent.Sender!;
    }

    private async Task<string> GetRoomNameAsync(InviteHandlerHostedService.InviteEventArgs invite)
    {
        // try get room name from invite state
        var name = invite.InviteData.InviteState?.Events?
            .FirstOrDefault(evt => evt is { Type: RoomNameEventContent.EventId, StateKey: "" })?
            .ContentAs<RoomNameEventContent>()?.Name;

        if (!string.IsNullOrWhiteSpace(name))
            return name;

        // try get room alias
        var alias = invite.InviteData.InviteState?.Events?
            .FirstOrDefault(evt => evt is { Type: RoomCanonicalAliasEventContent.EventId, StateKey: "" })?
            .ContentAs<RoomCanonicalAliasEventContent>()?.Alias;

        if (!string.IsNullOrWhiteSpace(alias))
            return alias;

        // try get room name via public previews
        try
        {
            name = await invite.Homeserver.GetRoom(invite.RoomId).GetNameOrFallbackAsync();
            if (name != invite.RoomId && !string.IsNullOrWhiteSpace(name))
                return name;
        }
        catch
        {
            //ignored
        }

        // fallback to room alias via public previews
        try
        {
            alias = (await invite.Homeserver.GetRoom(invite.RoomId).GetCanonicalAliasAsync())?.Alias;
            if (!string.IsNullOrWhiteSpace(alias))
                return alias;
        }
        catch
        {
            //ignored
        }

        // fall back to room ID
        return invite.RoomId;
    }
}