@page "/Tools/Moderation/MembershipHistory" @using System.Collections.ObjectModel @using LibMatrix @using LibMatrix.EventTypes.Spec.State

Membership history viewer



Room ID: Execute

Chronological order

Show joins leaves profile updates knocks invites kicks bans

Hide all Show all Toggle all

Sender: @foreach (var sender in Memberships.Select(x => x.Sender).Distinct()) { }

User: @foreach (var user in Memberships.Select(x => x.StateKey).Distinct()) { }


Results @{ Dictionary previousMemberships = []; var filteredMemberships = Memberships.AsEnumerable(); if (ChronologicalOrder) { filteredMemberships = filteredMemberships.Reverse(); } if (!string.IsNullOrWhiteSpace(Sender)) { filteredMemberships = filteredMemberships.Where(x => x.Sender == Sender); } if (!string.IsNullOrWhiteSpace(User)) { filteredMemberships = filteredMemberships.Where(x => x.StateKey == User); } @foreach (var membership in filteredMemberships) { RoomMemberEventContent content = membership.TypedContent as RoomMemberEventContent; StateEventResponse? previous = previousMemberships.GetValueOrDefault(membership.StateKey); RoomMemberEventContent? previousContent = previous?.TypedContent as RoomMemberEventContent; previousMemberships[membership.StateKey] = membership; }
@DateTimeOffset.FromUnixTimeMilliseconds(membership.OriginServerTs ?? 0).ToString("g") @switch (content.Membership) { case RoomMemberEventContent.MembershipTypes.Invite: { if (_showInvites) {

@membership.Sender invited @membership.StateKey @(string.IsNullOrWhiteSpace(content.Reason) ? "" : $"(reason: {content.Reason})")

} break; } case RoomMemberEventContent.MembershipTypes.Ban: { if (_showBans) {

@membership.Sender banned @membership.StateKey @(string.IsNullOrWhiteSpace(content.Reason) ? "" : $"(reason: {content.Reason})")

} break; } case RoomMemberEventContent.MembershipTypes.Leave: { if (membership.Sender == membership.StateKey) { if (_showLeaves) {

@membership.Sender left the room

} } else { if (_showKicks) {

@membership.Sender kicked @membership.StateKey @(string.IsNullOrWhiteSpace(content.Reason) ? "" : $"(reason: {content.Reason})")

} } break; } case RoomMemberEventContent.MembershipTypes.Knock: { if (_showKnocks) {

@membership.Sender knocked @membership.StateKey @(string.IsNullOrWhiteSpace(content.Reason) ? "" : $"(reason: {content.Reason})")

} break; } case RoomMemberEventContent.MembershipTypes.Join: { if (previousContent is { Membership: RoomMemberEventContent.MembershipTypes.Join }) { if (_showUpdates) {

@membership.Sender changed their profile
Display name: @previousContent.DisplayName -> @content.DisplayName
Avatar URL: @previousContent.AvatarUrl -> @content.AvatarUrl

} } else { if (_showJoins) {

@membership.Sender joined the room @(string.IsNullOrWhiteSpace(content.Reason) ? "" : $"(reason: {content.Reason})")
Display name: @content.DisplayName
Avatar URL: @content.AvatarUrl

} } break; } default: { Unknown membership @content.Membership! break; } }
}

Log @foreach (var line in log.Reverse()) {
@line
}
@code { #region Filter bindings private bool _chronologicalOrder = false; private bool ChronologicalOrder { get => _chronologicalOrder; set { _chronologicalOrder = value; StateHasChanged(); } } private bool _showJoins = true; private bool ShowJoins { get => _showJoins; set { _showJoins = value; StateHasChanged(); } } private bool _showLeaves = true; private bool ShowLeaves { get => _showLeaves; set { _showLeaves = value; StateHasChanged(); } } private bool _showUpdates = true; private bool ShowUpdates { get => _showUpdates; set { _showUpdates = value; StateHasChanged(); } } private bool _showKnocks = true; private bool ShowKnocks { get => _showKnocks; set { _showKnocks = value; StateHasChanged(); } } private bool _showInvites = true; private bool ShowInvites { get => _showInvites; set { _showInvites = value; StateHasChanged(); } } private bool _showKicks = true; private bool ShowKicks { get => _showKicks; set { _showKicks = value; StateHasChanged(); } } private bool _showBans = true; private bool ShowBans { get => _showBans; set { _showBans = value; StateHasChanged(); } } private string sender = ""; private string Sender { get => sender; set { sender = value; StateHasChanged(); } } private string user = ""; private string User { get => user; set { user = value; StateHasChanged(); } } #endregion private ObservableCollection log { get; set; } = new(); private List Memberships { get; set; } = []; private AuthenticatedHomeserverGeneric hs { get; set; } [Parameter, SupplyParameterFromQuery(Name = "room")] public string roomId { get; set; } protected override async Task OnInitializedAsync() { log.CollectionChanged += (sender, args) => StateHasChanged(); hs = await RMUStorage.GetCurrentSessionOrNavigate(); if (hs is null) return; StateHasChanged(); Console.WriteLine("Rerendered!"); await base.OnInitializedAsync(); if (!string.IsNullOrWhiteSpace(roomId)) await Execute(); } private async Task Execute() { Memberships.Clear(); var room = hs.GetRoom(roomId); var events = room.GetManyMessagesAsync(limit: int.MaxValue, chunkSize: 5000); await foreach (var resp in events) { var all = resp.State.Concat(resp.Chunk); Memberships.AddRange(all.Where(x => x.Type == RoomMemberEventContent.EventId)); log.Add($"{resp.State.Count} state, {resp.Chunk.Count} timeline"); } StateHasChanged(); } }