@page "/Rooms/{RoomId}/Policies2"
@using LibMatrix
@using ArcaneLibs.Extensions
@using LibMatrix.EventTypes.Spec.State
@using LibMatrix.EventTypes.Spec.State.Policy
@using System.Diagnostics
@using LibMatrix.RoomTypes
@using System.Collections.Frozen
@using System.Reflection
@using ArcaneLibs.Attributes
@using LibMatrix.EventTypes
@using MatrixUtils.Web.Shared.PolicyEditorComponents
Policy list editor - Editing @RoomId
@* *@
Create new policy
@if (Loading) {
Loading...
}
else if (PolicyEventsByType is not { Count: > 0 }) {
No policies yet
}
else {
var renderSw = Stopwatch.StartNew();
var renderTotalSw = Stopwatch.StartNew();
@foreach (var (type, value) in PolicyEventsByType) {
@(GetValidPolicyEventsByType(type).Count) active,
@(GetInvalidPolicyEventsByType(type).Count) invalid
(@value.Count total)
@(GetPolicyTypeName(type).ToLower())
}
Console.WriteLine($"Rendered hearder in {renderSw.GetElapsedAndRestart()}");
@foreach (var type in KnownPolicyTypes.OrderByDescending(t => GetPolicyEventsByType(t).Count)) {
@($"{GetPolicyTypeName(type)}: {GetPolicyEventsByType(type).Count} policies")
@{
var policies = GetValidPolicyEventsByType(type);
var invalidPolicies = GetInvalidPolicyEventsByType(type);
// enumerate all properties with friendly name
var props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => (x.GetFriendlyNameOrNull() ?? x.GetJsonPropertyNameOrNull()) is not null)
.Where(x => x.GetCustomAttribute
() is null)
.ToFrozenSet();
var propNames = props.Select(x => x.GetFriendlyNameOrNull() ?? x.GetJsonPropertyName()!).ToFrozenSet();
var proxySafeProps = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => props.Any(y => y.Name == x.Name))
.ToFrozenSet();
Console.WriteLine($"{proxySafeProps?.Count} proxy safe props found in {policies.FirstOrDefault()?.TypedContent?.GetType()}");
}
@foreach (var policy in policies.OrderBy(x => x.RawContent?["entity"]?.GetValue())) {
@{
var typedContent = policy.TypedContent!;
}
@foreach (var prop in proxySafeProps ?? Enumerable.Empty
()) {
@prop.GetGetMethod()?.Invoke(typedContent, null) |
}
@if (PowerLevels.UserHasStatePermission(Homeserver.WhoAmI.UserId, policy.Type)) {
Edit
Remove
@if (policy.IsLegacyType) {
Update policy type
}
}
}
@("Invalid " + GetPolicyTypeName(type).ToLower())
State key |
Json contents |
@foreach (var policy in invalidPolicies) {
@policy.StateKey |
@policy.RawContent.ToJson(true, false)
|
}
}
Console.WriteLine($"Rendered policies in {renderSw.GetElapsedAndRestart()}");
Console.WriteLine($"Rendered in {renderTotalSw.Elapsed}");
}
@if (CurrentlyEditingEvent is not null) {
}
@code {
#if DEBUG
private const bool Debug = true;
#else
private const bool Debug = false;
#endif
private bool Loading { get; set; } = true;
[Parameter]
public string RoomId { get; set; } = null!;
private bool _enableAvatars;
private StateEventResponse? _currentlyEditingEvent;
private Dictionary> PolicyEventsByType { get; set; } = new();
private StateEventResponse? CurrentlyEditingEvent {
get => _currentlyEditingEvent;
set {
_currentlyEditingEvent = value;
StateHasChanged();
}
}
private AuthenticatedHomeserverGeneric Homeserver { get; set; }
private GenericRoom Room { get; set; }
private RoomPowerLevelEventContent PowerLevels { get; set; }
protected override async Task OnInitializedAsync() {
var sw = Stopwatch.StartNew();
await base.OnInitializedAsync();
Homeserver = (await RMUStorage.GetCurrentSessionOrNavigate())!;
if (Homeserver is null) return;
Room = Homeserver.GetRoom(RoomId!);
PowerLevels = (await Room.GetPowerLevelsAsync())!;
await LoadStatesAsync();
Console.WriteLine($"Policy list editor initialized in {sw.Elapsed}!");
}
private async Task LoadStatesAsync() {
Loading = true;
var states = Room.GetFullStateAsync();
PolicyEventsByType.Clear();
await foreach (var state in states) {
if (state is null) continue;
if (!state.MappedType.IsAssignableTo(typeof(PolicyRuleEventContent))) continue;
if (!PolicyEventsByType.ContainsKey(state.MappedType)) PolicyEventsByType.Add(state.MappedType, new());
PolicyEventsByType[state.MappedType].Add(state);
}
Loading = false;
StateHasChanged();
}
private List GetPolicyEventsByType(Type type) => PolicyEventsByType.ContainsKey(type) ? PolicyEventsByType[type] : [];
private List GetValidPolicyEventsByType(Type type) => GetPolicyEventsByType(type)
.Where(x => !string.IsNullOrWhiteSpace(x.RawContent?["recommendation"]?.GetValue())).ToList();
private List GetInvalidPolicyEventsByType(Type type) => GetPolicyEventsByType(type)
.Where(x => string.IsNullOrWhiteSpace(x.RawContent?["recommendation"]?.GetValue())).ToList();
private string? GetPolicyTypeNameOrNull(Type type) => type.GetFriendlyNamePluralOrNull()
?? type.GetCustomAttributes()
.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.EventName))?.EventName;
private string GetPolicyTypeName(Type type) => GetPolicyTypeNameOrNull(type) ?? type.Name;
private async Task RemovePolicyAsync(StateEventResponse policyEvent) {
await Room.SendStateEventAsync(policyEvent.Type, policyEvent.StateKey.UrlEncode(), new { });
PolicyEventsByType[policyEvent.MappedType].Remove(policyEvent);
await LoadStatesAsync();
}
private async Task UpdatePolicyAsync(StateEventResponse policyEvent) {
await Room.SendStateEventAsync(policyEvent.Type, policyEvent.StateKey.UrlEncode(), policyEvent.RawContent);
CurrentlyEditingEvent = null;
await LoadStatesAsync();
}
private async Task UpgradePolicyAsync(StateEventResponse policyEvent) {
policyEvent.RawContent["upgraded_from_type"] = policyEvent.Type;
await LoadStatesAsync();
}
private static FrozenSet KnownPolicyTypes = StateEvent.KnownStateEventTypes.Where(x => x.IsAssignableTo(typeof(PolicyRuleEventContent))).ToFrozenSet();
// event types, unnamed
private static Dictionary PolicyTypes = KnownPolicyTypes
.ToDictionary(x => x.GetCustomAttributes().First(y => !string.IsNullOrWhiteSpace(y.EventName)).EventName, x => x);
}