Skip to content

Commit

Permalink
clean up json schema, parse device user agent
Browse files Browse the repository at this point in the history
  • Loading branch information
josxha committed Jan 6, 2024
1 parent a9fb1ab commit a017e3a
Show file tree
Hide file tree
Showing 12 changed files with 72 additions and 68 deletions.
8 changes: 4 additions & 4 deletions OryAdmin/Components/Pages/Identities/Users/Create.razor
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ else
</div>

<form @onsubmit="SubmitForm">
@foreach (var schema in _traitsSchemas!)
@foreach (var (schemaPathSections, schema) in _traitsSchemas!)
{
<div class="field">
<label class="label">
@schema.Schema.Title
@schema.Title
<div class="control">
<input type="text" class="input" id="@schema.Schema.Id" value=""
@onchange="args => UpdateValue(schema, args)"/>
<input type="text" class="input" id="@schema.Id" value=""
@onchange="args => _json.UpdateValueWithSchema(schema, schemaPathSections, args.Value)"/>
</div>
</label>
</div>
Expand Down
14 changes: 4 additions & 10 deletions OryAdmin/Components/Pages/Identities/Users/Create.razor.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
using Microsoft.AspNetCore.Components;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using Ory.Kratos.Client.Client;
using Ory.Kratos.Client.Model;
using OryAdmin.Extensions;
using OryAdmin.Models;
using OryAdmin.Services;

namespace OryAdmin.Components.Pages.Identities.Users;

public partial class Create
{
private JObject _json = new();
private string? _errorMessage;
private bool _isLoading = true;
private readonly JObject _json = new();
private bool _schemaDropdownActive;

private List<string>? _schemaIds;
private List<TraitsSchemaData>? _traitsSchemas;
private Dictionary<List<string>, JSchema>? _traitsSchemas;

[SupplyParameterFromQuery(Name = "schema")]
private string? SelectedSchemaId { get; set; }
Expand All @@ -35,7 +34,7 @@ protected override async Task OnParametersSetAsync()
{
_schemaIds ??= await SchemaService.ListIds();
SelectedSchemaId ??= _schemaIds.First();
_traitsSchemas = await SchemaService.GetTraitSchemas(SelectedSchemaId);
_traitsSchemas = await SchemaService.GetTraits(SelectedSchemaId);
}

private void OnSelectionChanged()
Expand All @@ -58,9 +57,4 @@ private async Task SubmitForm()

nav.NavigateTo("identities/users");
}

private void UpdateValue(TraitsSchemaData schema, ChangeEventArgs args)
{
_json.UpdateValueWithSchema(schema, args.Value);
}
}
12 changes: 6 additions & 6 deletions OryAdmin/Components/Pages/Identities/Users/Edit.razor
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
else
{
<form @onsubmit="SubmitForm">
@foreach (var schema in _traitSchemas!)
@foreach (var (schemaPathSections, schema) in _traitSchemas!)
{
var value = _json!.GetTraitValueFromPath(schema.Path);
var value = _json!.GetTraitValueFromPath(schemaPathSections);
<div class="field">
<label class="label">
@schema.Schema.Title
@schema.Title
<div class="control">
<input type="text" class="input" required="@schema.Schema.Required"
value="@value" id="@schema.Schema.Id"
@onchange="args => UpdateValue(schema, args)"/>
<input type="text" class="input" required="@schema.Required"
value="@value" id="@schema.Id"
@onchange="args => _json!.UpdateValueWithSchema(schema, schemaPathSections, args.Value)"/>
</div>
</label>
</div>
Expand Down
10 changes: 4 additions & 6 deletions OryAdmin/Components/Pages/Identities/Users/Edit.razor.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using Microsoft.AspNetCore.Components;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using Ory.Kratos.Client.Client;
using Ory.Kratos.Client.Model;
using OryAdmin.Extensions;
using OryAdmin.Models;
using OryAdmin.Services;

namespace OryAdmin.Components.Pages.Identities.Users;
Expand All @@ -14,7 +13,7 @@ public partial class Edit
private KratosIdentity? _identity;
private bool _isLoading = true;
private JObject? _json;
private List<TraitsSchemaData>? _traitSchemas;
private Dictionary<List<string>, JSchema>? _traitSchemas;
[Parameter] public string? UserId { get; set; }
[Inject] private ApiService ApiService { get; set; } = default!;
[Inject] private IdentitySchemaService SchemaService { get; set; } = default!;
Expand All @@ -23,7 +22,7 @@ protected override async Task OnInitializedAsync()
{
_identity = await ApiService.KratosIdentity.GetIdentityAsync(UserId);
_json = (JObject?)_identity.Traits;
_traitSchemas = await SchemaService.GetTraitSchemas(_identity.SchemaId);
_traitSchemas = await SchemaService.GetTraits(_identity.SchemaId);
_isLoading = false;
}

Expand All @@ -48,8 +47,7 @@ private async Task SubmitForm()
nav.NavigateTo($"identities/users/{UserId}");
}

private void UpdateValue(TraitsSchemaData schema, ChangeEventArgs args)
private void UpdateValue(JSchema schema, ChangeEventArgs args)
{
_json!.UpdateValueWithSchema(schema, args.Value);
}
}
16 changes: 14 additions & 2 deletions OryAdmin/Components/Pages/Identities/Users/Sessions.razor
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@page "/identities/users/{UserId}/sessions"
@using UAParser
@rendermode InteractiveServer
@inject NavigationManager nav

Expand All @@ -11,6 +12,7 @@
}
else
{
var uaParser = Parser.GetDefault();
<div class="box">
<h1 class="title">Active Sessions</h1>
@if (_activeSessions!.Count == 0)
Expand Down Expand Up @@ -40,7 +42,12 @@ else
<td>
@foreach (var device in session.Devices)
{
<p>@device.Id (@device.IpAddress)</p>
var info = uaParser.Parse(device.UserAgent);
<p>
@info.Device.Family on @info.OS
@device.IpAddress
@(string.IsNullOrWhiteSpace(device.Location) ? "" : $"({device.Location})")
</p>
}
</td>
<td>
Expand Down Expand Up @@ -118,7 +125,12 @@ else
<td>
@foreach (var device in session.Devices)
{
<p>@device.Id (@device.IpAddress)</p>
var info = uaParser.Parse(device.UserAgent);
<p>
@info.Device.Family on @info.OS
@device.IpAddress
@(string.IsNullOrWhiteSpace(device.Location) ? "" : $"({device.Location})")
</p>
}
</td>
<td>
Expand Down
11 changes: 10 additions & 1 deletion OryAdmin/Components/Pages/Identities/Users/View.razor
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@page "/identities/users/{UserId}"
@using UAParser
@rendermode InteractiveServer
@inject NavigationManager nav

Expand Down Expand Up @@ -116,6 +117,9 @@ else
</tr>
</thead>
<tbody>
@{
var uaParser = Parser.GetDefault();
}
@foreach (var session in _activeSessions!)
{
<tr>
Expand All @@ -125,7 +129,12 @@ else
<td>
@foreach (var device in session.Devices)
{
<p>@device.Id (@device.IpAddress)</p>
var info = uaParser.Parse(device.UserAgent);
<p>
@info.Device.Family on @info.OS
@device.IpAddress
@(string.IsNullOrWhiteSpace(device.Location) ? "" : $"({device.Location})")
</p>
}
</td>
<td>
Expand Down
1 change: 0 additions & 1 deletion OryAdmin/Components/_Imports.razor
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,4 @@
@using OryAdmin.Components
@using OryAdmin.Extensions
@using OryAdmin.Components.Elements
@using OryAdmin.Models;
@using OryAdmin.Services;
9 changes: 5 additions & 4 deletions OryAdmin/Extensions/JObjectExt.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
using Newtonsoft.Json.Linq;
using OryAdmin.Models;
using Newtonsoft.Json.Schema;

namespace OryAdmin.Extensions;

public static class JObjectExt
{
public static void UpdateValueWithSchema(this JObject json, TraitsSchemaData schema, object? value)
public static void UpdateValueWithSchema(this JObject json, JSchema schema, List<string> schemaPathSections,
object? value)
{
JObject? innerJson = null;
JObject obj; // prevents variable name shadowing
foreach (var path in schema.Path[..^1])
foreach (var path in schemaPathSections[..^1])
{
obj = innerJson ?? json;
if (!obj.ContainsKey(path)) obj.Add(path, new JObject());
innerJson = (JObject?)obj.GetValue(path);
}

// handle last path
var lastPath = schema.Path.Last();
var lastPath = schemaPathSections.Last();
obj = innerJson ?? json;
obj[lastPath] = new JValue(value);
}
Expand Down
14 changes: 0 additions & 14 deletions OryAdmin/Models/TraitsSchemaData.cs

This file was deleted.

1 change: 1 addition & 0 deletions OryAdmin/OryAdmin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<PackageReference Include="Ory.Keto.Client" Version="0.11.0-alpha.0"/>
<PackageReference Include="Ory.Kratos.Client" Version="1.0.0"/>
<PackageReference Include="Ory.Oathkeeper.Client" Version="0.40.6"/>
<PackageReference Include="UAParser" Version="3.1.47"/>
</ItemGroup>

<ItemGroup>
Expand Down
42 changes: 22 additions & 20 deletions OryAdmin/Services/IdentitySchemaService.cs
Original file line number Diff line number Diff line change
@@ -1,62 +1,64 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Schema;
using OryAdmin.Models;
using Newtonsoft.Json.Schema;

namespace OryAdmin.Services;

public class IdentitySchemaService(ApiService apiService)
{
private readonly Dictionary<string, JObject> _schemaCache = new();
private readonly Dictionary<string, JSchema> _schemaCache = new();

public async Task<JObject> GetById(string schemaId)
public async Task<JSchema> FetchById(string schemaId)
{
// check if schema object is cached
if (_schemaCache.TryGetValue(schemaId, out var schema))
return schema;
// request and cache new schema object
var newSchema = await apiService.KratosIdentity.GetIdentitySchemaAsync(schemaId);
_schemaCache[schemaId] = (JObject)newSchema;
_schemaCache[schemaId] = JSchema.Parse(newSchema.ToString()!);
return _schemaCache[schemaId];
}

public async Task<List<string>> ListIds()
{
var schemas = await apiService.KratosIdentity.ListIdentitySchemasAsync();
foreach (var container in schemas) _schemaCache[container.Id] = (JObject)container.Schema;
foreach (var container in schemas) _schemaCache[container.Id] = JSchema.Parse(container.Schema.ToString()!);
return schemas.Select(container => container.Id).ToList();
}

public async Task<List<TraitsSchemaData>> GetTraitSchemas(string schemaId)
public async Task<Dictionary<List<string>, JSchema>> GetTraits(string schemaId)
{
var schema = await FetchById(schemaId);
return GetTraits(schema);
}


public static Dictionary<List<string>, JSchema> GetTraits(JSchema schema)
{
var schemaObject = await GetById(schemaId);
var schema = JSchema.Parse(schemaObject.ToString());
var traits = schema.Properties["traits"].Properties;
return FlattenTraits(traits, []);
}

private static List<TraitsSchemaData> FlattenTraits(IDictionary<string, JSchema> traits, List<string> path)
private static Dictionary<List<string>, JSchema> FlattenTraits(IDictionary<string, JSchema> traits,
IReadOnlyCollection<string> pathSections)
{
var list = new List<TraitsSchemaData>();
var map = new Dictionary<List<string>, JSchema>();
foreach (var (traitKey, trait) in traits)
{
var newPath = new List<string>(path) { traitKey };
var newPathSections = new List<string>(pathSections) { traitKey };
switch (trait.Type)
{
case JSchemaType.String:
list.Add(new TraitsSchemaData(trait, newPath));
break;
case JSchemaType.Object:
list.AddRange(FlattenTraits(trait.Properties, newPath));
foreach (var entry in FlattenTraits(trait.Properties, newPathSections))
map[entry.Key] = entry.Value;
break;
case JSchemaType.Array:
// TODO support arrays
break;
default:
list.Add(new TraitsSchemaData(trait, newPath));
default: // string, etc.
map[newPathSections] = trait;
break;
}
}

return list;
return map;
}
}
2 changes: 2 additions & 0 deletions OryUI.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kratos/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

0 comments on commit a017e3a

Please sign in to comment.