Skip to content

Feature / Simple playground project added #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions RestApia.Shared.sln
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestApia.Extensions.Auth.Ba
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestApia.Extensions.Auth.OAuth2", "src\Extensions\RestApia.Extensions.Auth.OAuth2\RestApia.Extensions.Auth.OAuth2.csproj", "{AE97EEF8-CE4E-0976-B0FB-8C4FC7616E01}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Builder", "Builder", "{07A0437C-C5B5-4FC9-AA80-71C96A11FF54}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Builder.Shared", ".build\Builder.Shared.csproj", "{35A67EB2-CF2D-40B2-B598-685D70F9D94D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestApia.Extensions.Import.Postman", "src\Extensions\RestApia.Extensions.Import.Postman\RestApia.Extensions.Import.Postman.csproj", "{00CAA372-8954-4A50-94C5-6574EBACC467}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Playground", "Playground", "{B9D6F201-FDF7-42BB-A688-C8CBC51B4718}"
Expand All @@ -22,6 +18,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestApia.Extensions.ValuesP
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestApia.Extensions.ValuesProvider.CollectionValuesProvider", "src\Extensions\RestApia.Extensions.ValuesProvider.CollectionValuesProvider\RestApia.Extensions.ValuesProvider.CollectionValuesProvider.csproj", "{47CBF40F-4929-4FA4-A119-054E04AFF40C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestApia.Experiments.Desktop", "src\Playground\RestApia.Experiments.Desktop\RestApia.Experiments.Desktop.csproj", "{D34CE22C-21F9-4464-BE88-93D6E0DC41ED}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -40,10 +38,6 @@ Global
{AE97EEF8-CE4E-0976-B0FB-8C4FC7616E01}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE97EEF8-CE4E-0976-B0FB-8C4FC7616E01}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE97EEF8-CE4E-0976-B0FB-8C4FC7616E01}.Release|Any CPU.Build.0 = Release|Any CPU
{35A67EB2-CF2D-40B2-B598-685D70F9D94D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35A67EB2-CF2D-40B2-B598-685D70F9D94D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35A67EB2-CF2D-40B2-B598-685D70F9D94D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35A67EB2-CF2D-40B2-B598-685D70F9D94D}.Release|Any CPU.Build.0 = Release|Any CPU
{00CAA372-8954-4A50-94C5-6574EBACC467}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{00CAA372-8954-4A50-94C5-6574EBACC467}.Debug|Any CPU.Build.0 = Debug|Any CPU
{00CAA372-8954-4A50-94C5-6574EBACC467}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -60,14 +54,18 @@ Global
{47CBF40F-4929-4FA4-A119-054E04AFF40C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47CBF40F-4929-4FA4-A119-054E04AFF40C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47CBF40F-4929-4FA4-A119-054E04AFF40C}.Release|Any CPU.Build.0 = Release|Any CPU
{D34CE22C-21F9-4464-BE88-93D6E0DC41ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D34CE22C-21F9-4464-BE88-93D6E0DC41ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D34CE22C-21F9-4464-BE88-93D6E0DC41ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D34CE22C-21F9-4464-BE88-93D6E0DC41ED}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9B2C67A1-83B9-157D-5EAF-ADD07B0E8D3F} = {E2CF6B65-E284-39DA-C77D-4FDAB55B16AD}
{AE97EEF8-CE4E-0976-B0FB-8C4FC7616E01} = {E2CF6B65-E284-39DA-C77D-4FDAB55B16AD}
{35A67EB2-CF2D-40B2-B598-685D70F9D94D} = {07A0437C-C5B5-4FC9-AA80-71C96A11FF54}
{00CAA372-8954-4A50-94C5-6574EBACC467} = {E2CF6B65-E284-39DA-C77D-4FDAB55B16AD}
{200B00D8-9D09-464F-B4A8-B7DEC68EE9E8} = {B9D6F201-FDF7-42BB-A688-C8CBC51B4718}
{63845E5A-2440-4322-B06B-4AB9EA415DAE} = {E2CF6B65-E284-39DA-C77D-4FDAB55B16AD}
{47CBF40F-4929-4FA4-A119-054E04AFF40C} = {E2CF6B65-E284-39DA-C77D-4FDAB55B16AD}
{D34CE22C-21F9-4464-BE88-93D6E0DC41ED} = {B9D6F201-FDF7-42BB-A688-C8CBC51B4718}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,30 @@ public async Task<ReloadValuesResults> ReloadValuesAsync(IReadOnlyCollection<Val
if (!VariablesConverter.TryDeserialize<KeyVaultSettings>(inputValues, out var settings))
return ReloadValuesResults.Failed;

var values = await GetRemoteValuesAsync(settings);
if (values == null) return ReloadValuesResults.Failed;

return new ReloadValuesResults
{ Values = await GetRemoteValuesAsync(settings), Status = ValueReloadResultType.Success };
{
Values = values,
Status = ValueReloadResultType.Success,
};
}

private async Task<IReadOnlyCollection<ValueModel>> GetRemoteValuesAsync(KeyVaultSettings settings)
private async Task<IReadOnlyCollection<ValueModel>?> GetRemoteValuesAsync(KeyVaultSettings settings)
{
if (!Uri.TryCreate(settings.KeyVaultUrl, UriKind.Absolute, out var keyVaultUrl))
{
_dialogs.ShowError("Cannot read KeyVault secret values. KeyVault URL is not valid.");
return [];
return null;
}

var credentials = BuildCredentials(settings);
var client = BuildClient(keyVaultUrl, credentials);
var result = await ReadValuesAsync(client, settings);

if (result == null) return null;

return
[
new ()
Expand All @@ -88,14 +96,13 @@ private async Task<IReadOnlyCollection<ValueModel>> GetRemoteValuesAsync(KeyVaul
];
}

private async Task<IReadOnlyCollection<ValueModel>> ReadValuesAsync(SecretClient client, KeyVaultSettings settings)
private async Task<IReadOnlyCollection<ValueModel>?> ReadValuesAsync(SecretClient client, KeyVaultSettings settings)
{
var result = new List<ValueModel>();

try
{
// get list of secrets
var secretProperties = client.GetPropertiesOfSecrets();
var result = new List<ValueModel>();

foreach (var secretProperty in secretProperties)
{
Expand All @@ -107,14 +114,16 @@ private async Task<IReadOnlyCollection<ValueModel>> ReadValuesAsync(SecretClient
Type = ValueTypeEnum.Variable,
});
}

return result;
}
catch (Exception ex)
{
_logger.Fail(ex, $"Cannot read KeyVault secret values from remote. {ex.Message}");
_dialogs.ShowError("Cannot read KeyVault secret values from remote.");
}

return result;
return null;
}
}

private static SecretClient BuildClient(Uri url, TokenCredential credentials)
Expand Down
16 changes: 16 additions & 0 deletions src/Playground/RestApia.Experiments.Desktop/App.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="RestApia.Experiments.Desktop.App"
xmlns:local="using:RestApia.Experiments.Desktop"
RequestedThemeVariant="Dark">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->

<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>

<Application.Styles>
<FluentTheme />
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
</Application.Styles>
</Application>
33 changes: 33 additions & 0 deletions src/Playground/RestApia.Experiments.Desktop/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using AvaloniaWebView;
using RestApia.Experiments.Desktop.Views;

namespace RestApia.Experiments.Desktop;

public class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}

public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow();
AppWindow = desktop.MainWindow;
AvaloniaWebViewBuilder.Initialize(config =>
{
// some settings could be here
});
}

base.OnFrameworkInitializationCompleted();
}

public static Window AppWindow { get; private set; } = null!;
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Avalonia.Controls;
using CustomMessageBox.Avalonia;
using RestApia.Extensions.Auth.Basic;
using RestApia.Shared.Common.Enums;
using RestApia.Shared.Extensions.ValuesProviderService.Enums;
namespace RestApia.Experiments.Desktop.Experiments.Auth;

public class BasicAuthExperiments
{
public static async Task RunBasicAsync()
{
var service = new BasicAuthService();
var result = await service.ReloadValuesAsync([
new () { Name = nameof(BasicAuthSettings.Name), Value = "User", Type = ValueTypeEnum.Variable },
new () { Name = nameof(BasicAuthSettings.Password), Value = "Pa$$word", Type = ValueTypeEnum.Variable },
], ValuesReloadMode.Interactive);

if (!string.IsNullOrWhiteSpace(result.ErrorMessage))
{
await MessageBox.Show(result.ErrorMessage, "Authorization Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}

if (result.Status != ValueReloadResultType.Success)
{
await MessageBox.Show($"Authorization status: {result.Status}", "Authorization", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}

var message = result.Values.Select(x => $"{x.Name}: {x.Value}");
message = [$"Expired: {result.ExpiredAt}", ..message];

await MessageBox.Show(new SelectableTextBlock
{
Text = string.Join("\n", message),
},
"Authorization",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using CustomMessageBox.Avalonia;
using RestApia.Experiments.Desktop.Modules.Dialogs;
using RestApia.Experiments.Desktop.Modules.Logger;
using RestApia.Extensions.Auth.OAuth2.AuthCode;
using RestApia.Extensions.Auth.OAuth2.Implicit;
using RestApia.Shared.Common.Enums;
using RestApia.Shared.Common.Models;
using RestApia.Shared.Common.Services;
using RestApia.Shared.Extensions.ValuesProviderService.Enums;
namespace RestApia.Experiments.Desktop.Experiments.Auth;

public static class OAuth2Experiments
{
public static async Task RunAuthCodeAsync()
{
var service = new OAuth2AuthCodeService(ConsoleExtensionLogger.Instance, new ExtensionDialogs());
var settings = LocalSettings.Get<OAuth2AuthCodeSettings>();
var result = await service.ReloadValuesAsync(VariablesConverter.Serialize(settings), ValuesReloadMode.Interactive);

if (!string.IsNullOrWhiteSpace(result.ErrorMessage))
{
await MessageBox.Show(result.ErrorMessage, "Authorization Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}

if (result.Status != ValueReloadResultType.Success)
{
await MessageBox.Show($"Authorization status: {result.Status}", "Authorization", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}

await MessageGrid.ShowAsync(result
.Values
.Prepend(new ValueModel { Name = "Expired At", Value = result.ExpiredAt?.ToString() ?? "Never expired", Type = ValueTypeEnum.Other })
.Select(x => new { x.Name, Value = x.Value.ToString() }));
}

public static async Task RunImplicitAsync()
{
var service = new OAuth2ImplicitService(ConsoleExtensionLogger.Instance, new ExtensionDialogs());
var settings = LocalSettings.Get<OAuth2ImplicitSettings>();
var result = await service.ReloadValuesAsync(VariablesConverter.Serialize(settings), ValuesReloadMode.Interactive);

if (!string.IsNullOrWhiteSpace(result.ErrorMessage))
{
await MessageBox.Show(result.ErrorMessage, "Authorization Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}

if (result.Status != ValueReloadResultType.Success)
{
await MessageBox.Show($"Authorization status: {result.Status}", "Authorization", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}

await MessageGrid.ShowAsync(result
.Values
.Prepend(new ValueModel { Name = "Expired At", Value = result.ExpiredAt?.ToString() ?? "Never expired", Type = ValueTypeEnum.Other })
.Select(x => new { x.Name, Value = x.Value.ToString() }));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using CustomMessageBox.Avalonia;
using RestApia.Experiments.Desktop.Modules.Dialogs;
using RestApia.Experiments.Desktop.Modules.Logger;
using RestApia.Extensions.ValuesProvider.AzureKeyVault;
using RestApia.Shared.Common.Services;
using RestApia.Shared.Extensions.ValuesProviderService.Enums;
namespace RestApia.Experiments.Desktop.Experiments.Secrets;

public static class AzureKeyVaultExperiments
{
public static async Task RunAsync()
{
var settings = LocalSettings.Get<KeyVaultSettings>();
var service = new KeyVaultValuesProvider(ConsoleExtensionLogger.Instance, new ExtensionDialogs());
var result = await service.ReloadValuesAsync(VariablesConverter.Serialize(settings), ValuesReloadMode.Interactive);

if (!string.IsNullOrWhiteSpace(result.ErrorMessage))
{
await MessageBox.Show(result.ErrorMessage, "Secrets reading Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}

if (result.Status != ValueReloadResultType.Success)
{
await MessageBox.Show($"Secrets status: {result.Status}", "Authorization", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}

await MessageGrid.ShowAsync(result
.Values
.Select(x => new { x.Name, Value = x.Value.ToString() }));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="RestApia.Experiments.Desktop.Modules.Auth.AuthWindow"
Title="AuthWindow">
<Panel>
<WebView x:Name="WebViewControl" Focusable="True" />
</Panel>
</Window>
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Diagnostics.CodeAnalysis;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Microsoft.Web.WebView2.Core;
using RestApia.Shared.Common.Models;
using WebViewCore.Events;

namespace RestApia.Experiments.Desktop.Modules.Auth;

public partial class AuthWindow : Window
{
private readonly string _startUrl;
private readonly string _stopUrl;

[SuppressMessage("ReSharper", "UnusedMember.Global")]
public AuthWindow()
{
if (!Design.IsDesignMode)
throw new Exception("This constructor is only for design mode");

_stopUrl = string.Empty;
_startUrl = string.Empty;

InitializeComponent();
}

public AuthWindow(string startUrl, string stopUrl)
{
_startUrl = startUrl;
_stopUrl = stopUrl;

InitializeComponent();
}

protected override void OnLoaded(RoutedEventArgs e)
{
base.OnLoaded(e);

if (Design.IsDesignMode) return;
WebViewControl.NavigationStarting += NavigateStarting;
WebViewControl.Url = new Uri(_startUrl);
}

protected override void OnUnloaded(RoutedEventArgs e)
{
WebViewControl.NavigationStarting -= NavigateStarting;
base.OnUnloaded(e);
}

private void NavigateStarting(object? sender, WebViewUrlLoadingEventArg e)
{
var url = e.Url?.ToString();
if (string.IsNullOrWhiteSpace(url))
throw new ("Browser navigation url is empty");

if (!url.StartsWith(_stopUrl, StringComparison.OrdinalIgnoreCase)) return;

// stop URL detected
e.Cancel = true;

var headers = new Dictionary<string, string>();
if (e.RawArgs is CoreWebView2NavigationStartingEventArgs args)
headers = args.RequestHeaders.ToDictionary(header => header.Key, header => header.Value);

Dispatcher.UIThread.Post(() => Close(new BrowserDialogResult
{
Url = url,
Headers = headers,
}));
}
}
Loading