14 Commits

58 changed files with 5910 additions and 61 deletions

View File

@@ -33,15 +33,16 @@
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0"/>
<PackageVersion Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.11"/>
<PackageVersion Include="Microsoft.AspNetCore.Components.Authorization" Version="9.0.11"/>
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.2.1"/>
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
<!-- Add more community toolkit references here -->
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) != 'windows'">
<PackageVersion Include="Uno.CommunityToolkit.WinUI.UI.Controls" Version="7.1.200" />
<!-- Add more uno community toolkit references here -->
</ItemGroup>
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2"/>
<!-- Add more community toolkit references here -->
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) != 'windows'">
<PackageVersion Include="Uno.CommunityToolkit.WinUI.UI.Controls" Version="7.1.200"/>
<!-- Add more uno community toolkit references here -->
</ItemGroup>
</Project>

View File

@@ -8,6 +8,7 @@
<ResourceDictionary.MergedDictionaries>
<!-- Load WinUI resources -->
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Load Uno.UI.Toolkit resources -->
<ToolkitResources xmlns="using:Uno.Toolkit.UI" />
</ResourceDictionary.MergedDictionaries>
@@ -16,6 +17,11 @@
<local:ObjectToVisibilityConverter x:Key="ObjectToVisibilityConverter" />
<local:StringToVisibilityConverter x:Key="StringToVisibilityConverter" />
<local:ZeroToVisibilityConverter x:Key="ZeroToVisibilityConverter" />
<local:InvertBoolConverter x:Key="InvertBoolConverter" />
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<local:InvertBoolToVisibilityConverter x:Key="InvertBoolToVisibilityConverter" />
<local:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<local:RolesListConverter x:Key="RolesListConverter" />
</ResourceDictionary>
</Application.Resources>

View File

@@ -2,9 +2,11 @@ using System.Net.Http;
using Marechai.App.Presentation.ViewModels;
using Marechai.App.Presentation.Views;
using Marechai.App.Services;
using Marechai.App.Services.Authentication;
using Marechai.App.Services.Caching;
using Microsoft.UI.Xaml;
using Uno.Extensions;
using Uno.Extensions.Authentication;
using Uno.Extensions.Configuration;
using Uno.Extensions.Hosting;
using Uno.Extensions.Http;
@@ -22,8 +24,10 @@ using NewsViewModel = Marechai.App.Presentation.ViewModels.NewsViewModel;
using PhotoDetailViewModel = Marechai.App.Presentation.ViewModels.PhotoDetailViewModel;
using ProcessorDetailViewModel = Marechai.App.Presentation.ViewModels.ProcessorDetailViewModel;
using ProcessorsListViewModel = Marechai.App.Presentation.ViewModels.ProcessorsListViewModel;
using SettingsViewModel = Marechai.App.Presentation.ViewModels.SettingsViewModel;
using SoundSynthDetailViewModel = Marechai.App.Presentation.ViewModels.SoundSynthDetailViewModel;
using SoundSynthsListViewModel = Marechai.App.Presentation.ViewModels.SoundSynthsListViewModel;
using LoginViewModel = Marechai.App.Presentation.ViewModels.LoginViewModel;
namespace Marechai.App;
@@ -93,6 +97,8 @@ public partial class App : Application
.UseLocalization()
.UseHttp((context, services) =>
{
services.AddTransient<DelegatingHandler,
HttpAuthHandler>();
#if DEBUG
// DelegatingHandler will be automatically injected
@@ -114,6 +120,16 @@ public partial class App : Application
.ConfigureServices((context, services) =>
{
// Register application services
services
.AddSingleton<IColorThemeService,
ColorThemeService>();
services
.AddSingleton<IAuthenticationService,
AuthService>();
services.AddSingleton<ITokenService, TokenService>();
services.AddSingleton<IJwtService, JwtService>();
services.AddSingleton<FlagCache>();
services.AddSingleton<CompanyLogoCache>();
services.AddSingleton<MachinePhotoCache>();
@@ -149,6 +165,8 @@ public partial class App : Application
services.AddTransient<ProcessorDetailViewModel>();
services.AddTransient<SoundSynthsListViewModel>();
services.AddTransient<SoundSynthDetailViewModel>();
services.AddTransient<SettingsViewModel>();
services.AddTransient<LoginViewModel>();
})
.UseNavigation(RegisterRoutes));
@@ -166,6 +184,7 @@ public partial class App : Application
{
views.Register(new ViewMap(ViewModel: typeof(ShellViewModel)),
new ViewMap<MainPage, MainViewModel>(),
new ViewMap<LoginPage, LoginViewModel>(),
new ViewMap<NewsPage, NewsViewModel>(),
new ViewMap<ComputersPage, ComputersViewModel>(),
new ViewMap<ComputersListPage, ComputersListViewModel>(),
@@ -181,12 +200,15 @@ public partial class App : Application
new ViewMap<ProcessorDetailPage, ProcessorDetailViewModel>(),
new ViewMap<SoundSynthListPage, SoundSynthsListViewModel>(),
new ViewMap<SoundSynthDetailPage, SoundSynthDetailViewModel>(),
new ViewMap<SettingsPage, SettingsViewModel>(),
new ViewMap<UsersPage, UsersViewModel>(),
new DataViewMap<SecondPage, SecondViewModel, Entity>());
routes.Register(new RouteMap("",
views.FindByViewModel<ShellViewModel>(),
Nested:
[
new RouteMap("Login", views.FindByViewModel<LoginViewModel>()),
new RouteMap("Main",
views.FindByViewModel<MainViewModel>(),
true,
@@ -197,7 +219,8 @@ public partial class App : Application
true),
new RouteMap("computers",
views.FindByViewModel<ComputersViewModel>(),
Nested:
Nested
:
[
new RouteMap("list-computers",
views.FindByViewModel<
@@ -208,7 +231,8 @@ public partial class App : Application
]),
new RouteMap("consoles",
views.FindByViewModel<ConsolesViewModel>(),
Nested:
Nested
:
[
new RouteMap("list-consoles",
views.FindByViewModel<
@@ -216,7 +240,8 @@ public partial class App : Application
]),
new RouteMap("companies",
views.FindByViewModel<CompaniesViewModel>(),
Nested:
Nested
:
[
new RouteMap("company-details",
views.FindByViewModel<
@@ -224,7 +249,8 @@ public partial class App : Application
]),
new RouteMap("gpus",
views.FindByViewModel<GpuListViewModel>(),
Nested:
Nested
:
[
new RouteMap("gpu-details",
views.FindByViewModel<
@@ -239,7 +265,8 @@ public partial class App : Application
ProcessorDetailViewModel>())
]),
new RouteMap("sound-synths",
views.FindByViewModel<SoundSynthsListViewModel>(),
views.FindByViewModel<
SoundSynthsListViewModel>(),
Nested:
[
new RouteMap("sound-synth-details",
@@ -249,6 +276,10 @@ public partial class App : Application
views.FindByViewModel<
MachineViewViewModel>())
]),
new RouteMap("settings",
views.FindByViewModel<SettingsViewModel>()),
new RouteMap("users",
views.FindByViewModel<UsersViewModel>()),
new RouteMap("Second",
views.FindByViewModel<SecondViewModel>())
])

View File

@@ -35,15 +35,17 @@
Localization;
Navigation;
ThemeService;
Storage;
SkiaRenderer;
Svg;
</UnoFeatures>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Marechai.Data\Marechai.Data.csproj" />
<ProjectReference Include="..\Marechai.Data\Marechai.Data.csproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Humanizer" />
<PackageReference Include="Humanizer"/>
<PackageReference Include="System.IdentityModel.Tokens.Jwt"/>
</ItemGroup>
<ItemGroup>
<Compile Update="Presentation\Views\Shell.xaml.cs">
@@ -78,16 +80,20 @@
<DependentUpon>Sidebar.xaml</DependentUpon>
<IsDefaultItem>true</IsDefaultItem>
</Compile>
<Compile Update="Presentation\Views\UsersPage.xaml.cs">
<DependentUpon>UsersPage.xaml</DependentUpon>
<IsDefaultItem>true</IsDefaultItem>
</Compile>
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls" />
<!-- Add more community toolkit references here -->
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) != 'windows'">
<PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls" />
<!-- Add more uno community toolkit references here -->
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">
<PackageReference Include="CommunityToolkit.WinUI.UI.Controls"/>
<!-- Add more community toolkit references here -->
</ItemGroup>
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) != 'windows'">
<PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls"/>
<!-- Add more uno community toolkit references here -->
</ItemGroup>
</Project>

View File

@@ -231,6 +231,19 @@
Visibility="{Binding IsSidebarOpen}">
<StackPanel Orientation="Vertical"
Spacing="0">
<!-- Users (Uberadmin only) -->
<Button Content="User Management"
Command="{Binding NavigateToUsersCommand}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
Padding="16,10,16,10"
FontSize="13"
Background="Transparent"
Foreground="{ThemeResource TextFillColorPrimaryBrush}"
BorderThickness="0"
CornerRadius="0"
Visibility="{Binding IsUberadminUser, Converter={StaticResource BoolToVisibilityConverter}}" />
<!-- Login/Logout -->
<Button Content="{Binding LoginLogoutButtonText}"
Command="{Binding LoginLogoutCommand}"

View File

@@ -0,0 +1,9 @@
#nullable enable
namespace Marechai.App.Presentation.Models;
public class SoundSynthDetailNavigationParameter
{
public int SoundSynthId { get; set; }
public object? NavigationSource { get; set; }
}

View File

@@ -0,0 +1,93 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Uno.Extensions.Authentication;
using Uno.Extensions.Navigation;
namespace Marechai.App.Presentation.ViewModels;
public partial class LoginViewModel : ObservableObject
{
private readonly IAuthenticationService _authService;
private readonly INavigator _navigator;
private readonly IStringLocalizer _stringLocalizer;
[ObservableProperty]
private string _email = string.Empty;
[ObservableProperty]
private string? _errorMessage;
[ObservableProperty]
private bool _isLoggingIn;
[ObservableProperty]
private string _password = string.Empty;
public LoginViewModel(INavigator navigator, IAuthenticationService authService, IStringLocalizer stringLocalizer)
{
_navigator = navigator;
_authService = authService;
_stringLocalizer = stringLocalizer;
}
[RelayCommand]
private async Task LoginAsync()
{
// Clear previous error
ErrorMessage = null;
// Validate inputs
if(string.IsNullOrWhiteSpace(Email))
{
ErrorMessage = _stringLocalizer["LoginPage.Error.EmailRequired"];
return;
}
if(string.IsNullOrWhiteSpace(Password))
{
ErrorMessage = _stringLocalizer["LoginPage.Error.PasswordRequired"];
return;
}
IsLoggingIn = true;
try
{
var credentials = new Dictionary<string, string>
{
["Email"] = Email,
["Password"] = Password
};
bool success = await _authService.LoginAsync(null, credentials, null, CancellationToken.None);
if(success)
{
// Navigate back to main page on successful login
await _navigator.NavigateRouteAsync(this, "/Main");
}
else
{
// Check if there's an error message in credentials
if(credentials.TryGetValue("error", out string? error))
ErrorMessage = error;
else
ErrorMessage = _stringLocalizer["LoginPage.Error.LoginFailed"];
}
}
catch(Exception ex)
{
ErrorMessage = ex.Message;
}
finally
{
IsLoggingIn = false;
}
}
[RelayCommand]
private void ClearError() => ErrorMessage = null;
}

View File

@@ -1,18 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using Marechai.App.Services;
using Marechai.App.Services.Authentication;
using Uno.Extensions.Authentication;
using Uno.Extensions.Navigation;
using Uno.Extensions.Toolkit;
namespace Marechai.App.Presentation.ViewModels;
public partial class MainViewModel : ObservableObject
{
private readonly IStringLocalizer _localizer;
private readonly INavigator _navigator;
private readonly IAuthenticationService _authService;
private readonly IJwtService _jwtService;
private readonly IStringLocalizer _localizer;
private readonly INavigator _navigator;
private readonly ITokenService _tokenService;
[ObservableProperty]
private bool _isSidebarOpen = true;
[ObservableProperty]
private bool _isUberadminUser;
[ObservableProperty]
private Dictionary<string, string> _localizedStrings = new();
[ObservableProperty]
private string _loginLogoutButtonText = "";
@@ -25,10 +36,14 @@ public partial class MainViewModel : ObservableObject
private bool _sidebarContentVisible = true;
public MainViewModel(IStringLocalizer localizer, IOptions<AppConfig> appInfo, INavigator navigator,
NewsViewModel newsViewModel)
NewsViewModel newsViewModel, IColorThemeService colorThemeService, IThemeService themeService,
IAuthenticationService authService, IJwtService jwtService, ITokenService tokenService)
{
_navigator = navigator;
_localizer = localizer;
_authService = authService;
_jwtService = jwtService;
_tokenService = tokenService;
NewsViewModel = newsViewModel;
Title = "Marechai";
Title += $" - {localizer["ApplicationName"]}";
@@ -36,6 +51,9 @@ public partial class MainViewModel : ObservableObject
GoToSecond = new AsyncRelayCommand(GoToSecondView);
// Initialize color theme service with theme service
_ = InitializeThemeServicesAsync(colorThemeService, themeService);
// Initialize localized strings
InitializeLocalizedStrings();
@@ -53,11 +71,16 @@ public partial class MainViewModel : ObservableObject
NavigateToProcessorsCommand = new AsyncRelayCommand(() => NavigateTo("processors"));
NavigateToSoftwareCommand = new AsyncRelayCommand(() => NavigateTo("software"));
NavigateToSoundSynthesizersCommand = new AsyncRelayCommand(() => NavigateTo("sound-synths"));
NavigateToUsersCommand = new AsyncRelayCommand(() => NavigateTo("users"));
NavigateToSettingsCommand = new AsyncRelayCommand(() => NavigateTo("settings"));
LoginLogoutCommand = new RelayCommand(HandleLoginLogout);
ToggleSidebarCommand = new RelayCommand(() => IsSidebarOpen = !IsSidebarOpen);
// Subscribe to authentication events
_authService.LoggedOut += OnLoggedOut;
UpdateLoginLogoutButtonText();
UpdateUberadminStatus();
}
public string? Title { get; }
@@ -77,10 +100,27 @@ public partial class MainViewModel : ObservableObject
public ICommand NavigateToProcessorsCommand { get; }
public ICommand NavigateToSoftwareCommand { get; }
public ICommand NavigateToSoundSynthesizersCommand { get; }
public ICommand NavigateToUsersCommand { get; }
public ICommand NavigateToSettingsCommand { get; }
public ICommand LoginLogoutCommand { get; }
public ICommand ToggleSidebarCommand { get; }
private async Task InitializeThemeServicesAsync(IColorThemeService colorThemeService, IThemeService themeService)
{
try
{
// Wait for theme service to be ready
await themeService.InitializeAsync();
// Set the theme service reference and reapply the saved theme
colorThemeService.SetThemeService(themeService);
}
catch
{
// Silently fail - theme will work but without refresh on startup
}
}
private void InitializeLocalizedStrings()
{
LocalizedStrings = new Dictionary<string, string>
@@ -136,16 +176,62 @@ public partial class MainViewModel : ObservableObject
};
}
private void UpdateLoginLogoutButtonText()
private async void UpdateLoginLogoutButtonText()
{
// TODO: Check if user is logged in
// For now, always show "Login"
LoginLogoutButtonText = LocalizedStrings["Login"];
bool isAuthenticated = await _authService.IsAuthenticated(CancellationToken.None);
LoginLogoutButtonText = isAuthenticated ? LocalizedStrings["Logout"] : LocalizedStrings["Login"];
}
private static void HandleLoginLogout()
private void UpdateUberadminStatus()
{
// TODO: Implement login/logout logic
try
{
string token = _tokenService.GetToken();
if(!string.IsNullOrWhiteSpace(token))
{
IEnumerable<string> roles = _jwtService.GetRoles(token);
IsUberadminUser = roles.Contains("Uberadmin", StringComparer.OrdinalIgnoreCase);
}
else
IsUberadminUser = false;
}
catch
{
IsUberadminUser = false;
}
}
private void OnLoggedOut(object? sender, EventArgs e)
{
// Update button text when user logs out
UpdateLoginLogoutButtonText();
UpdateUberadminStatus();
}
public void RefreshAuthenticationState()
{
// Public method to refresh authentication state (called after login)
UpdateLoginLogoutButtonText();
UpdateUberadminStatus();
}
private async void HandleLoginLogout()
{
bool isAuthenticated = await _authService.IsAuthenticated(CancellationToken.None);
if(isAuthenticated)
{
// Logout
await _authService.LogoutAsync(null, CancellationToken.None);
UpdateLoginLogoutButtonText();
UpdateUberadminStatus();
}
else
{
// Navigate to login page - use absolute path starting from root
await _navigator.NavigateRouteAsync(this, "/Login");
}
}
private async Task NavigateTo(string destination)

View File

@@ -0,0 +1,190 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Marechai.App.Services;
using Uno.Extensions.Toolkit;
namespace Marechai.App.Presentation.ViewModels;
public partial class SettingsViewModel : ObservableObject
{
private readonly IColorThemeService _colorThemeService;
private readonly IStringLocalizer _localizer;
private readonly IThemeService _themeService;
[ObservableProperty]
private List<ColorThemeOption> _availableColorThemes = new();
[ObservableProperty]
private List<ThemeOption> _availableThemes = new();
[ObservableProperty]
private ColorThemeOption _selectedColorTheme;
[ObservableProperty]
private ThemeOption _selectedTheme;
public SettingsViewModel(IStringLocalizer localizer, IThemeService themeService,
IColorThemeService colorThemeService)
{
_localizer = localizer;
_themeService = themeService;
_colorThemeService = colorThemeService;
Title = _localizer["Settings"];
// Initialize immediately to ensure UI is populated
InitializeOptions();
// Wait for theme service to initialize
_ = InitializeThemeServiceAsync();
}
public string Title { get; }
private async Task InitializeThemeServiceAsync()
{
try
{
await _themeService.InitializeAsync();
// Ensure the color theme service has a reference to the theme service
_colorThemeService.SetThemeService(_themeService);
}
catch
{
// Theme service might already be initialized
}
}
private void InitializeOptions()
{
// Initialize Light/Dark/System Themes
AvailableThemes = new List<ThemeOption>
{
new()
{
Theme = AppTheme.Light,
DisplayName = _localizer["LightTheme"]
},
new()
{
Theme = AppTheme.Dark,
DisplayName = _localizer["DarkTheme"]
},
new()
{
Theme = AppTheme.System,
DisplayName = _localizer["SystemTheme"]
}
};
// Initialize Color Themes
AvailableColorThemes = new List<ColorThemeOption>
{
new()
{
ThemeName = "Default",
DisplayName = _localizer["DefaultColorTheme"]
},
new()
{
ThemeName = "Windows311",
DisplayName = _localizer["Windows311Theme"]
},
new()
{
ThemeName = "MacOS9",
DisplayName = _localizer["MacOS9Theme"]
},
new()
{
ThemeName = "DOS",
DisplayName = _localizer["DOSTheme"]
},
new()
{
ThemeName = "Amiga",
DisplayName = _localizer["AmigaTheme"]
},
new()
{
ThemeName = "CDE",
DisplayName = _localizer["CDETheme"]
}
};
// Try to load saved preferences
LoadSavedPreferences();
}
private async void LoadSavedPreferences()
{
try
{
// Load current theme from ThemeService
AppTheme currentTheme = _themeService.Theme;
SelectedTheme = AvailableThemes.FirstOrDefault(t => t.Theme == currentTheme) ??
AvailableThemes.FirstOrDefault(t => t.Theme == AppTheme.System) ?? AvailableThemes.First();
// Load current color theme
string currentColorTheme = _colorThemeService.CurrentColorTheme;
SelectedColorTheme = AvailableColorThemes.FirstOrDefault(t => t.ThemeName == currentColorTheme) ??
AvailableColorThemes.First();
}
catch
{
// If loading fails, use defaults
SelectedTheme = AvailableThemes.FirstOrDefault(t => t.Theme == AppTheme.System) ?? AvailableThemes.First();
SelectedColorTheme = AvailableColorThemes.First();
}
}
partial void OnSelectedThemeChanged(ThemeOption value)
{
if(value != null) ApplyTheme(value);
}
partial void OnSelectedColorThemeChanged(ColorThemeOption value)
{
if(value != null) ApplyColorTheme(value);
}
private async void ApplyTheme(ThemeOption theme)
{
try
{
// Apply theme immediately using ThemeService
await _themeService.SetThemeAsync(theme.Theme);
}
catch
{
// Silently fail
}
}
private void ApplyColorTheme(ColorThemeOption colorTheme)
{
try
{
_colorThemeService.ApplyColorTheme(colorTheme.ThemeName);
}
catch
{
// Silently fail
}
}
}
public class ThemeOption
{
public AppTheme Theme { get; set; }
public string DisplayName { get; set; } = string.Empty;
}
public class ColorThemeOption
{
public string ThemeName { get; set; } = string.Empty;
public string DisplayName { get; set; } = string.Empty;
}

View File

@@ -8,5 +8,6 @@ public class ShellViewModel
public ShellViewModel(INavigator navigator) => _navigator = navigator;
// Add code here to initialize or attach event handlers to singleton services
// Users can browse the app without authentication
// Login is available from the sidebar when needed
}

View File

@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Marechai.App.Presentation.Models;
using Marechai.App.Services;
@@ -56,14 +55,46 @@ public partial class SoundSynthsListViewModel : ObservableObject
List<SoundSynthDto> soundSynths = await _soundSynthsService.GetAllSoundSynthsAsync();
SoundSynths = new ObservableCollection<SoundSynthListItem>(soundSynths.Select(ss => new SoundSynthListItem
{
Id = ss.Id ?? 0,
Name = ss.Name ?? "Unknown",
Company = ss.Company ?? "Unknown"
})
.OrderBy(ss => ss.Company)
.ThenBy(ss => ss.Name));
// Separate special sound synths from regular ones
var specialSoundSynths = new List<SoundSynthListItem>();
var regularSoundSynths = new List<SoundSynthListItem>();
foreach(SoundSynthDto ss in soundSynths)
{
string displayName = ss.Name ?? "Unknown";
// Replace special database name
if(displayName == "DB_SOFTWARE") displayName = "Software";
var soundSynthItem = new SoundSynthListItem
{
Id = ss.Id ?? 0,
Name = displayName,
Company = ss.Company ?? "Unknown",
IsSpecial = ss.Name == "DB_SOFTWARE"
};
if(soundSynthItem.IsSpecial)
specialSoundSynths.Add(soundSynthItem);
else
regularSoundSynths.Add(soundSynthItem);
_logger.LogInformation("Sound Synth: {Name}, Company: {Company}, ID: {Id}, IsSpecial: {IsSpecial}",
displayName,
ss.Company,
ss.Id,
soundSynthItem.IsSpecial);
}
// Sort regular sound synths alphabetically by name
regularSoundSynths.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
// Add special sound synths first (Software), then regular sound synths
SoundSynths.Clear();
foreach(SoundSynthListItem ss in specialSoundSynths) SoundSynths.Add(ss);
foreach(SoundSynthListItem ss in regularSoundSynths) SoundSynths.Add(ss);
_logger.LogInformation("Successfully loaded {Count} Sound Synthesizers", SoundSynths.Count);
IsDataLoaded = true;
@@ -96,8 +127,9 @@ public partial class SoundSynthsListViewModel : ObservableObject
public class SoundSynthListItem
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string? Company { get; set; }
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string? Company { get; set; }
public bool IsSpecial { get; set; }
}
}

View File

@@ -0,0 +1,440 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using Marechai.App.Services.Authentication;
namespace Marechai.App.Presentation.ViewModels;
/// <summary>
/// ViewModel for user management page (Uberadmin only)
/// </summary>
public partial class UsersViewModel : ObservableObject
{
private readonly ApiClient _apiClient;
private readonly IJwtService _jwtService;
private readonly IStringLocalizer _localizer;
private readonly ILogger<UsersViewModel> _logger;
private readonly ITokenService _tokenService;
[ObservableProperty]
private ObservableCollection<string> _availableRoles = [];
[ObservableProperty]
private string _confirmPassword = string.Empty;
[ObservableProperty]
private string _dialogTitle = string.Empty;
[ObservableProperty]
private string _dialogType = string.Empty;
private string? _editingUserId;
[ObservableProperty]
private string _email = string.Empty;
[ObservableProperty]
private string _errorMessage = string.Empty;
[ObservableProperty]
private bool _hasError;
[ObservableProperty]
private bool _isDataLoaded;
[ObservableProperty]
private bool _isLoading;
[ObservableProperty]
private string _password = string.Empty;
[ObservableProperty]
private string _phoneNumber = string.Empty;
[ObservableProperty]
private string? _selectedRole;
[ObservableProperty]
private UserDto? _selectedUser;
[ObservableProperty]
private string _userName = string.Empty;
[ObservableProperty]
private ObservableCollection<string> _userRoles = [];
[ObservableProperty]
private ObservableCollection<UserDto> _users = [];
public UsersViewModel(ApiClient apiClient, IJwtService jwtService, ITokenService tokenService,
ILogger<UsersViewModel> logger, IStringLocalizer localizer)
{
_apiClient = apiClient;
_jwtService = jwtService;
_tokenService = tokenService;
_logger = logger;
_localizer = localizer;
LoadUsersCommand = new AsyncRelayCommand(LoadUsersAsync);
DeleteUserCommand = new AsyncRelayCommand<UserDto>(DeleteUserAsync);
OpenAddUserDialogCommand = new AsyncRelayCommand(OpenAddUserDialogAsync);
OpenEditUserDialogCommand = new AsyncRelayCommand<UserDto>(OpenEditUserDialogAsync);
OpenChangePasswordDialogCommand = new AsyncRelayCommand<UserDto>(OpenChangePasswordDialogAsync);
OpenManageRolesDialogCommand = new AsyncRelayCommand<UserDto>(OpenManageRolesDialogAsync);
SaveUserCommand = new AsyncRelayCommand(SaveUserAsync);
SavePasswordCommand = new AsyncRelayCommand(SavePasswordAsync);
AddRoleCommand = new AsyncRelayCommand(AddRoleAsync);
RemoveRoleCommand = new AsyncRelayCommand<string>(RemoveRoleAsync);
CloseDialogCommand = new RelayCommand(CloseDialog);
}
public IAsyncRelayCommand LoadUsersCommand { get; }
public IAsyncRelayCommand<UserDto> DeleteUserCommand { get; }
public IAsyncRelayCommand OpenAddUserDialogCommand { get; }
public IAsyncRelayCommand<UserDto> OpenEditUserDialogCommand { get; }
public IAsyncRelayCommand<UserDto> OpenChangePasswordDialogCommand { get; }
public IAsyncRelayCommand<UserDto> OpenManageRolesDialogCommand { get; }
public IAsyncRelayCommand SaveUserCommand { get; }
public IAsyncRelayCommand SavePasswordCommand { get; }
public IAsyncRelayCommand AddRoleCommand { get; }
public IAsyncRelayCommand<string> RemoveRoleCommand { get; }
public IRelayCommand CloseDialogCommand { get; }
/// <summary>
/// Checks if the current user is Uberadmin
/// </summary>
public bool IsUberadmin
{
get
{
string? token = _tokenService.GetToken();
IEnumerable<string>? roles = _jwtService.GetRoles(token);
return roles.Contains("Uberadmin", StringComparer.OrdinalIgnoreCase);
}
}
public event EventHandler<string>? ShowDialogRequested;
private async Task LoadUsersAsync()
{
try
{
IsLoading = true;
HasError = false;
ErrorMessage = string.Empty;
Users.Clear();
List<UserDto>? usersResponse = await _apiClient.Users.GetAsync();
if(usersResponse != null)
{
foreach(UserDto user in usersResponse) Users.Add(user);
IsDataLoaded = true;
}
}
catch(Exception ex)
{
_logger.LogError(ex, "Error loading users");
ErrorMessage = _localizer["Failed to load users. Please try again."];
HasError = true;
}
finally
{
IsLoading = false;
}
}
private async Task DeleteUserAsync(UserDto? user)
{
if(user?.Id == null) return;
try
{
await _apiClient.Users[user.Id].DeleteAsync();
await LoadUsersAsync();
}
catch(Exception ex)
{
_logger.LogError(ex, "Error deleting user");
ErrorMessage = _localizer["Failed to delete user."];
HasError = true;
}
}
private async Task OpenAddUserDialogAsync()
{
try
{
_editingUserId = null;
DialogTitle = _localizer["Add User"];
DialogType = "AddEdit";
Email = string.Empty;
UserName = string.Empty;
PhoneNumber = string.Empty;
Password = string.Empty;
ConfirmPassword = string.Empty;
ShowDialogRequested?.Invoke(this, "AddEdit");
}
catch(Exception ex)
{
_logger.LogError(ex, "Error opening add user dialog");
}
}
private async Task OpenEditUserDialogAsync(UserDto? user)
{
if(user?.Id == null) return;
try
{
_editingUserId = user.Id;
DialogTitle = _localizer["Edit User"];
DialogType = "AddEdit";
Email = user.Email ?? string.Empty;
UserName = user.UserName ?? string.Empty;
PhoneNumber = user.PhoneNumber ?? string.Empty;
Password = string.Empty;
ConfirmPassword = string.Empty;
ShowDialogRequested?.Invoke(this, "AddEdit");
}
catch(Exception ex)
{
_logger.LogError(ex, "Error opening edit user dialog");
}
}
private async Task OpenChangePasswordDialogAsync(UserDto? user)
{
if(user?.Id == null) return;
try
{
_editingUserId = user.Id;
DialogTitle = _localizer["Change Password"];
DialogType = "Password";
Password = string.Empty;
ConfirmPassword = string.Empty;
ShowDialogRequested?.Invoke(this, "Password");
}
catch(Exception ex)
{
_logger.LogError(ex, "Error opening change password dialog");
}
}
private async Task OpenManageRolesDialogAsync(UserDto? user)
{
if(user?.Id == null) return;
try
{
_editingUserId = user.Id;
DialogTitle = _localizer["Manage Roles"];
DialogType = "Roles";
// Load available roles
List<string>? rolesResponse = await _apiClient.Users.Roles.GetAsync();
AvailableRoles.Clear();
if(rolesResponse != null)
{
foreach(string role in rolesResponse)
if(!string.IsNullOrWhiteSpace(role))
AvailableRoles.Add(role);
}
_logger.LogInformation($"Loaded {AvailableRoles.Count} available roles");
// Load user's current roles
UserRoles.Clear();
if(user.Roles != null)
foreach(string role in user.Roles)
UserRoles.Add(role);
ShowDialogRequested?.Invoke(this, "Roles");
}
catch(Exception ex)
{
_logger.LogError(ex, "Error opening manage roles dialog");
}
}
private async Task SaveUserAsync()
{
try
{
if(string.IsNullOrWhiteSpace(Email) || string.IsNullOrWhiteSpace(UserName))
{
ErrorMessage = _localizer["Email and username are required."];
HasError = true;
return;
}
if(_editingUserId == null)
{
// Create new user
if(string.IsNullOrWhiteSpace(Password))
{
ErrorMessage = _localizer["Password is required for new users."];
HasError = true;
return;
}
if(Password != ConfirmPassword)
{
ErrorMessage = _localizer["Passwords do not match."];
HasError = true;
return;
}
var createRequest = new CreateUserRequest
{
Email = Email,
UserName = UserName,
PhoneNumber = PhoneNumber,
Password = Password
};
await _apiClient.Users.PostAsync(createRequest);
}
else
{
// Update existing user
var updateRequest = new UpdateUserRequest
{
Email = Email,
UserName = UserName,
PhoneNumber = PhoneNumber
};
await _apiClient.Users[_editingUserId].PutAsync(updateRequest);
}
CloseDialog();
await LoadUsersAsync();
}
catch(Exception ex)
{
_logger.LogError(ex, "Error saving user");
ErrorMessage = _localizer["Failed to save user."];
HasError = true;
}
}
private async Task SavePasswordAsync()
{
if(_editingUserId == null) return;
try
{
if(string.IsNullOrWhiteSpace(Password))
{
ErrorMessage = _localizer["Password is required."];
HasError = true;
return;
}
if(Password != ConfirmPassword)
{
ErrorMessage = _localizer["Passwords do not match."];
HasError = true;
return;
}
var changePasswordRequest = new ChangePasswordRequest
{
NewPassword = Password
};
await _apiClient.Users[_editingUserId].Password.PostAsync(changePasswordRequest);
CloseDialog();
}
catch(Exception ex)
{
_logger.LogError(ex, "Error changing password");
ErrorMessage = _localizer["Failed to change password."];
HasError = true;
}
}
private async Task AddRoleAsync()
{
if(_editingUserId == null || string.IsNullOrWhiteSpace(SelectedRole)) return;
try
{
if(UserRoles.Contains(SelectedRole))
{
ErrorMessage = _localizer["User already has this role."];
HasError = true;
return;
}
var addRoleRequest = new UserRoleRequest
{
RoleName = SelectedRole
};
await _apiClient.Users[_editingUserId].Roles.PostAsync(addRoleRequest);
UserRoles.Add(SelectedRole);
// Reload users to refresh the list
await LoadUsersAsync();
}
catch(Exception ex)
{
_logger.LogError(ex, "Error adding role");
ErrorMessage = _localizer["Failed to add role."];
HasError = true;
}
}
private async Task RemoveRoleAsync(string? role)
{
if(_editingUserId == null || string.IsNullOrWhiteSpace(role)) return;
try
{
await _apiClient.Users[_editingUserId].Roles[role].DeleteAsync();
UserRoles.Remove(role);
// Reload users to refresh the list
await LoadUsersAsync();
}
catch(Exception ex)
{
_logger.LogError(ex, "Error removing role");
ErrorMessage = _localizer["Failed to remove role."];
HasError = true;
}
}
private void CloseDialog()
{
DialogType = string.Empty;
_editingUserId = null;
Email = string.Empty;
UserName = string.Empty;
PhoneNumber = string.Empty;
Password = string.Empty;
ConfirmPassword = string.Empty;
UserRoles.Clear();
AvailableRoles.Clear();
HasError = false;
ErrorMessage = string.Empty;
}
}

View File

@@ -0,0 +1,209 @@
<?xml version="1.0"
encoding="utf-8"?>
<Page x:Class="Marechai.App.Presentation.Views.LoginPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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"
xmlns:vm="using:Marechai.App.Presentation.ViewModels"
xmlns:utu="using:Uno.Toolkit.UI"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
d:DataContext="{d:DesignInstance vm:LoginViewModel}">
<Grid utu:SafeArea.Insets="VisibleBounds">
<!-- Center content on screen -->
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center"
MaxWidth="480"
Padding="32">
<!-- Login Card with Mac OS 9 styling -->
<Border Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="2"
CornerRadius="8"
Padding="0"
Translation="0,0,16">
<Border.Shadow>
<ThemeShadow />
</Border.Shadow>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header with Mac OS 9 Title Bar Style -->
<Border Grid.Row="0"
Background="{ThemeResource AccentFillColorDefaultBrush}"
Padding="16,12"
CornerRadius="6,6,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Icon -->
<FontIcon Grid.Column="0"
Glyph="&#xE77B;"
FontSize="24"
Foreground="White"
Margin="0,0,12,0"
VerticalAlignment="Center" />
<!-- Title -->
<TextBlock Grid.Column="1"
x:Uid="LoginPage_Title"
Text="Sign In to Marechai"
Style="{StaticResource TitleTextBlockStyle}"
Foreground="White"
VerticalAlignment="Center" />
</Grid>
</Border>
<!-- Login Form Content -->
<ScrollViewer Grid.Row="1"
VerticalScrollBarVisibility="Auto">
<StackPanel Padding="32"
Spacing="24">
<!-- Welcome Message -->
<TextBlock x:Uid="LoginPage_WelcomeMessage"
Text="Welcome back! Please sign in to continue."
Style="{StaticResource BodyTextBlockStyle}"
TextWrapping="Wrap"
HorizontalAlignment="Center"
TextAlignment="Center" />
<!-- Email Input -->
<StackPanel Spacing="8">
<TextBlock x:Uid="LoginPage_EmailLabel"
Text="Email Address"
Style="{StaticResource BodyStrongTextBlockStyle}" />
<TextBox x:Name="EmailTextBox"
x:Uid="LoginPage_EmailTextBox"
Text="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="Enter your email"
InputScope="EmailSmtpAddress"
IsSpellCheckEnabled="False"
AutomationProperties.Name="Email address"
KeyDown="OnEmailKeyDown" />
</StackPanel>
<!-- Password Input -->
<StackPanel Spacing="8">
<TextBlock x:Uid="LoginPage_PasswordLabel"
Text="Password"
Style="{StaticResource BodyStrongTextBlockStyle}" />
<PasswordBox x:Name="PasswordBox"
x:Uid="LoginPage_PasswordBox"
Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="Enter your password"
AutomationProperties.Name="Password"
KeyDown="OnPasswordKeyDown" />
</StackPanel>
<!-- Error Message -->
<Border x:Name="ErrorBorder"
Background="#FFF4E6"
BorderBrush="#FFB84D"
BorderThickness="2"
CornerRadius="4"
Padding="12"
Visibility="{Binding ErrorMessage, Converter={StaticResource NullToVisibilityConverter}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Warning Icon -->
<FontIcon Grid.Column="0"
Glyph="&#xE7BA;"
Foreground="#D97706"
FontSize="20"
Margin="0,0,8,0"
VerticalAlignment="Top" />
<!-- Error Text -->
<TextBlock Grid.Column="1"
Text="{Binding ErrorMessage}"
Foreground="#92400E"
TextWrapping="Wrap"
VerticalAlignment="Center" />
<!-- Close Button -->
<Button Grid.Column="2"
Command="{Binding ClearErrorCommand}"
Background="Transparent"
BorderThickness="0"
Padding="8"
Margin="8,0,0,0"
VerticalAlignment="Center"
AutomationProperties.Name="Close error message">
<FontIcon Glyph="&#xE711;"
FontSize="12"
Foreground="#92400E" />
</Button>
</Grid>
</Border>
<!-- Login Button -->
<Button x:Name="LoginButton"
x:Uid="LoginPage_LoginButton"
Command="{Binding LoginCommand}"
IsEnabled="{Binding IsLoggingIn, Converter={StaticResource InvertBoolConverter}}"
HorizontalAlignment="Stretch"
Padding="16,12"
Style="{StaticResource AccentButtonStyle}"
AutomationProperties.Name="Sign in button">
<Button.Content>
<Grid>
<TextBlock x:Uid="LoginPage_LoginButtonText"
Text="Sign In"
Visibility="{Binding IsLoggingIn, Converter={StaticResource InvertBoolToVisibilityConverter}}" />
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
Spacing="8"
Visibility="{Binding IsLoggingIn, Converter={StaticResource BoolToVisibilityConverter}}">
<ProgressRing IsActive="True"
Width="20"
Height="20"
Foreground="White" />
<TextBlock x:Uid="LoginPage_SigningInText"
Text="Signing in..."
Foreground="White" />
</StackPanel>
</Grid>
</Button.Content>
</Button>
<!-- Additional Options -->
<StackPanel Spacing="8"
HorizontalAlignment="Center">
<HyperlinkButton x:Uid="LoginPage_ForgotPasswordLink"
Content="Forgot your password?"
HorizontalAlignment="Center"
Visibility="Collapsed" />
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center"
Spacing="4"
Visibility="Collapsed">
<TextBlock x:Uid="LoginPage_NoAccountText"
Text="Don't have an account?"
VerticalAlignment="Center" />
<HyperlinkButton x:Uid="LoginPage_SignUpLink"
Content="Sign up"
Padding="4,0" />
</StackPanel>
</StackPanel>
</StackPanel>
</ScrollViewer>
</Grid>
</Border>
</Grid>
</Grid>
</Page>

View File

@@ -0,0 +1,33 @@
using Windows.System;
using Marechai.App.Presentation.ViewModels;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
namespace Marechai.App.Presentation.Views;
public sealed partial class LoginPage : Page
{
public LoginPage() => InitializeComponent();
private void OnEmailKeyDown(object sender, KeyRoutedEventArgs e)
{
if(e.Key == VirtualKey.Enter)
{
// Move focus to password field
PasswordBox.Focus(FocusState.Keyboard);
e.Handled = true;
}
}
private void OnPasswordKeyDown(object sender, KeyRoutedEventArgs e)
{
if(e.Key == VirtualKey.Enter)
{
// Trigger login when Enter is pressed
if(DataContext is LoginViewModel viewModel && LoginButton.IsEnabled) viewModel.LoginCommand.Execute(null);
e.Handled = true;
}
}
}

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Page x:Class="Marechai.App.Presentation.Views.SettingsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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"
xmlns:vm="using:Marechai.App.Presentation.ViewModels"
xmlns:utu="using:Uno.Toolkit.UI"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid utu:SafeArea.Insets="VisibleBounds" Margin="16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Header -->
<TextBlock Grid.Row="0"
Text="{Binding Title}"
Style="{ThemeResource TitleTextBlockStyle}"
Margin="0,0,0,24"/>
<!-- Settings Content -->
<ScrollViewer Grid.Row="1"
VerticalScrollBarVisibility="Auto">
<StackPanel Spacing="24" MaxWidth="600" HorizontalAlignment="Left">
<!-- Theme Section -->
<StackPanel Spacing="8">
<TextBlock x:Uid="SettingsPage_ThemeSection_Header"
Text="Appearance"
Style="{ThemeResource SubtitleTextBlockStyle}"/>
<TextBlock x:Uid="SettingsPage_ThemeSection_Description"
Text="Select your preferred color theme"
Style="{ThemeResource BodyTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap"
Margin="0,0,0,8"/>
<!-- Brightness Theme Selector (Light/Dark/System) -->
<ComboBox x:Name="BrightnessThemeSelector"
x:Uid="SettingsPage_BrightnessThemeSelector"
Header="Brightness"
ItemsSource="{Binding AvailableThemes}"
SelectedItem="{Binding SelectedTheme, Mode=TwoWay}"
HorizontalAlignment="Stretch"
MinWidth="250"
Margin="0,0,0,12">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<!-- Color Theme Selector (Default/Windows 3.11) -->
<ComboBox x:Name="ColorThemeSelector"
x:Uid="SettingsPage_ColorThemeSelector"
Header="Color Theme"
ItemsSource="{Binding AvailableColorThemes}"
SelectedItem="{Binding SelectedColorTheme, Mode=TwoWay}"
HorizontalAlignment="Stretch"
MinWidth="250">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<!-- Placeholder for future settings sections -->
<StackPanel Spacing="8">
<TextBlock x:Uid="SettingsPage_AboutSection_Header"
Text="About"
Style="{ThemeResource SubtitleTextBlockStyle}"/>
<TextBlock x:Uid="SettingsPage_Version"
Text="Version 1.0"
Style="{ThemeResource BodyTextBlockStyle}"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"/>
</StackPanel>
</StackPanel>
</ScrollViewer>
</Grid>
</Page>

View File

@@ -0,0 +1,14 @@
using Marechai.App.Presentation.ViewModels;
using Microsoft.UI.Xaml.Controls;
namespace Marechai.App.Presentation.Views;
public sealed partial class SettingsPage : Page
{
public SettingsPage()
{
InitializeComponent();
}
public SettingsViewModel? ViewModel => DataContext as SettingsViewModel;
}

View File

@@ -0,0 +1,184 @@
<?xml version="1.0"
encoding="utf-8"?>
<Page x:Class="Marechai.App.Presentation.Views.UsersPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.UI.Controls"
x:Name="PageRoot"
NavigationCacheMode="Required"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Header with Title -->
<Grid Grid.Row="0"
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource DividerStrokeColorDefaultBrush}"
BorderThickness="0,0,0,1"
Padding="16,12">
<!-- Page Title -->
<StackPanel VerticalAlignment="Center">
<TextBlock Text="User Management"
FontSize="20"
FontWeight="SemiBold"
Foreground="{ThemeResource TextControlForeground}" />
<TextBlock Text="Manage users, roles, and permissions"
FontSize="12"
Foreground="{ThemeResource SystemBaseMediumColor}"
Margin="0,4,0,0" />
</StackPanel>
</Grid>
<!-- Main Content -->
<Grid Grid.Row="1">
<!-- Access Denied Message -->
<StackPanel Visibility="{Binding IsUberadmin, Converter={StaticResource InvertBoolToVisibilityConverter}}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Padding="24"
Spacing="16"
MaxWidth="400">
<InfoBar IsOpen="True"
Severity="Warning"
Title="Access Denied"
Message="You must be an Uberadmin to access user management."
IsClosable="False" />
</StackPanel>
<!-- Content (only visible to Uberadmin) -->
<Grid Visibility="{Binding IsUberadmin, Converter={StaticResource BoolToVisibilityConverter}}"
Canvas.ZIndex="0">
<!-- Loading State -->
<StackPanel Visibility="{Binding IsLoading, Converter={StaticResource BoolToVisibilityConverter}}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Padding="32"
Spacing="16">
<ProgressRing IsActive="True"
IsIndeterminate="True"
Height="64"
Width="64"
Foreground="{ThemeResource SystemAccentColor}" />
<TextBlock Text="Loading users..."
FontSize="14"
TextAlignment="Center"
Foreground="{ThemeResource SystemBaseMediumColor}" />
</StackPanel>
<!-- Error State -->
<StackPanel Visibility="{Binding HasError, Converter={StaticResource BoolToVisibilityConverter}}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Padding="24"
Spacing="16"
MaxWidth="400"
Canvas.ZIndex="100">
<InfoBar IsOpen="True"
Severity="Error"
Title="Unable to Load Users"
Message="{Binding ErrorMessage}"
IsClosable="False" />
<Button Content="Retry"
Command="{Binding LoadUsersCommand}"
HorizontalAlignment="Center"
Style="{ThemeResource AccentButtonStyle}" />
</StackPanel>
<!-- Users DataGrid -->
<Grid Visibility="{Binding IsDataLoaded, Converter={StaticResource BoolToVisibilityConverter}}"
Canvas.ZIndex="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Command Bar -->
<CommandBar Grid.Row="0"
DefaultLabelPosition="Right">
<AppBarButton Icon="Add"
Label="Add User"
Command="{Binding OpenAddUserDialogCommand}" />
<AppBarButton Icon="Refresh"
Label="Refresh"
Command="{Binding LoadUsersCommand}" />
</CommandBar>
<!-- DataGrid -->
<controls:DataGrid Grid.Row="1"
Margin="16"
ItemsSource="{Binding Users}"
SelectedItem="{Binding SelectedUser, Mode=TwoWay}"
AutoGenerateColumns="False"
GridLinesVisibility="None"
HeadersVisibility="Column"
AlternatingRowBackground="{ThemeResource CardBackgroundFillColorSecondaryBrush}"
CanUserReorderColumns="True"
CanUserResizeColumns="True"
CanUserSortColumns="True"
IsReadOnly="True"
SelectionMode="Single"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<controls:DataGrid.Columns>
<controls:DataGridTextColumn Header="Email"
Binding="{Binding Email}"
Width="2*" />
<controls:DataGridTextColumn Header="Username"
Binding="{Binding UserName}"
Width="*" />
<controls:DataGridTextColumn Header="Phone"
Binding="{Binding PhoneNumber}"
Width="*" />
<controls:DataGridTextColumn Header="Roles"
Width="2*"
Binding="{Binding Roles, Converter={StaticResource RolesListConverter}}" />
<controls:DataGridTemplateColumn Header="Actions"
Width="Auto">
<controls:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
Spacing="4">
<Button Content="Edit"
Command="{Binding DataContext.OpenEditUserDialogCommand, ElementName=PageRoot}"
CommandParameter="{Binding}"
Style="{ThemeResource TextBlockButtonStyle}"
Padding="8,4" />
<Button Content="Password"
Command="{Binding DataContext.OpenChangePasswordDialogCommand, ElementName=PageRoot}"
CommandParameter="{Binding}"
Style="{ThemeResource TextBlockButtonStyle}"
Padding="8,4" />
<Button Content="Roles"
Command="{Binding DataContext.OpenManageRolesDialogCommand, ElementName=PageRoot}"
CommandParameter="{Binding}"
Style="{ThemeResource TextBlockButtonStyle}"
Padding="8,4" />
<Button Content="Delete"
Command="{Binding DataContext.DeleteUserCommand, ElementName=PageRoot}"
CommandParameter="{Binding}"
Foreground="{ThemeResource SystemErrorTextColor}"
Style="{ThemeResource TextBlockButtonStyle}"
Padding="8,4" />
</StackPanel>
</DataTemplate>
</controls:DataGridTemplateColumn.CellTemplate>
</controls:DataGridTemplateColumn>
</controls:DataGrid.Columns>
</controls:DataGrid>
</Grid>
</Grid>
</Grid>
</Grid>
</Page>

View File

@@ -0,0 +1,394 @@
using System;
using System.Diagnostics;
using Marechai.App.Presentation.ViewModels;
using Microsoft.UI;
using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
namespace Marechai.App.Presentation.Views;
/// <summary>
/// User management page for Uberadmins
/// </summary>
public sealed partial class UsersPage : Page
{
private ContentDialog? _currentOpenDialog;
private UsersViewModel? _currentViewModel;
public UsersPage()
{
InitializeComponent();
Loaded += UsersPage_Loaded;
DataContextChanged += UsersPage_DataContextChanged;
}
private void UsersPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
// Unsubscribe from previous ViewModel
if(_currentViewModel != null) _currentViewModel.ShowDialogRequested -= OnShowDialogRequested;
// Subscribe to new ViewModel
if(DataContext is UsersViewModel vm)
{
_currentViewModel = vm;
vm.ShowDialogRequested += OnShowDialogRequested;
if(vm.IsUberadmin)
{
// Load data when DataContext is set and user is Uberadmin
vm.LoadUsersCommand.Execute(null);
}
}
}
private void UsersPage_Loaded(object sender, RoutedEventArgs e)
{
if(DataContext is UsersViewModel vm && vm.IsUberadmin)
{
// Load data when page is loaded (fallback)
vm.LoadUsersCommand.Execute(null);
}
}
private async void OnShowDialogRequested(object? sender, string dialogType)
{
// Close any currently open dialog first
if(_currentOpenDialog != null)
{
_currentOpenDialog.Hide();
_currentOpenDialog = null;
}
if(DataContext is not UsersViewModel vm) return;
ContentDialog? dialog = null;
switch(dialogType)
{
case "AddEdit":
{
var emailBox = new TextBox
{
Header = "Email",
Text = vm.Email
};
emailBox.TextChanged += (s, e) => vm.Email = emailBox.Text;
var userNameBox = new TextBox
{
Header = "Username",
Text = vm.UserName
};
userNameBox.TextChanged += (s, e) => vm.UserName = userNameBox.Text;
var phoneBox = new TextBox
{
Header = "Phone Number",
Text = vm.PhoneNumber
};
phoneBox.TextChanged += (s, e) => vm.PhoneNumber = phoneBox.Text;
var passwordBox = new PasswordBox
{
Header = "Password",
Password = vm.Password,
PlaceholderText = "Leave blank to keep current (when editing)"
};
passwordBox.PasswordChanged += (s, e) => vm.Password = passwordBox.Password;
var confirmPasswordBox = new PasswordBox
{
Header = "Confirm Password",
Password = vm.ConfirmPassword
};
confirmPasswordBox.PasswordChanged += (s, e) => vm.ConfirmPassword = confirmPasswordBox.Password;
dialog = new ContentDialog
{
XamlRoot = XamlRoot,
Title = vm.DialogTitle,
PrimaryButtonText = "Save",
CloseButtonText = "Cancel",
PrimaryButtonCommand = vm.SaveUserCommand,
CloseButtonCommand = vm.CloseDialogCommand,
DefaultButton = ContentDialogButton.Primary,
Content = new StackPanel
{
Spacing = 12,
MinWidth = 400,
Children =
{
emailBox,
userNameBox,
phoneBox,
passwordBox,
confirmPasswordBox
}
}
};
}
break;
case "Password":
{
var passwordBox = new PasswordBox
{
Header = "New Password",
Password = vm.Password
};
passwordBox.PasswordChanged += (s, e) => vm.Password = passwordBox.Password;
var confirmPasswordBox = new PasswordBox
{
Header = "Confirm Password",
Password = vm.ConfirmPassword
};
confirmPasswordBox.PasswordChanged += (s, e) => vm.ConfirmPassword = confirmPasswordBox.Password;
dialog = new ContentDialog
{
XamlRoot = XamlRoot,
Title = vm.DialogTitle,
PrimaryButtonText = "Change Password",
CloseButtonText = "Cancel",
PrimaryButtonCommand = vm.SavePasswordCommand,
CloseButtonCommand = vm.CloseDialogCommand,
DefaultButton = ContentDialogButton.Primary,
Content = new StackPanel
{
Spacing = 12,
MinWidth = 400,
Children =
{
passwordBox,
confirmPasswordBox
}
}
};
}
break;
case "Roles":
{
Debug.WriteLine($"Creating Roles dialog. Available roles count: {vm.AvailableRoles.Count}");
foreach(string role in vm.AvailableRoles) Debug.WriteLine($" - Role: {role}");
var rolesContent = new Grid
{
RowSpacing = 16,
MinWidth = 450
};
rolesContent.RowDefinitions.Add(new RowDefinition
{
Height = GridLength.Auto
});
rolesContent.RowDefinitions.Add(new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
});
var addRolePanel = new StackPanel
{
Spacing = 8
};
addRolePanel.Children.Add(new TextBlock
{
Text = "Add Role",
FontWeight = FontWeights.SemiBold
});
var addRoleGrid = new Grid
{
ColumnSpacing = 8
};
addRoleGrid.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Star)
});
addRoleGrid.ColumnDefinitions.Add(new ColumnDefinition
{
Width = GridLength.Auto
});
// Use ListView with SingleSelection instead of ComboBox - ComboBox has issues with programmatic creation
var roleListView = new ListView
{
SelectionMode = ListViewSelectionMode.Single,
HorizontalAlignment = HorizontalAlignment.Stretch,
MaxHeight = 200,
MinWidth = 300
};
Debug.WriteLine($"Creating ListView for role selection with {vm.AvailableRoles.Count} roles");
// Populate the ListView
foreach(string role in vm.AvailableRoles)
{
var item = new ListViewItem
{
Content = role
};
roleListView.Items.Add(item);
Debug.WriteLine($" Added role to ListView: {role}");
}
Debug.WriteLine($"ListView Items.Count: {roleListView.Items.Count}");
roleListView.SelectionChanged += (s, e) =>
{
if(roleListView.SelectedItem is ListViewItem selectedItem &&
selectedItem.Content is string selectedRole)
{
vm.SelectedRole = selectedRole;
Debug.WriteLine($"Selected role from ListView: {selectedRole}");
}
};
Grid.SetColumn(roleListView, 0);
addRoleGrid.Children.Add(roleListView);
var addButton = new Button
{
Content = "Add",
Command = vm.AddRoleCommand
};
Grid.SetColumn(addButton, 1);
addRoleGrid.Children.Add(addButton);
addRolePanel.Children.Add(addRoleGrid);
Grid.SetRow(addRolePanel, 0);
rolesContent.Children.Add(addRolePanel);
var currentRolesPanel = new StackPanel
{
Spacing = 8,
Margin = new Thickness(0, 8, 0, 0)
};
currentRolesPanel.Children.Add(new TextBlock
{
Text = "Current Roles",
FontWeight = FontWeights.SemiBold
});
// Create a StackPanel to display roles dynamically
var rolesStack = new StackPanel
{
Spacing = 4
};
// Handler to refresh the roles list
void UpdateRolesList()
{
rolesStack.Children.Clear();
foreach(string role in vm.UserRoles)
{
var roleItem = new Grid
{
ColumnSpacing = 8,
Margin = new Thickness(0, 4, 0, 4)
};
roleItem.ColumnDefinitions.Add(new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Star)
});
roleItem.ColumnDefinitions.Add(new ColumnDefinition
{
Width = GridLength.Auto
});
var roleText = new TextBlock
{
Text = role,
VerticalAlignment = VerticalAlignment.Center
};
Grid.SetColumn(roleText, 0);
roleItem.Children.Add(roleText);
var removeButton = new Button
{
Content = "Remove",
Foreground = new SolidColorBrush(Colors.Red),
CommandParameter = role
};
removeButton.Click += (s, e) =>
{
var btn = s as Button;
var roleToRemove = btn?.CommandParameter as string;
if(roleToRemove != null && vm.RemoveRoleCommand.CanExecute(roleToRemove))
{
vm.RemoveRoleCommand.Execute(roleToRemove);
UpdateRolesList();
}
};
Grid.SetColumn(removeButton, 1);
roleItem.Children.Add(removeButton);
rolesStack.Children.Add(roleItem);
}
}
// Listen to collection changes
vm.UserRoles.CollectionChanged += (s, e) => UpdateRolesList();
// Initial population
UpdateRolesList();
var scrollViewer = new ScrollViewer
{
MaxHeight = 200,
Content = rolesStack
};
currentRolesPanel.Children.Add(scrollViewer);
Grid.SetRow(currentRolesPanel, 1);
rolesContent.Children.Add(currentRolesPanel);
dialog = new ContentDialog
{
XamlRoot = XamlRoot,
Title = vm.DialogTitle,
CloseButtonText = "Close",
CloseButtonCommand = vm.CloseDialogCommand,
DefaultButton = ContentDialogButton.Close,
Content = rolesContent
};
}
break;
}
if(dialog != null)
{
_currentOpenDialog = dialog;
await dialog.ShowAsync();
_currentOpenDialog = null;
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Kiota.Abstractions;
using Uno.Extensions;
using Uno.Extensions.Authentication;
namespace Marechai.App.Services.Authentication;
public sealed class AuthService
(ApiClient client, ITokenService tokenService, IStringLocalizer stringLocalizer) : IAuthenticationService
{
/// <inheritdoc />
public async ValueTask<bool> LoginAsync(IDispatcher? dispatcher, IDictionary<string, string>? credentials = null,
string? provider = null, CancellationToken? cancellationToken = null)
{
if(credentials is null) return false;
string? email =
(credentials.FirstOrDefault(x => x.Key.Equals("Email", StringComparison.OrdinalIgnoreCase)).Value ??
credentials.FirstOrDefault(x => x.Key.Equals("email", StringComparison.OrdinalIgnoreCase)).Value ??
credentials.FirstOrDefault(x => x.Key.Equals("Username", StringComparison.OrdinalIgnoreCase)).Value)
?.Trim();
string? password =
(credentials.FirstOrDefault(x => x.Key.Equals("Password", StringComparison.OrdinalIgnoreCase)).Value ??
credentials.FirstOrDefault(x => x.Key.Equals("password", StringComparison.OrdinalIgnoreCase)).Value)
?.Trim();
if(string.IsNullOrWhiteSpace(email))
{
credentials["error"] = stringLocalizer["Auth.EmailIsRequired"];
return false;
}
if(string.IsNullOrWhiteSpace(password))
{
credentials["error"] = stringLocalizer["Auth.PasswordIsRequired"];
return false;
}
var loginModel = new AuthRequest
{
Email = email,
Password = password
};
AuthResponse? authResponse;
try
{
tokenService.RemoveToken();
authResponse = await client.Auth.Login.PostAsync(loginModel);
}
catch(ProblemDetails ex)
{
if(ex.Status == 400)
credentials["error"] = ex.Detail ?? ex.Title ?? stringLocalizer["Http.BadRequest"];
else if(ex.Status == 401)
credentials["error"] = stringLocalizer["Auth.InvalidCredentials"];
else
credentials["error"] = ex.Detail ?? ex.Title ?? stringLocalizer["Http.BadRequest"];
return false;
}
catch(ApiException ex)
{
if(ex.ResponseStatusCode == 401)
credentials["error"] = stringLocalizer["Auth.InvalidCredentials"];
else if(ex.ResponseStatusCode == 400)
credentials["error"] = stringLocalizer["Http.BadRequest"];
else
credentials["error"] = ex.Message ?? stringLocalizer["Http.BadRequest"];
return false;
}
catch(Exception ex)
{
#pragma warning disable EPC12
credentials["error"] = ex.Message;
#pragma warning restore EPC12
return false;
}
if(string.IsNullOrWhiteSpace(authResponse?.Token)) return false;
tokenService.SetToken(authResponse.Token);
return true;
}
/// <inheritdoc />
public ValueTask<bool> RefreshAsync(CancellationToken? cancellationToken = null) =>
IsAuthenticated(cancellationToken);
/// <inheritdoc />
public async ValueTask<bool> LogoutAsync(IDispatcher? dispatcher, CancellationToken? cancellationToken = null)
{
tokenService.RemoveToken();
LoggedOut?.Invoke(this, EventArgs.Empty);
return true;
}
/// <inheritdoc />
public async ValueTask<bool> IsAuthenticated(CancellationToken? cancellationToken = null)
{
string token = tokenService.GetToken();
// TODO: Check token validity
return !string.IsNullOrWhiteSpace(token);
}
/// <inheritdoc />
public string[] Providers { get; } = [];
/// <inheritdoc />
public event EventHandler? LoggedOut;
}

View File

@@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
namespace Marechai.App.Services.Authentication;
public interface IJwtService
{
IEnumerable<string> GetRoles(string token);
string? GetUserId(string token);
string? GetUserName(string token);
string? GetEmail(string token);
bool IsTokenValid(string token);
}
public sealed class JwtService : IJwtService
{
/// <inheritdoc />
public IEnumerable<string> GetRoles(string token)
{
if(string.IsNullOrWhiteSpace(token)) return [];
try
{
var handler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtToken = handler.ReadJwtToken(token);
return jwtToken.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value).ToList();
}
catch
{
return [];
}
}
/// <inheritdoc />
public string? GetUserId(string token)
{
if(string.IsNullOrWhiteSpace(token)) return null;
try
{
var handler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtToken = handler.ReadJwtToken(token);
return jwtToken.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Sid)?.Value;
}
catch
{
return null;
}
}
/// <inheritdoc />
public string? GetUserName(string token)
{
if(string.IsNullOrWhiteSpace(token)) return null;
try
{
var handler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtToken = handler.ReadJwtToken(token);
return jwtToken.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value;
}
catch
{
return null;
}
}
/// <inheritdoc />
public string? GetEmail(string token)
{
if(string.IsNullOrWhiteSpace(token)) return null;
try
{
var handler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtToken = handler.ReadJwtToken(token);
return jwtToken.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)?.Value;
}
catch
{
return null;
}
}
/// <inheritdoc />
public bool IsTokenValid(string token)
{
if(string.IsNullOrWhiteSpace(token)) return false;
try
{
var handler = new JwtSecurityTokenHandler();
JwtSecurityToken jwtToken = handler.ReadJwtToken(token);
// Check if token has expired (if expiration is set)
if(jwtToken.ValidTo != DateTime.MinValue) return jwtToken.ValidTo > DateTime.UtcNow;
return true;
}
catch
{
return false;
}
}
}

View File

@@ -0,0 +1,32 @@
using Windows.Storage;
namespace Marechai.App.Services.Authentication;
public interface ITokenService
{
string GetToken();
void RemoveToken();
void SetToken(string token);
}
public sealed class TokenService : ITokenService
{
readonly ApplicationDataContainer _settings = ApplicationData.Current.LocalSettings;
/// <inheritdoc />
public string GetToken() => (string)_settings.Values["token"];
/// <inheritdoc />
public void RemoveToken()
{
_settings.Values.Remove("token");
}
/// <inheritdoc />
public void SetToken(string token)
{
_settings.Values["token"] = token;
}
}

View File

@@ -41,6 +41,7 @@ using Marechai.App.Software;
using Marechai.App.SoundSynths;
using Marechai.App.SoundSynthsByMachine;
using Marechai.App.StorageByMachine;
using Marechai.App.Users;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Serialization.Form;
@@ -264,6 +265,11 @@ namespace Marechai.App
{
get => new global::Marechai.App.StorageByMachine.StorageByMachineRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>The users property</summary>
public global::Marechai.App.Users.UsersRequestBuilder Users
{
get => new global::Marechai.App.Users.UsersRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.ApiClient"/> and sets the default values.
/// </summary>

View File

@@ -0,0 +1,198 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Gpus.Item.Machines;
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.Gpus.Item
{
/// <summary>
/// Builds and executes requests for operations under \gpus\{gpu-id}
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class GpuItemRequestBuilder : BaseRequestBuilder
{
/// <summary>The machines property</summary>
public global::Marechai.App.Gpus.Item.Machines.MachinesRequestBuilder Machines
{
get => new global::Marechai.App.Gpus.Item.Machines.MachinesRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Gpus.Item.GpuItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public GpuItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/gpus/{gpu%2Did}", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Gpus.Item.GpuItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public GpuItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/gpus/{gpu%2Did}", rawUrl)
{
}
/// <returns>A <see cref="string"/></returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<string?> DeleteAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<string> DeleteAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToDeleteRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
return await RequestAdapter.SendPrimitiveAsync<string>(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="global::Marechai.App.Models.GpuDto"/></returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<global::Marechai.App.Models.GpuDto?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<global::Marechai.App.Models.GpuDto> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToGetRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
return await RequestAdapter.SendAsync<global::Marechai.App.Models.GpuDto>(requestInfo, global::Marechai.App.Models.GpuDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="string"/></returns>
/// <param name="body">The request body</param>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<string?> PutAsync(global::Marechai.App.Models.GpuDto body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<string> PutAsync(global::Marechai.App.Models.GpuDto body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = ToPutRequestInformation(body, requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
return await RequestAdapter.SendPrimitiveAsync<string>(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToDeleteRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToDeleteRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json, text/plain;q=0.9");
return requestInfo;
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json, text/plain;q=0.9");
return requestInfo;
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="body">The request body</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToPutRequestInformation(global::Marechai.App.Models.GpuDto body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToPutRequestInformation(global::Marechai.App.Models.GpuDto body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = new RequestInformation(Method.PUT, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json, text/plain;q=0.9");
requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body);
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Gpus.Item.GpuItemRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.Gpus.Item.GpuItemRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.Gpus.Item.GpuItemRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class GpuItemRequestBuilderDeleteRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class GpuItemRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class GpuItemRequestBuilderPutRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,92 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.Gpus.Item.Machines
{
/// <summary>
/// Builds and executes requests for operations under \gpus\{gpu-id}\machines
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class MachinesRequestBuilder : BaseRequestBuilder
{
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Gpus.Item.Machines.MachinesRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public MachinesRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/gpus/{gpu%2Did}/machines", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Gpus.Item.Machines.MachinesRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public MachinesRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/gpus/{gpu%2Did}/machines", rawUrl)
{
}
/// <returns>A List&lt;global::Marechai.App.Models.MachineDto&gt;</returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<List<global::Marechai.App.Models.MachineDto>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<List<global::Marechai.App.Models.MachineDto>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToGetRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
var collectionResult = await RequestAdapter.SendCollectionAsync<global::Marechai.App.Models.MachineDto>(requestInfo, global::Marechai.App.Models.MachineDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
return collectionResult?.AsList();
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Gpus.Item.Machines.MachinesRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.Gpus.Item.Machines.MachinesRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.Gpus.Item.Machines.MachinesRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class MachinesRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,65 @@
// <auto-generated/>
#pragma warning disable CS0618
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using System.Collections.Generic;
using System.IO;
using System;
namespace Marechai.App.Models
{
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
#pragma warning disable CS1591
public partial class ChangePasswordRequest : IAdditionalDataHolder, IParsable
#pragma warning restore CS1591
{
/// <summary>Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.</summary>
public IDictionary<string, object> AdditionalData { get; set; }
/// <summary>The newPassword property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? NewPassword { get; set; }
#nullable restore
#else
public string NewPassword { get; set; }
#endif
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Models.ChangePasswordRequest"/> and sets the default values.
/// </summary>
public ChangePasswordRequest()
{
AdditionalData = new Dictionary<string, object>();
}
/// <summary>
/// Creates a new instance of the appropriate class based on discriminator value
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Models.ChangePasswordRequest"/></returns>
/// <param name="parseNode">The parse node to use to read the discriminator value and create the object</param>
public static global::Marechai.App.Models.ChangePasswordRequest CreateFromDiscriminatorValue(IParseNode parseNode)
{
if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode));
return new global::Marechai.App.Models.ChangePasswordRequest();
}
/// <summary>
/// The deserialization information for the current model
/// </summary>
/// <returns>A IDictionary&lt;string, Action&lt;IParseNode&gt;&gt;</returns>
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
{
return new Dictionary<string, Action<IParseNode>>
{
{ "newPassword", n => { NewPassword = n.GetStringValue(); } },
};
}
/// <summary>
/// Serializes information the current object
/// </summary>
/// <param name="writer">Serialization writer to use to serialize this model</param>
public virtual void Serialize(ISerializationWriter writer)
{
if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer));
writer.WriteStringValue("newPassword", NewPassword);
writer.WriteAdditionalData(AdditionalData);
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,95 @@
// <auto-generated/>
#pragma warning disable CS0618
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using System.Collections.Generic;
using System.IO;
using System;
namespace Marechai.App.Models
{
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
#pragma warning disable CS1591
public partial class CreateUserRequest : IAdditionalDataHolder, IParsable
#pragma warning restore CS1591
{
/// <summary>Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.</summary>
public IDictionary<string, object> AdditionalData { get; set; }
/// <summary>The email property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? Email { get; set; }
#nullable restore
#else
public string Email { get; set; }
#endif
/// <summary>The password property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? Password { get; set; }
#nullable restore
#else
public string Password { get; set; }
#endif
/// <summary>The phoneNumber property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? PhoneNumber { get; set; }
#nullable restore
#else
public string PhoneNumber { get; set; }
#endif
/// <summary>The userName property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? UserName { get; set; }
#nullable restore
#else
public string UserName { get; set; }
#endif
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Models.CreateUserRequest"/> and sets the default values.
/// </summary>
public CreateUserRequest()
{
AdditionalData = new Dictionary<string, object>();
}
/// <summary>
/// Creates a new instance of the appropriate class based on discriminator value
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Models.CreateUserRequest"/></returns>
/// <param name="parseNode">The parse node to use to read the discriminator value and create the object</param>
public static global::Marechai.App.Models.CreateUserRequest CreateFromDiscriminatorValue(IParseNode parseNode)
{
if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode));
return new global::Marechai.App.Models.CreateUserRequest();
}
/// <summary>
/// The deserialization information for the current model
/// </summary>
/// <returns>A IDictionary&lt;string, Action&lt;IParseNode&gt;&gt;</returns>
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
{
return new Dictionary<string, Action<IParseNode>>
{
{ "email", n => { Email = n.GetStringValue(); } },
{ "password", n => { Password = n.GetStringValue(); } },
{ "phoneNumber", n => { PhoneNumber = n.GetStringValue(); } },
{ "userName", n => { UserName = n.GetStringValue(); } },
};
}
/// <summary>
/// Serializes information the current object
/// </summary>
/// <param name="writer">Serialization writer to use to serialize this model</param>
public virtual void Serialize(ISerializationWriter writer)
{
if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer));
writer.WriteStringValue("email", Email);
writer.WriteStringValue("password", Password);
writer.WriteStringValue("phoneNumber", PhoneNumber);
writer.WriteStringValue("userName", UserName);
writer.WriteAdditionalData(AdditionalData);
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,93 @@
// <auto-generated/>
#pragma warning disable CS0618
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using System.Collections.Generic;
using System.IO;
using System;
namespace Marechai.App.Models
{
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
#pragma warning disable CS1591
public partial class UpdateUserRequest : IAdditionalDataHolder, IParsable
#pragma warning restore CS1591
{
/// <summary>Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.</summary>
public IDictionary<string, object> AdditionalData { get; set; }
/// <summary>The email property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? Email { get; set; }
#nullable restore
#else
public string Email { get; set; }
#endif
/// <summary>The emailConfirmed property</summary>
public bool? EmailConfirmed { get; set; }
/// <summary>The lockoutEnabled property</summary>
public bool? LockoutEnabled { get; set; }
/// <summary>The phoneNumber property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? PhoneNumber { get; set; }
#nullable restore
#else
public string PhoneNumber { get; set; }
#endif
/// <summary>The userName property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? UserName { get; set; }
#nullable restore
#else
public string UserName { get; set; }
#endif
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Models.UpdateUserRequest"/> and sets the default values.
/// </summary>
public UpdateUserRequest()
{
AdditionalData = new Dictionary<string, object>();
}
/// <summary>
/// Creates a new instance of the appropriate class based on discriminator value
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Models.UpdateUserRequest"/></returns>
/// <param name="parseNode">The parse node to use to read the discriminator value and create the object</param>
public static global::Marechai.App.Models.UpdateUserRequest CreateFromDiscriminatorValue(IParseNode parseNode)
{
if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode));
return new global::Marechai.App.Models.UpdateUserRequest();
}
/// <summary>
/// The deserialization information for the current model
/// </summary>
/// <returns>A IDictionary&lt;string, Action&lt;IParseNode&gt;&gt;</returns>
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
{
return new Dictionary<string, Action<IParseNode>>
{
{ "email", n => { Email = n.GetStringValue(); } },
{ "emailConfirmed", n => { EmailConfirmed = n.GetBoolValue(); } },
{ "lockoutEnabled", n => { LockoutEnabled = n.GetBoolValue(); } },
{ "phoneNumber", n => { PhoneNumber = n.GetStringValue(); } },
{ "userName", n => { UserName = n.GetStringValue(); } },
};
}
/// <summary>
/// Serializes information the current object
/// </summary>
/// <param name="writer">Serialization writer to use to serialize this model</param>
public virtual void Serialize(ISerializationWriter writer)
{
if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer));
writer.WriteStringValue("email", Email);
writer.WriteBoolValue("emailConfirmed", EmailConfirmed);
writer.WriteBoolValue("lockoutEnabled", LockoutEnabled);
writer.WriteStringValue("phoneNumber", PhoneNumber);
writer.WriteStringValue("userName", UserName);
writer.WriteAdditionalData(AdditionalData);
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,131 @@
// <auto-generated/>
#pragma warning disable CS0618
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using System.Collections.Generic;
using System.IO;
using System;
namespace Marechai.App.Models
{
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
#pragma warning disable CS1591
public partial class UserDto : IAdditionalDataHolder, IParsable
#pragma warning restore CS1591
{
/// <summary>The accessFailedCount property</summary>
public int? AccessFailedCount { get; set; }
/// <summary>Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.</summary>
public IDictionary<string, object> AdditionalData { get; set; }
/// <summary>The email property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? Email { get; set; }
#nullable restore
#else
public string Email { get; set; }
#endif
/// <summary>The emailConfirmed property</summary>
public bool? EmailConfirmed { get; set; }
/// <summary>The id property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? Id { get; set; }
#nullable restore
#else
public string Id { get; set; }
#endif
/// <summary>The lockoutEnabled property</summary>
public bool? LockoutEnabled { get; set; }
/// <summary>The lockoutEnd property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? LockoutEnd { get; set; }
#nullable restore
#else
public string LockoutEnd { get; set; }
#endif
/// <summary>The phoneNumber property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? PhoneNumber { get; set; }
#nullable restore
#else
public string PhoneNumber { get; set; }
#endif
/// <summary>The phoneNumberConfirmed property</summary>
public bool? PhoneNumberConfirmed { get; set; }
/// <summary>The roles property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public List<string>? Roles { get; set; }
#nullable restore
#else
public List<string> Roles { get; set; }
#endif
/// <summary>The userName property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? UserName { get; set; }
#nullable restore
#else
public string UserName { get; set; }
#endif
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Models.UserDto"/> and sets the default values.
/// </summary>
public UserDto()
{
AdditionalData = new Dictionary<string, object>();
}
/// <summary>
/// Creates a new instance of the appropriate class based on discriminator value
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Models.UserDto"/></returns>
/// <param name="parseNode">The parse node to use to read the discriminator value and create the object</param>
public static global::Marechai.App.Models.UserDto CreateFromDiscriminatorValue(IParseNode parseNode)
{
if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode));
return new global::Marechai.App.Models.UserDto();
}
/// <summary>
/// The deserialization information for the current model
/// </summary>
/// <returns>A IDictionary&lt;string, Action&lt;IParseNode&gt;&gt;</returns>
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
{
return new Dictionary<string, Action<IParseNode>>
{
{ "accessFailedCount", n => { AccessFailedCount = n.GetIntValue(); } },
{ "email", n => { Email = n.GetStringValue(); } },
{ "emailConfirmed", n => { EmailConfirmed = n.GetBoolValue(); } },
{ "id", n => { Id = n.GetStringValue(); } },
{ "lockoutEnabled", n => { LockoutEnabled = n.GetBoolValue(); } },
{ "lockoutEnd", n => { LockoutEnd = n.GetStringValue(); } },
{ "phoneNumber", n => { PhoneNumber = n.GetStringValue(); } },
{ "phoneNumberConfirmed", n => { PhoneNumberConfirmed = n.GetBoolValue(); } },
{ "roles", n => { Roles = n.GetCollectionOfPrimitiveValues<string>()?.AsList(); } },
{ "userName", n => { UserName = n.GetStringValue(); } },
};
}
/// <summary>
/// Serializes information the current object
/// </summary>
/// <param name="writer">Serialization writer to use to serialize this model</param>
public virtual void Serialize(ISerializationWriter writer)
{
if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer));
writer.WriteIntValue("accessFailedCount", AccessFailedCount);
writer.WriteStringValue("email", Email);
writer.WriteBoolValue("emailConfirmed", EmailConfirmed);
writer.WriteStringValue("id", Id);
writer.WriteBoolValue("lockoutEnabled", LockoutEnabled);
writer.WriteStringValue("lockoutEnd", LockoutEnd);
writer.WriteStringValue("phoneNumber", PhoneNumber);
writer.WriteBoolValue("phoneNumberConfirmed", PhoneNumberConfirmed);
writer.WriteCollectionOfPrimitiveValues<string>("roles", Roles);
writer.WriteStringValue("userName", UserName);
writer.WriteAdditionalData(AdditionalData);
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,65 @@
// <auto-generated/>
#pragma warning disable CS0618
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using System.Collections.Generic;
using System.IO;
using System;
namespace Marechai.App.Models
{
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
#pragma warning disable CS1591
public partial class UserRoleRequest : IAdditionalDataHolder, IParsable
#pragma warning restore CS1591
{
/// <summary>Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.</summary>
public IDictionary<string, object> AdditionalData { get; set; }
/// <summary>The roleName property</summary>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public string? RoleName { get; set; }
#nullable restore
#else
public string RoleName { get; set; }
#endif
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Models.UserRoleRequest"/> and sets the default values.
/// </summary>
public UserRoleRequest()
{
AdditionalData = new Dictionary<string, object>();
}
/// <summary>
/// Creates a new instance of the appropriate class based on discriminator value
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Models.UserRoleRequest"/></returns>
/// <param name="parseNode">The parse node to use to read the discriminator value and create the object</param>
public static global::Marechai.App.Models.UserRoleRequest CreateFromDiscriminatorValue(IParseNode parseNode)
{
if(ReferenceEquals(parseNode, null)) throw new ArgumentNullException(nameof(parseNode));
return new global::Marechai.App.Models.UserRoleRequest();
}
/// <summary>
/// The deserialization information for the current model
/// </summary>
/// <returns>A IDictionary&lt;string, Action&lt;IParseNode&gt;&gt;</returns>
public virtual IDictionary<string, Action<IParseNode>> GetFieldDeserializers()
{
return new Dictionary<string, Action<IParseNode>>
{
{ "roleName", n => { RoleName = n.GetStringValue(); } },
};
}
/// <summary>
/// Serializes information the current object
/// </summary>
/// <param name="writer">Serialization writer to use to serialize this model</param>
public virtual void Serialize(ISerializationWriter writer)
{
if(ReferenceEquals(writer, null)) throw new ArgumentNullException(nameof(writer));
writer.WriteStringValue("roleName", RoleName);
writer.WriteAdditionalData(AdditionalData);
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,61 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.ProcessorsByMachine.ByProcessor.Item;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System;
namespace Marechai.App.ProcessorsByMachine.ByProcessor
{
/// <summary>
/// Builds and executes requests for operations under \processors-by-machine\by-processor
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class ByProcessorRequestBuilder : BaseRequestBuilder
{
/// <summary>Gets an item from the Marechai.App.processorsByMachine.byProcessor.item collection</summary>
/// <param name="position">Unique identifier of the item</param>
/// <returns>A <see cref="global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder"/></returns>
public global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder this[int position]
{
get
{
var urlTplParams = new Dictionary<string, object>(PathParameters);
urlTplParams.Add("processorId", position);
return new global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder(urlTplParams, RequestAdapter);
}
}
/// <summary>Gets an item from the Marechai.App.processorsByMachine.byProcessor.item collection</summary>
/// <param name="position">Unique identifier of the item</param>
/// <returns>A <see cref="global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder"/></returns>
[Obsolete("This indexer is deprecated and will be removed in the next major version. Use the one with the typed parameter instead.")]
public global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder this[string position]
{
get
{
var urlTplParams = new Dictionary<string, object>(PathParameters);
if (!string.IsNullOrWhiteSpace(position)) urlTplParams.Add("processorId", position);
return new global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder(urlTplParams, RequestAdapter);
}
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.ProcessorsByMachine.ByProcessor.ByProcessorRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public ByProcessorRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/processors-by-machine/by-processor", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.ProcessorsByMachine.ByProcessor.ByProcessorRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public ByProcessorRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/processors-by-machine/by-processor", rawUrl)
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,92 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.ProcessorsByMachine.ByProcessor.Item
{
/// <summary>
/// Builds and executes requests for operations under \processors-by-machine\by-processor\{processorId}
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class WithProcessorItemRequestBuilder : BaseRequestBuilder
{
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public WithProcessorItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/processors-by-machine/by-processor/{processorId}", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public WithProcessorItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/processors-by-machine/by-processor/{processorId}", rawUrl)
{
}
/// <returns>A List&lt;global::Marechai.App.Models.ProcessorByMachineDto&gt;</returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<List<global::Marechai.App.Models.ProcessorByMachineDto>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<List<global::Marechai.App.Models.ProcessorByMachineDto>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToGetRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
var collectionResult = await RequestAdapter.SendCollectionAsync<global::Marechai.App.Models.ProcessorByMachineDto>(requestInfo, global::Marechai.App.Models.ProcessorByMachineDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
return collectionResult?.AsList();
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.ProcessorsByMachine.ByProcessor.Item.WithProcessorItemRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class WithProcessorItemRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,41 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.ResolutionsByGpu.Gpus.Item.Resolutions;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System;
namespace Marechai.App.ResolutionsByGpu.Gpus.Item
{
/// <summary>
/// Builds and executes requests for operations under \resolutions-by-gpu\gpus\{gpuId}
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class WithGpuItemRequestBuilder : BaseRequestBuilder
{
/// <summary>The resolutions property</summary>
public global::Marechai.App.ResolutionsByGpu.Gpus.Item.Resolutions.ResolutionsRequestBuilder Resolutions
{
get => new global::Marechai.App.ResolutionsByGpu.Gpus.Item.Resolutions.ResolutionsRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.ResolutionsByGpu.Gpus.Item.WithGpuItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public WithGpuItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/resolutions-by-gpu/gpus/{gpuId}", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.ResolutionsByGpu.Gpus.Item.WithGpuItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public WithGpuItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/resolutions-by-gpu/gpus/{gpuId}", rawUrl)
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,61 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.SoundSynthsByMachine.BySoundSynth.Item;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System;
namespace Marechai.App.SoundSynthsByMachine.BySoundSynth
{
/// <summary>
/// Builds and executes requests for operations under \sound-synths-by-machine\by-sound-synth
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class BySoundSynthRequestBuilder : BaseRequestBuilder
{
/// <summary>Gets an item from the Marechai.App.soundSynthsByMachine.bySoundSynth.item collection</summary>
/// <param name="position">Unique identifier of the item</param>
/// <returns>A <see cref="global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder"/></returns>
public global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder this[int position]
{
get
{
var urlTplParams = new Dictionary<string, object>(PathParameters);
urlTplParams.Add("soundSynthId", position);
return new global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder(urlTplParams, RequestAdapter);
}
}
/// <summary>Gets an item from the Marechai.App.soundSynthsByMachine.bySoundSynth.item collection</summary>
/// <param name="position">Unique identifier of the item</param>
/// <returns>A <see cref="global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder"/></returns>
[Obsolete("This indexer is deprecated and will be removed in the next major version. Use the one with the typed parameter instead.")]
public global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder this[string position]
{
get
{
var urlTplParams = new Dictionary<string, object>(PathParameters);
if (!string.IsNullOrWhiteSpace(position)) urlTplParams.Add("soundSynthId", position);
return new global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder(urlTplParams, RequestAdapter);
}
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.SoundSynthsByMachine.BySoundSynth.BySoundSynthRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public BySoundSynthRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/sound-synths-by-machine/by-sound-synth", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.SoundSynthsByMachine.BySoundSynth.BySoundSynthRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public BySoundSynthRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/sound-synths-by-machine/by-sound-synth", rawUrl)
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,92 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.SoundSynthsByMachine.BySoundSynth.Item
{
/// <summary>
/// Builds and executes requests for operations under \sound-synths-by-machine\by-sound-synth\{soundSynthId}
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class WithSoundSynthItemRequestBuilder : BaseRequestBuilder
{
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public WithSoundSynthItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/sound-synths-by-machine/by-sound-synth/{soundSynthId}", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public WithSoundSynthItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/sound-synths-by-machine/by-sound-synth/{soundSynthId}", rawUrl)
{
}
/// <returns>A List&lt;global::Marechai.App.Models.SoundSynthByMachineDto&gt;</returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<List<global::Marechai.App.Models.SoundSynthByMachineDto>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<List<global::Marechai.App.Models.SoundSynthByMachineDto>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToGetRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
var collectionResult = await RequestAdapter.SendCollectionAsync<global::Marechai.App.Models.SoundSynthByMachineDto>(requestInfo, global::Marechai.App.Models.SoundSynthByMachineDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
return collectionResult?.AsList();
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "text/plain;q=0.9");
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.SoundSynthsByMachine.BySoundSynth.Item.WithSoundSynthItemRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class WithSoundSynthItemRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,101 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.Users.Item.Password
{
/// <summary>
/// Builds and executes requests for operations under \users\{id}\password
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class PasswordRequestBuilder : BaseRequestBuilder
{
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Item.Password.PasswordRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public PasswordRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/{id}/password", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Item.Password.PasswordRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public PasswordRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/{id}/password", rawUrl)
{
}
/// <param name="body">The request body</param>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 403 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task PostAsync(global::Marechai.App.Models.ChangePasswordRequest body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task PostAsync(global::Marechai.App.Models.ChangePasswordRequest body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = ToPostRequestInformation(body, requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "403", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
await RequestAdapter.SendNoContentAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="body">The request body</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToPostRequestInformation(global::Marechai.App.Models.ChangePasswordRequest body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToPostRequestInformation(global::Marechai.App.Models.ChangePasswordRequest body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json, text/plain;q=0.9");
requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body);
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Users.Item.Password.PasswordRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.Users.Item.Password.PasswordRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.Users.Item.Password.PasswordRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class PasswordRequestBuilderPostRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,96 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.Users.Item.Roles.Item
{
/// <summary>
/// Builds and executes requests for operations under \users\{id}\roles\{roleName}
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class WithRoleNameItemRequestBuilder : BaseRequestBuilder
{
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Item.Roles.Item.WithRoleNameItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public WithRoleNameItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/{id}/roles/{roleName}", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Item.Roles.Item.WithRoleNameItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public WithRoleNameItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/{id}/roles/{roleName}", rawUrl)
{
}
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 403 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task DeleteAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task DeleteAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToDeleteRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "403", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
await RequestAdapter.SendNoContentAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToDeleteRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToDeleteRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json, text/plain;q=0.9");
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Users.Item.Roles.Item.WithRoleNameItemRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.Users.Item.Roles.Item.WithRoleNameItemRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.Users.Item.Roles.Item.WithRoleNameItemRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class WithRoleNameItemRequestBuilderDeleteRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,114 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Marechai.App.Users.Item.Roles.Item;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.Users.Item.Roles
{
/// <summary>
/// Builds and executes requests for operations under \users\{id}\roles
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class RolesRequestBuilder : BaseRequestBuilder
{
/// <summary>Gets an item from the Marechai.App.users.item.roles.item collection</summary>
/// <param name="position">Unique identifier of the item</param>
/// <returns>A <see cref="global::Marechai.App.Users.Item.Roles.Item.WithRoleNameItemRequestBuilder"/></returns>
public global::Marechai.App.Users.Item.Roles.Item.WithRoleNameItemRequestBuilder this[string position]
{
get
{
var urlTplParams = new Dictionary<string, object>(PathParameters);
urlTplParams.Add("roleName", position);
return new global::Marechai.App.Users.Item.Roles.Item.WithRoleNameItemRequestBuilder(urlTplParams, RequestAdapter);
}
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Item.Roles.RolesRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public RolesRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/{id}/roles", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Item.Roles.RolesRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public RolesRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/{id}/roles", rawUrl)
{
}
/// <param name="body">The request body</param>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 403 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task PostAsync(global::Marechai.App.Models.UserRoleRequest body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task PostAsync(global::Marechai.App.Models.UserRoleRequest body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = ToPostRequestInformation(body, requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "403", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
await RequestAdapter.SendNoContentAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="body">The request body</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToPostRequestInformation(global::Marechai.App.Models.UserRoleRequest body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToPostRequestInformation(global::Marechai.App.Models.UserRoleRequest body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json, text/plain;q=0.9");
requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body);
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Users.Item.Roles.RolesRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.Users.Item.Roles.RolesRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.Users.Item.Roles.RolesRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class RolesRequestBuilderPostRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,209 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Marechai.App.Users.Item.Password;
using Marechai.App.Users.Item.Roles;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.Users.Item
{
/// <summary>
/// Builds and executes requests for operations under \users\{id}
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class UsersItemRequestBuilder : BaseRequestBuilder
{
/// <summary>The password property</summary>
public global::Marechai.App.Users.Item.Password.PasswordRequestBuilder Password
{
get => new global::Marechai.App.Users.Item.Password.PasswordRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>The roles property</summary>
public global::Marechai.App.Users.Item.Roles.RolesRequestBuilder Roles
{
get => new global::Marechai.App.Users.Item.Roles.RolesRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Item.UsersItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public UsersItemRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/{id}", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Item.UsersItemRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public UsersItemRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/{id}", rawUrl)
{
}
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 403 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task DeleteAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task DeleteAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToDeleteRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "403", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
await RequestAdapter.SendNoContentAsync(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="global::Marechai.App.Models.UserDto"/></returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 403 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<global::Marechai.App.Models.UserDto?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<global::Marechai.App.Models.UserDto> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToGetRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "403", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
return await RequestAdapter.SendAsync<global::Marechai.App.Models.UserDto>(requestInfo, global::Marechai.App.Models.UserDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="global::Marechai.App.Models.UserDto"/></returns>
/// <param name="body">The request body</param>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 403 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 404 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<global::Marechai.App.Models.UserDto?> PutAsync(global::Marechai.App.Models.UpdateUserRequest body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<global::Marechai.App.Models.UserDto> PutAsync(global::Marechai.App.Models.UpdateUserRequest body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = ToPutRequestInformation(body, requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "403", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "404", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
return await RequestAdapter.SendAsync<global::Marechai.App.Models.UserDto>(requestInfo, global::Marechai.App.Models.UserDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToDeleteRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToDeleteRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.DELETE, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json, text/plain;q=0.9");
return requestInfo;
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json");
return requestInfo;
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="body">The request body</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToPutRequestInformation(global::Marechai.App.Models.UpdateUserRequest body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToPutRequestInformation(global::Marechai.App.Models.UpdateUserRequest body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = new RequestInformation(Method.PUT, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json");
requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body);
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Users.Item.UsersItemRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.Users.Item.UsersItemRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.Users.Item.UsersItemRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class UsersItemRequestBuilderDeleteRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class UsersItemRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class UsersItemRequestBuilderPutRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,94 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.Users.Roles
{
/// <summary>
/// Builds and executes requests for operations under \users\roles
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class RolesRequestBuilder : BaseRequestBuilder
{
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Roles.RolesRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public RolesRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/roles", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.Roles.RolesRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public RolesRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users/roles", rawUrl)
{
}
/// <returns>A List&lt;string&gt;</returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 403 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<List<string>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<List<string>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToGetRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "403", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
var collectionResult = await RequestAdapter.SendPrimitiveCollectionAsync<string>(requestInfo, errorMapping, cancellationToken).ConfigureAwait(false);
return collectionResult?.AsList();
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json");
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Users.Roles.RolesRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.Users.Roles.RolesRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.Users.Roles.RolesRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class RolesRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -0,0 +1,166 @@
// <auto-generated/>
#pragma warning disable CS0618
using Marechai.App.Models;
using Marechai.App.Users.Item;
using Marechai.App.Users.Roles;
using Microsoft.Kiota.Abstractions.Extensions;
using Microsoft.Kiota.Abstractions.Serialization;
using Microsoft.Kiota.Abstractions;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;
using System;
namespace Marechai.App.Users
{
/// <summary>
/// Builds and executes requests for operations under \users
/// </summary>
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class UsersRequestBuilder : BaseRequestBuilder
{
/// <summary>The roles property</summary>
public global::Marechai.App.Users.Roles.RolesRequestBuilder Roles
{
get => new global::Marechai.App.Users.Roles.RolesRequestBuilder(PathParameters, RequestAdapter);
}
/// <summary>Gets an item from the Marechai.App.users.item collection</summary>
/// <param name="position">Unique identifier of the item</param>
/// <returns>A <see cref="global::Marechai.App.Users.Item.UsersItemRequestBuilder"/></returns>
public global::Marechai.App.Users.Item.UsersItemRequestBuilder this[string position]
{
get
{
var urlTplParams = new Dictionary<string, object>(PathParameters);
urlTplParams.Add("id", position);
return new global::Marechai.App.Users.Item.UsersItemRequestBuilder(urlTplParams, RequestAdapter);
}
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.UsersRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="pathParameters">Path parameters for the request</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public UsersRequestBuilder(Dictionary<string, object> pathParameters, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users", pathParameters)
{
}
/// <summary>
/// Instantiates a new <see cref="global::Marechai.App.Users.UsersRequestBuilder"/> and sets the default values.
/// </summary>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
/// <param name="requestAdapter">The request adapter to use to execute the requests.</param>
public UsersRequestBuilder(string rawUrl, IRequestAdapter requestAdapter) : base(requestAdapter, "{+baseurl}/users", rawUrl)
{
}
/// <returns>A List&lt;global::Marechai.App.Models.UserDto&gt;</returns>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 403 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<List<global::Marechai.App.Models.UserDto>?> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<List<global::Marechai.App.Models.UserDto>> GetAsync(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
var requestInfo = ToGetRequestInformation(requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "403", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
var collectionResult = await RequestAdapter.SendCollectionAsync<global::Marechai.App.Models.UserDto>(requestInfo, global::Marechai.App.Models.UserDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
return collectionResult?.AsList();
}
/// <returns>A <see cref="global::Marechai.App.Models.UserDto"/></returns>
/// <param name="body">The request body</param>
/// <param name="cancellationToken">Cancellation token to use when cancelling requests</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 400 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 401 status code</exception>
/// <exception cref="global::Marechai.App.Models.ProblemDetails">When receiving a 403 status code</exception>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public async Task<global::Marechai.App.Models.UserDto?> PostAsync(global::Marechai.App.Models.CreateUserRequest body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default, CancellationToken cancellationToken = default)
{
#nullable restore
#else
public async Task<global::Marechai.App.Models.UserDto> PostAsync(global::Marechai.App.Models.CreateUserRequest body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default, CancellationToken cancellationToken = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = ToPostRequestInformation(body, requestConfiguration);
var errorMapping = new Dictionary<string, ParsableFactory<IParsable>>
{
{ "400", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "401", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
{ "403", global::Marechai.App.Models.ProblemDetails.CreateFromDiscriminatorValue },
};
return await RequestAdapter.SendAsync<global::Marechai.App.Models.UserDto>(requestInfo, global::Marechai.App.Models.UserDto.CreateFromDiscriminatorValue, errorMapping, cancellationToken).ConfigureAwait(false);
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToGetRequestInformation(Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
var requestInfo = new RequestInformation(Method.GET, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json");
return requestInfo;
}
/// <returns>A <see cref="RequestInformation"/></returns>
/// <param name="body">The request body</param>
/// <param name="requestConfiguration">Configuration for the request such as headers, query parameters, and middleware options.</param>
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
#nullable enable
public RequestInformation ToPostRequestInformation(global::Marechai.App.Models.CreateUserRequest body, Action<RequestConfiguration<DefaultQueryParameters>>? requestConfiguration = default)
{
#nullable restore
#else
public RequestInformation ToPostRequestInformation(global::Marechai.App.Models.CreateUserRequest body, Action<RequestConfiguration<DefaultQueryParameters>> requestConfiguration = default)
{
#endif
if(ReferenceEquals(body, null)) throw new ArgumentNullException(nameof(body));
var requestInfo = new RequestInformation(Method.POST, UrlTemplate, PathParameters);
requestInfo.Configure(requestConfiguration);
requestInfo.Headers.TryAdd("Accept", "application/json");
requestInfo.SetContentFromParsable(RequestAdapter, "application/json", body);
return requestInfo;
}
/// <summary>
/// Returns a request builder with the provided arbitrary URL. Using this method means any other path or query parameters are ignored.
/// </summary>
/// <returns>A <see cref="global::Marechai.App.Users.UsersRequestBuilder"/></returns>
/// <param name="rawUrl">The raw URL to use for the request builder.</param>
public global::Marechai.App.Users.UsersRequestBuilder WithUrl(string rawUrl)
{
return new global::Marechai.App.Users.UsersRequestBuilder(rawUrl, RequestAdapter);
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class UsersRequestBuilderGetRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
/// <summary>
/// Configuration for the request such as headers, query parameters, and middleware options.
/// </summary>
[Obsolete("This class is deprecated. Please use the generic RequestConfiguration class generated by the generator.")]
[global::System.CodeDom.Compiler.GeneratedCode("Kiota", "1.0.0")]
public partial class UsersRequestBuilderPostRequestConfiguration : RequestConfiguration<DefaultQueryParameters>
{
}
}
}
#pragma warning restore CS0618

View File

@@ -1,34 +1,34 @@
{
"descriptionHash": "C3420A48BBEE846A2606007719F2CB672783E54BFC6264E374C4EE4E7983D3F3D8505882D01625FF9C5A4C3A861D92FB482DCC66804B3CA76FD67E8E10717E5D",
"descriptionLocation": "http://localhost:5023/openapi/v1.json",
"lockFileVersion": "1.0.0",
"kiotaVersion": "1.29.0",
"clientClassName": "ApiClient",
"typeAccessModifier": "Public",
"clientNamespaceName": "Marechai.App",
"language": "CSharp",
"usesBackingStore": false,
"descriptionHash": "1F12C3D431E5804DE0610670BB6E3F6E813834C2AE2B82DDD54DF72B577E977AEA2FF00FC1C309AD40E33BE29228A8A5E988A7997CD2C75EFBB900C28190FAE3",
"descriptionLocation": "http://localhost:5023/openapi/v1.json",
"lockFileVersion": "1.0.0",
"kiotaVersion": "1.29.0",
"clientClassName": "ApiClient",
"typeAccessModifier": "Public",
"clientNamespaceName": "Marechai.App",
"language": "CSharp",
"usesBackingStore": false,
"excludeBackwardCompatible": false,
"includeAdditionalData": true,
"disableSSLValidation": false,
"serializers": [
"includeAdditionalData": true,
"disableSSLValidation": false,
"serializers": [
"Microsoft.Kiota.Serialization.Json.JsonSerializationWriterFactory",
"Microsoft.Kiota.Serialization.Text.TextSerializationWriterFactory",
"Microsoft.Kiota.Serialization.Form.FormSerializationWriterFactory",
"Microsoft.Kiota.Serialization.Multipart.MultipartSerializationWriterFactory"
],
"deserializers": [
"deserializers": [
"Microsoft.Kiota.Serialization.Json.JsonParseNodeFactory",
"Microsoft.Kiota.Serialization.Text.TextParseNodeFactory",
"Microsoft.Kiota.Serialization.Form.FormParseNodeFactory"
],
"structuredMimeTypes": [
"structuredMimeTypes": [
"application/json",
"text/plain;q=0.9",
"application/x-www-form-urlencoded;q=0.2",
"multipart/form-data;q=0.1"
],
"includePatterns": [],
"excludePatterns": [],
"disabledValidationRules": []
"includePatterns": [],
"excludePatterns": [],
"disabledValidationRules": []
}

View File

@@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Windows.Storage;
using Microsoft.UI.Xaml;
using Uno.Extensions.Toolkit;
namespace Marechai.App.Services;
public interface IColorThemeService
{
string CurrentColorTheme { get; }
IReadOnlyList<string> AvailableColorThemes { get; }
void ApplyColorTheme(string themeName);
void SetThemeService(IThemeService themeService);
void ReapplyCurrentTheme();
}
public class ColorThemeService : IColorThemeService
{
private const string COLOR_THEME_KEY = "ColorTheme";
private const string DEFAULT_THEME = "Default";
private IThemeService _themeService;
public ColorThemeService()
{
LoadSavedTheme();
}
public string CurrentColorTheme { get; private set; } = DEFAULT_THEME;
public IReadOnlyList<string> AvailableColorThemes => new List<string>
{
DEFAULT_THEME,
"Windows311",
"MacOS9",
"DOS",
"Amiga",
"CDE"
};
public void SetThemeService(IThemeService themeService)
{
_themeService = themeService;
// Reapply the current theme now that we have the theme service
if(CurrentColorTheme != DEFAULT_THEME) ReapplyCurrentTheme();
}
public void ReapplyCurrentTheme()
{
// Force refresh of the current theme
ApplyColorTheme(CurrentColorTheme);
}
public void ApplyColorTheme(string themeName)
{
if(!AvailableColorThemes.Contains(themeName)) return;
CurrentColorTheme = themeName;
// Save preference
try
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
localSettings.Values[COLOR_THEME_KEY] = themeName;
}
catch
{
// Silently fail
}
// Apply the theme by rebuilding merged dictionaries
Application app = Application.Current;
if(app?.Resources == null) return;
// Store the existing merged dictionaries (except color overrides)
var existingDictionaries = app.Resources.MergedDictionaries
.Where(d => d.Source?.OriginalString?.Contains("ColorPalette") != true)
.ToList();
// Clear all merged dictionaries
app.Resources.MergedDictionaries.Clear();
// Re-add the existing dictionaries
foreach(ResourceDictionary dict in existingDictionaries) app.Resources.MergedDictionaries.Add(dict);
// Add the new color theme if not default
if(themeName != DEFAULT_THEME)
{
string themeFile = themeName switch
{
"Windows311" => "ms-appx:///Styles/Win311ColorPalette.xaml",
"MacOS9" => "ms-appx:///Styles/MacOS9ColorPalette.xaml",
"DOS" => "ms-appx:///Styles/DOSColorPalette.xaml",
"Amiga" => "ms-appx:///Styles/AmigaColorPalette.xaml",
"CDE" => "ms-appx:///Styles/CDEColorPalette.xaml",
_ => null
};
if(themeFile != null)
{
var newDictionary = new ResourceDictionary
{
Source = new Uri(themeFile)
};
app.Resources.MergedDictionaries.Add(newDictionary);
}
}
// Force UI refresh by toggling the theme temporarily
ForceThemeRefresh();
}
private void LoadSavedTheme()
{
try
{
ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
if(localSettings.Values.ContainsKey(COLOR_THEME_KEY))
{
var savedTheme = localSettings.Values[COLOR_THEME_KEY] as string;
if(!string.IsNullOrEmpty(savedTheme) && AvailableColorThemes.Contains(savedTheme))
{
CurrentColorTheme = savedTheme;
ApplyColorTheme(CurrentColorTheme);
}
}
}
catch
{
// If loading fails, use default theme
}
}
private async void ForceThemeRefresh()
{
if(_themeService == null) return;
try
{
// Get current theme
AppTheme currentTheme = _themeService.Theme;
// Toggle to opposite theme briefly
AppTheme tempTheme = currentTheme == AppTheme.Light ? AppTheme.Dark : AppTheme.Light;
await _themeService.SetThemeAsync(tempTheme);
// Small delay to ensure the change is applied
await Task.Delay(50);
// Switch back to original theme
await _themeService.SetThemeAsync(currentTheme);
}
catch
{
// Silently fail
}
}
}

View File

@@ -0,0 +1,22 @@
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Marechai.App.Services.Authentication;
namespace Marechai.App.Services.Endpoints;
public sealed class HttpAuthHandler(ITokenService tokenService) : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
string token = tokenService.GetToken();
if(!string.IsNullOrEmpty(token)) request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
return response;
}
}

View File

@@ -166,4 +166,109 @@
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
<value>Company was renamed on an unknown date to an unknown name.</value>
</data>
<data name="SettingsPage_ThemeSection_Header.Text" xml:space="preserve">
<value>Appearance</value>
</data>
<data name="SettingsPage_ThemeSection_Description.Text" xml:space="preserve">
<value>Select your preferred theme</value>
</data>
<data name="SettingsPage_ThemeSelector.Header" xml:space="preserve">
<value>Theme</value>
</data>
<data name="SettingsPage_ThemeChange_Notice.Text" xml:space="preserve">
<value>Theme changes will be applied the next time you start the application.</value>
</data>
<data name="SettingsPage_AboutSection_Header.Text" xml:space="preserve">
<value>About</value>
</data>
<data name="SettingsPage_Version.Text" xml:space="preserve">
<value>Version 1.0</value>
</data>
<data name="LightTheme" xml:space="preserve">
<value>Light</value>
</data>
<data name="DarkTheme" xml:space="preserve">
<value>Dark</value>
</data>
<data name="SystemTheme" xml:space="preserve">
<value>System</value>
</data>
<data name="DefaultColorTheme" xml:space="preserve">
<value>Default</value>
</data>
<data name="Windows311Theme" xml:space="preserve">
<value>Windows 3.11</value>
</data>
<data name="MacOS9Theme" xml:space="preserve">
<value>Mac OS 9</value>
</data>
<data name="DOSTheme" xml:space="preserve">
<value>DOS / Turbo Vision</value>
</data>
<data name="AmigaTheme" xml:space="preserve">
<value>Amiga Workbench</value>
</data>
<data name="CDETheme" xml:space="preserve">
<value>CDE / Motif</value>
</data>
<data name="SettingsPage_BrightnessThemeSelector.Header" xml:space="preserve">
<value>Brightness</value>
</data>
<data name="SettingsPage_ColorThemeSelector.Header" xml:space="preserve">
<value>Color Theme</value>
</data>
<data name="SettingsPage_DesignSystemSelector.Header" xml:space="preserve">
<value>Design System</value>
</data>
<data name="SettingsPage_DesignSystemChange_Notice.Text" xml:space="preserve">
<value>Design system changes will be applied the next time you start the application. Color theme changes are applied immediately.</value>
</data>
<!-- Login Page -->
<data name="LoginPage_Title.Text" xml:space="preserve">
<value>Sign In to Marechai</value>
</data>
<data name="LoginPage_WelcomeMessage.Text" xml:space="preserve">
<value>Welcome back! Please sign in to continue.</value>
</data>
<data name="LoginPage_EmailLabel.Text" xml:space="preserve">
<value>Email Address</value>
</data>
<data name="LoginPage_EmailTextBox.PlaceholderText" xml:space="preserve">
<value>Enter your email</value>
</data>
<data name="LoginPage_PasswordLabel.Text" xml:space="preserve">
<value>Password</value>
</data>
<data name="LoginPage_PasswordBox.PlaceholderText" xml:space="preserve">
<value>Enter your password</value>
</data>
<data name="LoginPage_LoginButton.Content" xml:space="preserve">
<value>Sign In</value>
</data>
<data name="LoginPage_LoginButtonText.Text" xml:space="preserve">
<value>Sign In</value>
</data>
<data name="LoginPage_SigningInText.Text" xml:space="preserve">
<value>Signing in...</value>
</data>
<data name="LoginPage_ForgotPasswordLink.Content" xml:space="preserve">
<value>Forgot your password?</value>
</data>
<data name="LoginPage_NoAccountText.Text" xml:space="preserve">
<value>Don't have an account?</value>
</data>
<data name="LoginPage_SignUpLink.Content" xml:space="preserve">
<value>Sign up</value>
</data>
<data name="LoginPage.Error.EmailRequired" xml:space="preserve">
<value>Email address is required.</value>
</data>
<data name="LoginPage.Error.PasswordRequired" xml:space="preserve">
<value>Password is required.</value>
</data>
<data name="LoginPage.Error.LoginFailed" xml:space="preserve">
<value>Login failed. Please check your credentials and try again.</value>
</data>
</root>

View File

@@ -166,4 +166,109 @@
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
<value>La empresa fue renombrada en una fecha desconocida a un nombre desconocido.</value>
</data>
<data name="SettingsPage_ThemeSection_Header.Text" xml:space="preserve">
<value>Apariencia</value>
</data>
<data name="SettingsPage_ThemeSection_Description.Text" xml:space="preserve">
<value>Seleccione su tema preferido</value>
</data>
<data name="SettingsPage_ThemeSelector.Header" xml:space="preserve">
<value>Tema</value>
</data>
<data name="SettingsPage_ThemeChange_Notice.Text" xml:space="preserve">
<value>Los cambios de tema se aplicarán la próxima vez que inicie la aplicación.</value>
</data>
<data name="SettingsPage_AboutSection_Header.Text" xml:space="preserve">
<value>Acerca de</value>
</data>
<data name="SettingsPage_Version.Text" xml:space="preserve">
<value>Versión 1.0</value>
</data>
<data name="LightTheme" xml:space="preserve">
<value>Claro</value>
</data>
<data name="DarkTheme" xml:space="preserve">
<value>Oscuro</value>
</data>
<data name="SystemTheme" xml:space="preserve">
<value>Sistema</value>
</data>
<data name="DefaultColorTheme" xml:space="preserve">
<value>Predeterminado</value>
</data>
<data name="Windows311Theme" xml:space="preserve">
<value>Windows 3.11</value>
</data>
<data name="MacOS9Theme" xml:space="preserve">
<value>Mac OS 9</value>
</data>
<data name="DOSTheme" xml:space="preserve">
<value>DOS / Turbo Vision</value>
</data>
<data name="AmigaTheme" xml:space="preserve">
<value>Amiga Workbench</value>
</data>
<data name="CDETheme" xml:space="preserve">
<value>CDE / Motif</value>
</data>
<data name="SettingsPage_BrightnessThemeSelector.Header" xml:space="preserve">
<value>Brillo</value>
</data>
<data name="SettingsPage_ColorThemeSelector.Header" xml:space="preserve">
<value>Tema de Color</value>
</data>
<data name="SettingsPage_DesignSystemSelector.Header" xml:space="preserve">
<value>Sistema de Diseño</value>
</data>
<data name="SettingsPage_DesignSystemChange_Notice.Text" xml:space="preserve">
<value>Los cambios del sistema de diseño se aplicarán la próxima vez que inicie la aplicación. Los cambios de tema de color se aplican inmediatamente.</value>
</data>
<!-- Login Page -->
<data name="LoginPage_Title.Text" xml:space="preserve">
<value>Iniciar Sesión en Marechai</value>
</data>
<data name="LoginPage_WelcomeMessage.Text" xml:space="preserve">
<value>¡Bienvenido de nuevo! Por favor, inicia sesión para continuar.</value>
</data>
<data name="LoginPage_EmailLabel.Text" xml:space="preserve">
<value>Dirección de Correo Electrónico</value>
</data>
<data name="LoginPage_EmailTextBox.PlaceholderText" xml:space="preserve">
<value>Ingrese su correo electrónico</value>
</data>
<data name="LoginPage_PasswordLabel.Text" xml:space="preserve">
<value>Contraseña</value>
</data>
<data name="LoginPage_PasswordBox.PlaceholderText" xml:space="preserve">
<value>Ingrese su contraseña</value>
</data>
<data name="LoginPage_LoginButton.Content" xml:space="preserve">
<value>Iniciar Sesión</value>
</data>
<data name="LoginPage_LoginButtonText.Text" xml:space="preserve">
<value>Iniciar Sesión</value>
</data>
<data name="LoginPage_SigningInText.Text" xml:space="preserve">
<value>Iniciando sesión...</value>
</data>
<data name="LoginPage_ForgotPasswordLink.Content" xml:space="preserve">
<value>¿Olvidó su contraseña?</value>
</data>
<data name="LoginPage_NoAccountText.Text" xml:space="preserve">
<value>¿No tiene una cuenta?</value>
</data>
<data name="LoginPage_SignUpLink.Content" xml:space="preserve">
<value>Registrarse</value>
</data>
<data name="LoginPage.Error.EmailRequired" xml:space="preserve">
<value>La dirección de correo electrónico es obligatoria.</value>
</data>
<data name="LoginPage.Error.PasswordRequired" xml:space="preserve">
<value>La contraseña es obligatoria.</value>
</data>
<data name="LoginPage.Error.LoginFailed" xml:space="preserve">
<value>Error al iniciar sesión. Por favor, verifique sus credenciales e intente nuevamente.</value>
</data>
</root>

View File

@@ -166,4 +166,109 @@
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
<value>L'entreprise a été renommée à une date inconnue en un nom inconnu.</value>
</data>
<data name="SettingsPage_ThemeSection_Header.Text" xml:space="preserve">
<value>Apparence</value>
</data>
<data name="SettingsPage_ThemeSection_Description.Text" xml:space="preserve">
<value>Sélectionnez votre thème préféré</value>
</data>
<data name="SettingsPage_ThemeSelector.Header" xml:space="preserve">
<value>Thème</value>
</data>
<data name="SettingsPage_ThemeChange_Notice.Text" xml:space="preserve">
<value>Les modifications du thème seront appliquées au prochain démarrage de l'application.</value>
</data>
<data name="SettingsPage_AboutSection_Header.Text" xml:space="preserve">
<value>À propos</value>
</data>
<data name="SettingsPage_Version.Text" xml:space="preserve">
<value>Version 1.0</value>
</data>
<data name="LightTheme" xml:space="preserve">
<value>Clair</value>
</data>
<data name="DarkTheme" xml:space="preserve">
<value>Sombre</value>
</data>
<data name="SystemTheme" xml:space="preserve">
<value>Système</value>
</data>
<data name="DefaultColorTheme" xml:space="preserve">
<value>Par défaut</value>
</data>
<data name="Windows311Theme" xml:space="preserve">
<value>Windows 3.11</value>
</data>
<data name="MacOS9Theme" xml:space="preserve">
<value>Mac OS 9</value>
</data>
<data name="DOSTheme" xml:space="preserve">
<value>DOS / Turbo Vision</value>
</data>
<data name="AmigaTheme" xml:space="preserve">
<value>Amiga Workbench</value>
</data>
<data name="CDETheme" xml:space="preserve">
<value>CDE / Motif</value>
</data>
<data name="SettingsPage_BrightnessThemeSelector.Header" xml:space="preserve">
<value>Luminosité</value>
</data>
<data name="SettingsPage_ColorThemeSelector.Header" xml:space="preserve">
<value>Thème de Couleur</value>
</data>
<data name="SettingsPage_DesignSystemSelector.Header" xml:space="preserve">
<value>Système de Conception</value>
</data>
<data name="SettingsPage_DesignSystemChange_Notice.Text" xml:space="preserve">
<value>Les modifications du système de conception seront appliquées la prochaine fois que vous démarrerez l'application. Les modifications du thème de couleur sont appliquées immédiatement.</value>
</data>
<!-- Login Page -->
<data name="LoginPage_Title.Text" xml:space="preserve">
<value>Se Connecter à Marechai</value>
</data>
<data name="LoginPage_WelcomeMessage.Text" xml:space="preserve">
<value>Bienvenue ! Veuillez vous connecter pour continuer.</value>
</data>
<data name="LoginPage_EmailLabel.Text" xml:space="preserve">
<value>Adresse E-mail</value>
</data>
<data name="LoginPage_EmailTextBox.PlaceholderText" xml:space="preserve">
<value>Entrez votre e-mail</value>
</data>
<data name="LoginPage_PasswordLabel.Text" xml:space="preserve">
<value>Mot de Passe</value>
</data>
<data name="LoginPage_PasswordBox.PlaceholderText" xml:space="preserve">
<value>Entrez votre mot de passe</value>
</data>
<data name="LoginPage_LoginButton.Content" xml:space="preserve">
<value>Se Connecter</value>
</data>
<data name="LoginPage_LoginButtonText.Text" xml:space="preserve">
<value>Se Connecter</value>
</data>
<data name="LoginPage_SigningInText.Text" xml:space="preserve">
<value>Connexion en cours...</value>
</data>
<data name="LoginPage_ForgotPasswordLink.Content" xml:space="preserve">
<value>Mot de passe oublié ?</value>
</data>
<data name="LoginPage_NoAccountText.Text" xml:space="preserve">
<value>Vous n'avez pas de compte ?</value>
</data>
<data name="LoginPage_SignUpLink.Content" xml:space="preserve">
<value>S'inscrire</value>
</data>
<data name="LoginPage.Error.EmailRequired" xml:space="preserve">
<value>L'adresse e-mail est requise.</value>
</data>
<data name="LoginPage.Error.PasswordRequired" xml:space="preserve">
<value>Le mot de passe est requis.</value>
</data>
<data name="LoginPage.Error.LoginFailed" xml:space="preserve">
<value>Échec de la connexion. Veuillez vérifier vos identifiants et réessayer.</value>
</data>
</root>

View File

@@ -166,4 +166,109 @@
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
<value>A empresa foi renomeada em uma data desconhecida para um nome desconhecido.</value>
</data>
<data name="SettingsPage_ThemeSection_Header.Text" xml:space="preserve">
<value>Aparência</value>
</data>
<data name="SettingsPage_ThemeSection_Description.Text" xml:space="preserve">
<value>Selecione o seu tema preferido</value>
</data>
<data name="SettingsPage_ThemeSelector.Header" xml:space="preserve">
<value>Tema</value>
</data>
<data name="SettingsPage_ThemeChange_Notice.Text" xml:space="preserve">
<value>As alterações de tema serão aplicadas na próxima vez que você iniciar o aplicativo.</value>
</data>
<data name="SettingsPage_AboutSection_Header.Text" xml:space="preserve">
<value>Sobre</value>
</data>
<data name="SettingsPage_Version.Text" xml:space="preserve">
<value>Versão 1.0</value>
</data>
<data name="LightTheme" xml:space="preserve">
<value>Claro</value>
</data>
<data name="DarkTheme" xml:space="preserve">
<value>Escuro</value>
</data>
<data name="SystemTheme" xml:space="preserve">
<value>Sistema</value>
</data>
<data name="DefaultColorTheme" xml:space="preserve">
<value>Padrão</value>
</data>
<data name="Windows311Theme" xml:space="preserve">
<value>Windows 3.11</value>
</data>
<data name="MacOS9Theme" xml:space="preserve">
<value>Mac OS 9</value>
</data>
<data name="DOSTheme" xml:space="preserve">
<value>DOS / Turbo Vision</value>
</data>
<data name="AmigaTheme" xml:space="preserve">
<value>Amiga Workbench</value>
</data>
<data name="CDETheme" xml:space="preserve">
<value>CDE / Motif</value>
</data>
<data name="SettingsPage_BrightnessThemeSelector.Header" xml:space="preserve">
<value>Brilho</value>
</data>
<data name="SettingsPage_ColorThemeSelector.Header" xml:space="preserve">
<value>Tema de Cor</value>
</data>
<data name="SettingsPage_DesignSystemSelector.Header" xml:space="preserve">
<value>Sistema de Design</value>
</data>
<data name="SettingsPage_DesignSystemChange_Notice.Text" xml:space="preserve">
<value>As alterações no sistema de design serão aplicadas na próxima vez que você iniciar o aplicativo. As alterações no tema de cores são aplicadas imediatamente.</value>
</data>
<!-- Login Page -->
<data name="LoginPage_Title.Text" xml:space="preserve">
<value>Entrar no Marechai</value>
</data>
<data name="LoginPage_WelcomeMessage.Text" xml:space="preserve">
<value>Bem-vindo de volta! Por favor, faça login para continuar.</value>
</data>
<data name="LoginPage_EmailLabel.Text" xml:space="preserve">
<value>Endereço de E-mail</value>
</data>
<data name="LoginPage_EmailTextBox.PlaceholderText" xml:space="preserve">
<value>Digite seu e-mail</value>
</data>
<data name="LoginPage_PasswordLabel.Text" xml:space="preserve">
<value>Senha</value>
</data>
<data name="LoginPage_PasswordBox.PlaceholderText" xml:space="preserve">
<value>Digite sua senha</value>
</data>
<data name="LoginPage_LoginButton.Content" xml:space="preserve">
<value>Entrar</value>
</data>
<data name="LoginPage_LoginButtonText.Text" xml:space="preserve">
<value>Entrar</value>
</data>
<data name="LoginPage_SigningInText.Text" xml:space="preserve">
<value>Entrando...</value>
</data>
<data name="LoginPage_ForgotPasswordLink.Content" xml:space="preserve">
<value>Esqueceu sua senha?</value>
</data>
<data name="LoginPage_NoAccountText.Text" xml:space="preserve">
<value>Não tem uma conta?</value>
</data>
<data name="LoginPage_SignUpLink.Content" xml:space="preserve">
<value>Cadastre-se</value>
</data>
<data name="LoginPage.Error.EmailRequired" xml:space="preserve">
<value>O endereço de e-mail é obrigatório.</value>
</data>
<data name="LoginPage.Error.PasswordRequired" xml:space="preserve">
<value>A senha é obrigatória.</value>
</data>
<data name="LoginPage.Error.LoginFailed" xml:space="preserve">
<value>Falha no login. Por favor, verifique suas credenciais e tente novamente.</value>
</data>
</root>

View File

@@ -0,0 +1,213 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Amiga Workbench Theme -->
<!-- Classic blue background with orange accents and white text -->
<!-- System Accent - Amiga Orange -->
<Color x:Key="SystemAccentColor">#FF8800</Color> <Color x:Key="SystemAccentColorLight1">#FFAA33</Color>
<Color x:Key="SystemAccentColorLight2">#FFCC66</Color> <Color x:Key="SystemAccentColorLight3">#FFDD88</Color>
<Color x:Key="SystemAccentColorDark1">#CC6600</Color> <Color x:Key="SystemAccentColorDark2">#994400</Color>
<Color x:Key="SystemAccentColorDark3">#662200</Color>
<!-- Font Family - Topaz-like monospace -->
<FontFamily x:Key="ContentControlThemeFontFamily">Cascadia Mono, Consolas, Courier New, monospace</FontFamily>
<FontFamily x:Key="SymbolThemeFontFamily">Cascadia Mono, Consolas, Courier New, monospace</FontFamily>
<!-- ALL TEXT - White on Blue -->
<SolidColorBrush x:Key="TextFillColorPrimaryBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextFillColorSecondaryBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextFillColorTertiaryBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextFillColorDisabledBrush"
Color="#888888" />
<SolidColorBrush x:Key="TextControlForeground"
Color="#000000" />
<SolidColorBrush x:Key="TextControlForegroundPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="TextControlForegroundFocused"
Color="#000000" />
<SolidColorBrush x:Key="TextControlForegroundDisabled"
Color="#888888" />
<SolidColorBrush x:Key="TextControlPlaceholderForeground"
Color="#666666" />
<SolidColorBrush x:Key="TextControlPlaceholderForegroundPointerOver"
Color="#777777" />
<SolidColorBrush x:Key="TextControlPlaceholderForegroundFocused"
Color="#777777" />
<SolidColorBrush x:Key="TextControlHeaderForeground"
Color="#FFFFFF" />
<!-- Button Text - Black on Orange/White -->
<SolidColorBrush x:Key="ButtonForeground"
Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ButtonForegroundDisabled"
Color="#666666" />
<!-- ComboBox Text -->
<SolidColorBrush x:Key="ComboBoxForeground"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundPressed"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundFocused"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundDisabled"
Color="#666666" />
<!-- Navigation and List Text -->
<SolidColorBrush x:Key="NavigationViewItemForeground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="NavigationViewItemForegroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="NavigationViewItemForegroundPressed"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ListViewItemForeground"
Color="#000000" />
<SolidColorBrush x:Key="ListViewItemForegroundPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="ListViewItemForegroundSelected"
Color="#FFFFFF" />
<!-- System Control Foreground -->
<SolidColorBrush x:Key="SystemControlForegroundBaseHighBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumHighBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumLowBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemControlForegroundBaseLowBrush"
Color="#FFFFFF" />
<!-- System Colors -->
<SolidColorBrush x:Key="SystemBaseMediumColor"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemBaseHighColor"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemBaseMediumHighColor"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemBaseMediumLowColor"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemBaseLowColor"
Color="#FFFFFF" />
<!-- Backgrounds - Amiga Blue -->
<SolidColorBrush x:Key="ApplicationPageBackgroundThemeBrush"
Color="#0055AA" />
<SolidColorBrush x:Key="LayerFillColorDefaultBrush"
Color="#0055AA" />
<SolidColorBrush x:Key="LayerFillColorAltBrush"
Color="#004488" />
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush"
Color="#0055AA" />
<SolidColorBrush x:Key="CardBackgroundFillColorSecondaryBrush"
Color="#004488" />
<SolidColorBrush x:Key="SurfaceFillColorDefaultBrush"
Color="#0055AA" />
<SolidColorBrush x:Key="ControlFillColorDefaultBrush"
Color="#0055AA" />
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush"
Color="#004499" />
<SolidColorBrush x:Key="ControlFillColorTertiaryBrush"
Color="#004488" />
<SolidColorBrush x:Key="ControlFillColorDisabledBrush"
Color="#003366" />
<SolidColorBrush x:Key="SubtleFillColorTransparentBrush"
Color="Transparent" />
<SolidColorBrush x:Key="SubtleFillColorSecondaryBrush"
Color="#004488" />
<SolidColorBrush x:Key="SubtleFillColorTertiaryBrush"
Color="#003366" />
<!-- Button Backgrounds - Orange like Amiga -->
<SolidColorBrush x:Key="ButtonBackground"
Color="#FF8800" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#FFAA33" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#CC6600" />
<SolidColorBrush x:Key="ButtonBackgroundDisabled"
Color="#555555" />
<!-- TextBox Backgrounds - White inputs like Workbench -->
<SolidColorBrush x:Key="TextControlBackground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundFocused"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundDisabled"
Color="#CCCCCC" />
<!-- ComboBox Backgrounds -->
<SolidColorBrush x:Key="ComboBoxBackground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundPressed"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundFocused"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundDisabled"
Color="#CCCCCC" />
<!-- Navigation Backgrounds - Darker Blue -->
<SolidColorBrush x:Key="NavigationViewDefaultPaneBackground"
Color="#003377" />
<SolidColorBrush x:Key="NavigationViewTopPaneBackground"
Color="#003377" />
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground"
Color="#003377" />
<!-- List Backgrounds - White items like file lists -->
<SolidColorBrush x:Key="ListViewItemBackground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ListViewItemBackgroundPointerOver"
Color="#FFEECC" />
<SolidColorBrush x:Key="ListViewItemBackgroundPressed"
Color="#FFDDAA" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelected"
Color="#FF8800" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelectedPointerOver"
Color="#FFAA33" />
<!-- Borders - Black and Orange -->
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush"
Color="#000000" />
<SolidColorBrush x:Key="ControlStrokeColorDefaultBrush"
Color="#000000" />
<SolidColorBrush x:Key="ControlStrokeColorSecondaryBrush"
Color="#333333" />
<SolidColorBrush x:Key="DividerStrokeColorDefaultBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBorderBrush"
Color="#000000" />
<SolidColorBrush x:Key="TextControlBorderBrushPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="TextControlBorderBrushFocused"
Color="#FF8800" />
<SolidColorBrush x:Key="ComboBoxBorderBrush"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxBorderBrushPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxBorderBrushPressed"
Color="#FF8800" />
<!-- Accent Colors -->
<SolidColorBrush x:Key="AccentFillColorDefaultBrush"
Color="#FF8800" />
<SolidColorBrush x:Key="AccentFillColorSecondaryBrush"
Color="#FFAA33" />
<SolidColorBrush x:Key="AccentFillColorTertiaryBrush"
Color="#FFCC66" />
</ResourceDictionary>

View File

@@ -0,0 +1,219 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- CDE (Common Desktop Environment) Theme -->
<!-- Classic teal/cyan title bars with beige/tan windows -->
<!-- System Accent - Black for icons on tan, Teal for selections -->
<Color x:Key="SystemAccentColor">#000000</Color> <Color x:Key="SystemAccentColorLight1">#333333</Color>
<Color x:Key="SystemAccentColorLight2">#666666</Color> <Color x:Key="SystemAccentColorLight3">#999999</Color>
<Color x:Key="SystemAccentColorDark1">#000000</Color> <Color x:Key="SystemAccentColorDark2">#000000</Color>
<Color x:Key="SystemAccentColorDark3">#000000</Color>
<!-- ALL TEXT - Black on Tan, White on Teal -->
<SolidColorBrush x:Key="TextFillColorPrimaryBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextFillColorSecondaryBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextFillColorTertiaryBrush"
Color="#E0E0E0" />
<SolidColorBrush x:Key="TextFillColorDisabledBrush"
Color="#888888" />
<SolidColorBrush x:Key="TextControlForeground"
Color="#000000" />
<SolidColorBrush x:Key="TextControlForegroundPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="TextControlForegroundFocused"
Color="#000000" />
<SolidColorBrush x:Key="TextControlForegroundDisabled"
Color="#888888" />
<SolidColorBrush x:Key="TextControlPlaceholderForeground"
Color="#666666" />
<SolidColorBrush x:Key="TextControlPlaceholderForegroundPointerOver"
Color="#777777" />
<SolidColorBrush x:Key="TextControlPlaceholderForegroundFocused"
Color="#777777" />
<SolidColorBrush x:Key="TextControlHeaderForeground"
Color="#5F9EA0" />
<!-- Button Text -->
<SolidColorBrush x:Key="ButtonForeground"
Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundDisabled"
Color="#888888" />
<!-- ComboBox Text -->
<SolidColorBrush x:Key="ComboBoxForeground"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundPressed"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundFocused"
Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundDisabled"
Color="#888888" />
<!-- Navigation and List Text - White on Teal, Black on Tan -->
<SolidColorBrush x:Key="NavigationViewItemForeground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="NavigationViewItemForegroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="NavigationViewItemForegroundPressed"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ListViewItemForeground"
Color="#000000" />
<SolidColorBrush x:Key="ListViewItemForegroundPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="ListViewItemForegroundSelected"
Color="#FFFFFF" />
<!-- Icon Colors - White on Teal Headers -->
<SolidColorBrush x:Key="IconElementForeground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="FontIconForeground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SymbolIconForeground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="GlyphBrush"
Color="#FFFFFF" />
<!-- System Control Foreground - White on Teal -->
<SolidColorBrush x:Key="SystemControlForegroundBaseHighBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumHighBrush"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumLowBrush"
Color="#E0E0E0" />
<SolidColorBrush x:Key="SystemControlForegroundBaseLowBrush"
Color="#CCCCCC" />
<!-- System Colors - White on Teal -->
<SolidColorBrush x:Key="SystemBaseMediumColor"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemBaseHighColor"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemBaseMediumHighColor"
Color="#FFFFFF" />
<SolidColorBrush x:Key="SystemBaseMediumLowColor"
Color="#E0E0E0" />
<SolidColorBrush x:Key="SystemBaseLowColor"
Color="#CCCCCC" />
<!-- Backgrounds - CDE Tan/Beige Primary -->
<SolidColorBrush x:Key="ApplicationPageBackgroundThemeBrush"
Color="#C8B698" />
<SolidColorBrush x:Key="LayerFillColorDefaultBrush"
Color="#5F9EA0" />
<SolidColorBrush x:Key="LayerFillColorAltBrush"
Color="#4A7F81" />
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush"
Color="#5F9EA0" />
<SolidColorBrush x:Key="CardBackgroundFillColorSecondaryBrush"
Color="#4A7F81" />
<SolidColorBrush x:Key="SurfaceFillColorDefaultBrush"
Color="#D9C7B8" />
<SolidColorBrush x:Key="ControlFillColorDefaultBrush"
Color="#D9C7B8" />
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush"
Color="#D0BEA8" />
<SolidColorBrush x:Key="ControlFillColorTertiaryBrush"
Color="#C8B698" />
<SolidColorBrush x:Key="ControlFillColorDisabledBrush"
Color="#B8A888" />
<SolidColorBrush x:Key="SubtleFillColorTransparentBrush"
Color="Transparent" />
<SolidColorBrush x:Key="SubtleFillColorSecondaryBrush"
Color="#D0BEA8" />
<SolidColorBrush x:Key="SubtleFillColorTertiaryBrush"
Color="#C8B698" />
<!-- Button Backgrounds - Light Tan/Beige with 3D effect -->
<SolidColorBrush x:Key="ButtonBackground"
Color="#D9C7B8" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#E5D3C4" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#C0AE98" />
<SolidColorBrush x:Key="ButtonBackgroundDisabled"
Color="#B8A888" />
<!-- TextBox Backgrounds - White/Very Light Tan -->
<SolidColorBrush x:Key="TextControlBackground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundFocused"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundDisabled"
Color="#E8E8E8" />
<!-- ComboBox Backgrounds -->
<SolidColorBrush x:Key="ComboBoxBackground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundPressed"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundFocused"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundDisabled"
Color="#E8E8E8" />
<!-- Navigation Backgrounds - Teal like title bars -->
<SolidColorBrush x:Key="NavigationViewDefaultPaneBackground"
Color="#5F9EA0" />
<SolidColorBrush x:Key="NavigationViewTopPaneBackground"
Color="#5F9EA0" />
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground"
Color="#5F9EA0" />
<!-- List Backgrounds - White items -->
<SolidColorBrush x:Key="ListViewItemBackground"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ListViewItemBackgroundPointerOver"
Color="#E8E8E8" />
<SolidColorBrush x:Key="ListViewItemBackgroundPressed"
Color="#D0D0D0" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelected"
Color="#5F9EA0" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelectedPointerOver"
Color="#7FB3B5" />
<!-- Borders - Dark Gray -->
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush"
Color="#666666" />
<SolidColorBrush x:Key="ControlStrokeColorDefaultBrush"
Color="#666666" />
<SolidColorBrush x:Key="ControlStrokeColorSecondaryBrush"
Color="#888888" />
<SolidColorBrush x:Key="DividerStrokeColorDefaultBrush"
Color="#999999" />
<SolidColorBrush x:Key="TextControlBorderBrush"
Color="#666666" />
<SolidColorBrush x:Key="TextControlBorderBrushPointerOver"
Color="#666666" />
<SolidColorBrush x:Key="TextControlBorderBrushFocused"
Color="#5F9EA0" />
<SolidColorBrush x:Key="ComboBoxBorderBrush"
Color="#666666" />
<SolidColorBrush x:Key="ComboBoxBorderBrushPointerOver"
Color="#666666" />
<SolidColorBrush x:Key="ComboBoxBorderBrushPressed"
Color="#5F9EA0" />
<!-- Accent Colors -->
<SolidColorBrush x:Key="AccentFillColorDefaultBrush"
Color="#5F9EA0" />
<SolidColorBrush x:Key="AccentFillColorSecondaryBrush"
Color="#7FB3B5" />
<SolidColorBrush x:Key="AccentFillColorTertiaryBrush"
Color="#9FC8CA" />
</ResourceDictionary>

View File

@@ -0,0 +1,213 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- DOS / Turbo Vision Theme -->
<!-- Classic blue background with cyan highlights and monospaced font -->
<!-- System Accent - Cyan/Bright Green -->
<Color x:Key="SystemAccentColor">#00FFFF</Color> <Color x:Key="SystemAccentColorLight1">#55FFFF</Color>
<Color x:Key="SystemAccentColorLight2">#AAFFFF</Color> <Color x:Key="SystemAccentColorLight3">#CCFFFF</Color>
<Color x:Key="SystemAccentColorDark1">#00CCCC</Color> <Color x:Key="SystemAccentColorDark2">#009999</Color>
<Color x:Key="SystemAccentColorDark3">#006666</Color>
<!-- Font Family - Monospace -->
<FontFamily x:Key="ContentControlThemeFontFamily">Cascadia Mono, Consolas, Courier New, monospace</FontFamily>
<FontFamily x:Key="SymbolThemeFontFamily">Cascadia Mono, Consolas, Courier New, monospace</FontFamily>
<!-- ALL TEXT - Yellow/White on Blue -->
<SolidColorBrush x:Key="TextFillColorPrimaryBrush"
Color="#FFFF00" />
<SolidColorBrush x:Key="TextFillColorSecondaryBrush"
Color="#FFFF00" />
<SolidColorBrush x:Key="TextFillColorTertiaryBrush"
Color="#FFFF00" />
<SolidColorBrush x:Key="TextFillColorDisabledBrush"
Color="#808080" />
<SolidColorBrush x:Key="TextControlForeground"
Color="#FFFF00" />
<SolidColorBrush x:Key="TextControlForegroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlForegroundFocused"
Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlForegroundDisabled"
Color="#808080" />
<SolidColorBrush x:Key="TextControlPlaceholderForeground"
Color="#AAAAAA" />
<SolidColorBrush x:Key="TextControlPlaceholderForegroundPointerOver"
Color="#CCCCCC" />
<SolidColorBrush x:Key="TextControlPlaceholderForegroundFocused"
Color="#CCCCCC" />
<SolidColorBrush x:Key="TextControlHeaderForeground"
Color="#00FFFF" />
<!-- Button Text -->
<SolidColorBrush x:Key="ButtonForeground"
Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver"
Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundPressed"
Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundDisabled"
Color="#808080" />
<!-- ComboBox Text -->
<SolidColorBrush x:Key="ComboBoxForeground"
Color="#FFFF00" />
<SolidColorBrush x:Key="ComboBoxForegroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxForegroundPressed"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxForegroundFocused"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxForegroundDisabled"
Color="#808080" />
<!-- Navigation and List Text -->
<SolidColorBrush x:Key="NavigationViewItemForeground"
Color="#FFFF00" />
<SolidColorBrush x:Key="NavigationViewItemForegroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="NavigationViewItemForegroundPressed"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ListViewItemForeground"
Color="#FFFF00" />
<SolidColorBrush x:Key="ListViewItemForegroundPointerOver"
Color="#FFFFFF" />
<SolidColorBrush x:Key="ListViewItemForegroundSelected"
Color="#000000" />
<!-- System Control Foreground -->
<SolidColorBrush x:Key="SystemControlForegroundBaseHighBrush"
Color="#FFFF00" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumBrush"
Color="#FFFF00" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumHighBrush"
Color="#FFFF00" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumLowBrush"
Color="#FFFF00" />
<SolidColorBrush x:Key="SystemControlForegroundBaseLowBrush"
Color="#FFFF00" />
<!-- System Colors -->
<SolidColorBrush x:Key="SystemBaseMediumColor"
Color="#00FFFF" />
<SolidColorBrush x:Key="SystemBaseHighColor"
Color="#FFFF00" />
<SolidColorBrush x:Key="SystemBaseMediumHighColor"
Color="#FFFF00" />
<SolidColorBrush x:Key="SystemBaseMediumLowColor"
Color="#FFFF00" />
<SolidColorBrush x:Key="SystemBaseLowColor"
Color="#FFFF00" />
<!-- Backgrounds - Classic DOS Blue -->
<SolidColorBrush x:Key="ApplicationPageBackgroundThemeBrush"
Color="#0000AA" />
<SolidColorBrush x:Key="LayerFillColorDefaultBrush"
Color="#0000AA" />
<SolidColorBrush x:Key="LayerFillColorAltBrush"
Color="#000088" />
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush"
Color="#0000AA" />
<SolidColorBrush x:Key="CardBackgroundFillColorSecondaryBrush"
Color="#000088" />
<SolidColorBrush x:Key="SurfaceFillColorDefaultBrush"
Color="#0000AA" />
<SolidColorBrush x:Key="ControlFillColorDefaultBrush"
Color="#0000AA" />
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush"
Color="#000099" />
<SolidColorBrush x:Key="ControlFillColorTertiaryBrush"
Color="#000088" />
<SolidColorBrush x:Key="ControlFillColorDisabledBrush"
Color="#000077" />
<SolidColorBrush x:Key="SubtleFillColorTransparentBrush"
Color="Transparent" />
<SolidColorBrush x:Key="SubtleFillColorSecondaryBrush"
Color="#000088" />
<SolidColorBrush x:Key="SubtleFillColorTertiaryBrush"
Color="#000077" />
<!-- Button Backgrounds - Gray like Turbo Vision -->
<SolidColorBrush x:Key="ButtonBackground"
Color="#AAAAAA" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver"
Color="#00FF00" />
<SolidColorBrush x:Key="ButtonBackgroundPressed"
Color="#00FFFF" />
<SolidColorBrush x:Key="ButtonBackgroundDisabled"
Color="#555555" />
<!-- TextBox Backgrounds - Cyan on Blue -->
<SolidColorBrush x:Key="TextControlBackground"
Color="#0000AA" />
<SolidColorBrush x:Key="TextControlBackgroundPointerOver"
Color="#0000CC" />
<SolidColorBrush x:Key="TextControlBackgroundFocused"
Color="#0000CC" />
<SolidColorBrush x:Key="TextControlBackgroundDisabled"
Color="#000077" />
<!-- ComboBox Backgrounds -->
<SolidColorBrush x:Key="ComboBoxBackground"
Color="#0000AA" />
<SolidColorBrush x:Key="ComboBoxBackgroundPointerOver"
Color="#0000CC" />
<SolidColorBrush x:Key="ComboBoxBackgroundPressed"
Color="#0000CC" />
<SolidColorBrush x:Key="ComboBoxBackgroundFocused"
Color="#0000CC" />
<SolidColorBrush x:Key="ComboBoxBackgroundDisabled"
Color="#000077" />
<!-- Navigation Backgrounds - Darker Blue -->
<SolidColorBrush x:Key="NavigationViewDefaultPaneBackground"
Color="#000088" />
<SolidColorBrush x:Key="NavigationViewTopPaneBackground"
Color="#000088" />
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground"
Color="#000088" />
<!-- List Backgrounds - Cyan selection -->
<SolidColorBrush x:Key="ListViewItemBackground"
Color="#0000AA" />
<SolidColorBrush x:Key="ListViewItemBackgroundPointerOver"
Color="#0000CC" />
<SolidColorBrush x:Key="ListViewItemBackgroundPressed"
Color="#000088" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelected"
Color="#00FFFF" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelectedPointerOver"
Color="#00FFFF" />
<!-- Borders - Cyan -->
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush"
Color="#00FFFF" />
<SolidColorBrush x:Key="ControlStrokeColorDefaultBrush"
Color="#00FFFF" />
<SolidColorBrush x:Key="ControlStrokeColorSecondaryBrush"
Color="#00AAAA" />
<SolidColorBrush x:Key="DividerStrokeColorDefaultBrush"
Color="#008888" />
<SolidColorBrush x:Key="TextControlBorderBrush"
Color="#00FFFF" />
<SolidColorBrush x:Key="TextControlBorderBrushPointerOver"
Color="#00FFFF" />
<SolidColorBrush x:Key="TextControlBorderBrushFocused"
Color="#FFFF00" />
<SolidColorBrush x:Key="ComboBoxBorderBrush"
Color="#00FFFF" />
<SolidColorBrush x:Key="ComboBoxBorderBrushPointerOver"
Color="#00FFFF" />
<SolidColorBrush x:Key="ComboBoxBorderBrushPressed"
Color="#FFFF00" />
<!-- Accent Colors -->
<SolidColorBrush x:Key="AccentFillColorDefaultBrush"
Color="#00FFFF" />
<SolidColorBrush x:Key="AccentFillColorSecondaryBrush"
Color="#00CCCC" />
<SolidColorBrush x:Key="AccentFillColorTertiaryBrush"
Color="#009999" />
</ResourceDictionary>

View File

@@ -0,0 +1,128 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Mac OS 9 Platinum Theme -->
<!-- Black text on white/platinum backgrounds throughout -->
<!-- System Accent - Mac OS 9 Purple -->
<Color x:Key="SystemAccentColor">#5856D6</Color>
<Color x:Key="SystemAccentColorLight1">#7776E8</Color>
<Color x:Key="SystemAccentColorLight2">#9695F0</Color>
<Color x:Key="SystemAccentColorLight3">#B5B4F8</Color>
<Color x:Key="SystemAccentColorDark1">#4443B5</Color>
<Color x:Key="SystemAccentColorDark2">#333294</Color>
<Color x:Key="SystemAccentColorDark3">#222173</Color>
<!-- ALL TEXT - BLACK -->
<SolidColorBrush x:Key="TextFillColorPrimaryBrush" Color="#000000" />
<SolidColorBrush x:Key="TextFillColorSecondaryBrush" Color="#000000" />
<SolidColorBrush x:Key="TextFillColorTertiaryBrush" Color="#000000" />
<SolidColorBrush x:Key="TextFillColorDisabledBrush" Color="#999999" />
<SolidColorBrush x:Key="TextControlForeground" Color="#000000" />
<SolidColorBrush x:Key="TextControlForegroundPointerOver" Color="#000000" />
<SolidColorBrush x:Key="TextControlForegroundFocused" Color="#000000" />
<SolidColorBrush x:Key="TextControlForegroundDisabled" Color="#999999" />
<SolidColorBrush x:Key="TextControlPlaceholderForeground" Color="#666666" />
<SolidColorBrush x:Key="TextControlPlaceholderForegroundPointerOver" Color="#666666" />
<SolidColorBrush x:Key="TextControlPlaceholderForegroundFocused" Color="#666666" />
<SolidColorBrush x:Key="TextControlHeaderForeground" Color="#000000" />
<!-- Button Text -->
<SolidColorBrush x:Key="ButtonForeground" Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundPointerOver" Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundPressed" Color="#000000" />
<SolidColorBrush x:Key="ButtonForegroundDisabled" Color="#999999" />
<!-- ComboBox Text -->
<SolidColorBrush x:Key="ComboBoxForeground" Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundPointerOver" Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundPressed" Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundFocused" Color="#000000" />
<SolidColorBrush x:Key="ComboBoxForegroundDisabled" Color="#999999" />
<!-- Navigation and List Text -->
<SolidColorBrush x:Key="NavigationViewItemForeground" Color="#000000" />
<SolidColorBrush x:Key="NavigationViewItemForegroundPointerOver" Color="#000000" />
<SolidColorBrush x:Key="NavigationViewItemForegroundPressed" Color="#000000" />
<SolidColorBrush x:Key="ListViewItemForeground" Color="#000000" />
<SolidColorBrush x:Key="ListViewItemForegroundPointerOver" Color="#000000" />
<SolidColorBrush x:Key="ListViewItemForegroundSelected" Color="#FFFFFF" />
<!-- System Control Foreground -->
<SolidColorBrush x:Key="SystemControlForegroundBaseHighBrush" Color="#000000" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumBrush" Color="#000000" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumHighBrush" Color="#000000" />
<SolidColorBrush x:Key="SystemControlForegroundBaseMediumLowBrush" Color="#000000" />
<SolidColorBrush x:Key="SystemControlForegroundBaseLowBrush" Color="#000000" />
<!-- System Colors -->
<SolidColorBrush x:Key="SystemBaseMediumColor" Color="#000000" />
<SolidColorBrush x:Key="SystemBaseHighColor" Color="#000000" />
<SolidColorBrush x:Key="SystemBaseMediumHighColor" Color="#000000" />
<SolidColorBrush x:Key="SystemBaseMediumLowColor" Color="#000000" />
<SolidColorBrush x:Key="SystemBaseLowColor" Color="#000000" />
<!-- Backgrounds - Mac OS 9 Platinum Gray -->
<SolidColorBrush x:Key="ApplicationPageBackgroundThemeBrush" Color="#CCCCCC" />
<SolidColorBrush x:Key="LayerFillColorDefaultBrush" Color="#DDDDDD" />
<SolidColorBrush x:Key="LayerFillColorAltBrush" Color="#D0D0D0" />
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="#DDDDDD" />
<SolidColorBrush x:Key="CardBackgroundFillColorSecondaryBrush" Color="#D0D0D0" />
<SolidColorBrush x:Key="SurfaceFillColorDefaultBrush" Color="#DDDDDD" />
<SolidColorBrush x:Key="ControlFillColorDefaultBrush" Color="#DDDDDD" />
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush" Color="#D8D8D8" />
<SolidColorBrush x:Key="ControlFillColorTertiaryBrush" Color="#D0D0D0" />
<SolidColorBrush x:Key="ControlFillColorDisabledBrush" Color="#C8C8C8" />
<SolidColorBrush x:Key="SubtleFillColorTransparentBrush" Color="Transparent" />
<SolidColorBrush x:Key="SubtleFillColorSecondaryBrush" Color="#D0D0D0" />
<SolidColorBrush x:Key="SubtleFillColorTertiaryBrush" Color="#C8C8C8" />
<!-- Button Backgrounds -->
<SolidColorBrush x:Key="ButtonBackground" Color="#DDDDDD" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver" Color="#E8E8E8" />
<SolidColorBrush x:Key="ButtonBackgroundPressed" Color="#C8C8C8" />
<SolidColorBrush x:Key="ButtonBackgroundDisabled" Color="#D0D0D0" />
<!-- TextBox Backgrounds - White inputs on gray windows -->
<SolidColorBrush x:Key="TextControlBackground" Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundPointerOver" Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundFocused" Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundDisabled" Color="#E0E0E0" />
<!-- ComboBox Backgrounds -->
<SolidColorBrush x:Key="ComboBoxBackground" Color="#DDDDDD" />
<SolidColorBrush x:Key="ComboBoxBackgroundPointerOver" Color="#E8E8E8" />
<SolidColorBrush x:Key="ComboBoxBackgroundPressed" Color="#C8C8C8" />
<SolidColorBrush x:Key="ComboBoxBackgroundFocused" Color="#DDDDDD" />
<SolidColorBrush x:Key="ComboBoxBackgroundDisabled" Color="#D0D0D0" />
<!-- Navigation Backgrounds - Platinum Gray -->
<SolidColorBrush x:Key="NavigationViewDefaultPaneBackground" Color="#D8D8D8" />
<SolidColorBrush x:Key="NavigationViewTopPaneBackground" Color="#D8D8D8" />
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground" Color="#D8D8D8" />
<!-- List Backgrounds - Platinum Gray -->
<SolidColorBrush x:Key="ListViewItemBackground" Color="#DDDDDD" />
<SolidColorBrush x:Key="ListViewItemBackgroundPointerOver" Color="#E8E8E8" />
<SolidColorBrush x:Key="ListViewItemBackgroundPressed" Color="#C8C8C8" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelected" Color="#5856D6" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelectedPointerOver" Color="#6D6BE8" />
<!-- Borders -->
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="#999999" />
<SolidColorBrush x:Key="ControlStrokeColorDefaultBrush" Color="#999999" />
<SolidColorBrush x:Key="ControlStrokeColorSecondaryBrush" Color="#AAAAAA" />
<SolidColorBrush x:Key="DividerStrokeColorDefaultBrush" Color="#CCCCCC" />
<SolidColorBrush x:Key="TextControlBorderBrush" Color="#999999" />
<SolidColorBrush x:Key="TextControlBorderBrushPointerOver" Color="#777777" />
<SolidColorBrush x:Key="TextControlBorderBrushFocused" Color="#5856D6" />
<SolidColorBrush x:Key="ComboBoxBorderBrush" Color="#999999" />
<SolidColorBrush x:Key="ComboBoxBorderBrushPointerOver" Color="#777777" />
<SolidColorBrush x:Key="ComboBoxBorderBrushPressed" Color="#5856D6" />
<!-- Accent Colors -->
<SolidColorBrush x:Key="AccentFillColorDefaultBrush" Color="#5856D6" />
<SolidColorBrush x:Key="AccentFillColorSecondaryBrush" Color="#6D6BE8" />
<SolidColorBrush x:Key="AccentFillColorTertiaryBrush" Color="#8280F0" />
</ResourceDictionary>

View File

@@ -0,0 +1,86 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Windows 3.11 Color Theme -->
<!-- Classic teal/cyan desktop background and gray window chrome -->
<!-- System Colors -->
<Color x:Key="SystemAccentColor">#008080</Color>
<Color x:Key="SystemAccentColorLight1">#00A0A0</Color>
<Color x:Key="SystemAccentColorLight2">#00C0C0</Color>
<Color x:Key="SystemAccentColorLight3">#00E0E0</Color>
<Color x:Key="SystemAccentColorDark1">#006060</Color>
<Color x:Key="SystemAccentColorDark2">#004040</Color>
<Color x:Key="SystemAccentColorDark3">#002020</Color>
<!-- Background Colors - Classic Windows 3.11 teal -->
<SolidColorBrush x:Key="ApplicationPageBackgroundThemeBrush" Color="#008080" />
<SolidColorBrush x:Key="LayerFillColorDefaultBrush" Color="#C0C0C0" />
<SolidColorBrush x:Key="LayerFillColorAltBrush" Color="#C0C0C0" />
<!-- Card and Surface Colors - Gray window chrome -->
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush" Color="#C0C0C0" />
<SolidColorBrush x:Key="CardBackgroundFillColorSecondaryBrush" Color="#C0C0C0" />
<SolidColorBrush x:Key="SurfaceFillColorDefaultBrush" Color="#C0C0C0" />
<SolidColorBrush x:Key="ControlFillColorDefaultBrush" Color="#C0C0C0" />
<!-- Accent Colors - Classic teal -->
<SolidColorBrush x:Key="AccentFillColorDefaultBrush" Color="#008080" />
<SolidColorBrush x:Key="AccentFillColorSecondaryBrush" Color="#006060" />
<SolidColorBrush x:Key="AccentFillColorTertiaryBrush" Color="#004040" />
<!-- Text Colors - Classic black text on gray -->
<SolidColorBrush x:Key="TextFillColorPrimaryBrush" Color="#000000" />
<SolidColorBrush x:Key="TextFillColorSecondaryBrush" Color="#404040" />
<SolidColorBrush x:Key="TextFillColorTertiaryBrush" Color="#606060" />
<SolidColorBrush x:Key="TextFillColorDisabledBrush" Color="#808080" />
<!-- Border Colors - Classic 3D borders -->
<SolidColorBrush x:Key="CardStrokeColorDefaultBrush" Color="#808080" />
<SolidColorBrush x:Key="ControlStrokeColorDefaultBrush" Color="#808080" />
<SolidColorBrush x:Key="ControlStrokeColorSecondaryBrush" Color="#808080" />
<SolidColorBrush x:Key="DividerStrokeColorDefaultBrush" Color="#808080" />
<!-- Button Colors -->
<SolidColorBrush x:Key="ButtonBackgroundBrush" Color="#C0C0C0" />
<SolidColorBrush x:Key="ButtonBackgroundPointerOver" Color="#D0D0D0" />
<SolidColorBrush x:Key="ButtonBackgroundPressed" Color="#808080" />
<SolidColorBrush x:Key="ButtonForeground" Color="#000000" />
<!-- NavigationView Colors -->
<SolidColorBrush x:Key="NavigationViewDefaultPaneBackground" Color="#C0C0C0" />
<SolidColorBrush x:Key="NavigationViewTopPaneBackground" Color="#C0C0C0" />
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground" Color="#C0C0C0" />
<!-- List and Item Colors -->
<SolidColorBrush x:Key="ListViewItemBackgroundBrush" Color="#FFFFFF" />
<SolidColorBrush x:Key="ListViewItemBackgroundPointerOver" Color="#E0E0E0" />
<SolidColorBrush x:Key="ListViewItemBackgroundSelected" Color="#000080" />
<SolidColorBrush x:Key="ListViewItemForegroundSelected" Color="#FFFFFF" />
<!-- Subtle Fill Colors -->
<SolidColorBrush x:Key="SubtleFillColorTransparentBrush" Color="Transparent" />
<SolidColorBrush x:Key="SubtleFillColorSecondaryBrush" Color="#E0E0E0" />
<SolidColorBrush x:Key="SubtleFillColorTertiaryBrush" Color="#D0D0D0" />
<!-- Control Colors -->
<SolidColorBrush x:Key="ControlFillColorSecondaryBrush" Color="#D0D0D0" />
<SolidColorBrush x:Key="ControlFillColorTertiaryBrush" Color="#E0E0E0" />
<SolidColorBrush x:Key="ControlFillColorDisabledBrush" Color="#A0A0A0" />
<!-- TextBox Colors -->
<SolidColorBrush x:Key="TextControlBackground" Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundPointerOver" Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlBackgroundFocused" Color="#FFFFFF" />
<SolidColorBrush x:Key="TextControlForeground" Color="#000000" />
<SolidColorBrush x:Key="TextControlBorderBrush" Color="#808080" />
<!-- ComboBox Colors -->
<SolidColorBrush x:Key="ComboBoxBackground" Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundPointerOver" Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundPressed" Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxBackgroundFocused" Color="#FFFFFF" />
<SolidColorBrush x:Key="ComboBoxForeground" Color="#000000" />
<SolidColorBrush x:Key="ComboBoxBorderBrush" Color="#808080" />
</ResourceDictionary>

View File

@@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
namespace Marechai.Data.Models;
public sealed record ChangePasswordRequest
{
[Required]
[MinLength(6)]
[JsonPropertyName("newPassword")]
public string NewPassword { get; set; } = null!;
}

View File

@@ -0,0 +1,24 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
namespace Marechai.Data.Models;
public sealed record CreateUserRequest
{
[Required]
[JsonPropertyName("userName")]
public string UserName { get; set; } = null!;
[Required]
[EmailAddress]
[JsonPropertyName("email")]
public string Email { get; set; } = null!;
[Required]
[MinLength(6)]
[JsonPropertyName("password")]
public string Password { get; set; } = null!;
[JsonPropertyName("phoneNumber")]
public string? PhoneNumber { get; set; }
}

View File

@@ -0,0 +1,25 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
namespace Marechai.Data.Models;
public sealed record UpdateUserRequest
{
[Required]
[JsonPropertyName("userName")]
public string UserName { get; set; } = null!;
[Required]
[EmailAddress]
[JsonPropertyName("email")]
public string Email { get; set; } = null!;
[JsonPropertyName("phoneNumber")]
public string? PhoneNumber { get; set; }
[JsonPropertyName("emailConfirmed")]
public bool? EmailConfirmed { get; set; }
[JsonPropertyName("lockoutEnabled")]
public bool? LockoutEnabled { get; set; }
}

View File

@@ -0,0 +1,37 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Marechai.Data.Models;
public sealed record UserDto
{
[JsonPropertyName("id")]
public string Id { get; set; } = null!;
[JsonPropertyName("userName")]
public string UserName { get; set; } = null!;
[JsonPropertyName("email")]
public string Email { get; set; } = null!;
[JsonPropertyName("emailConfirmed")]
public bool EmailConfirmed { get; set; }
[JsonPropertyName("phoneNumber")]
public string? PhoneNumber { get; set; }
[JsonPropertyName("phoneNumberConfirmed")]
public bool PhoneNumberConfirmed { get; set; }
[JsonPropertyName("lockoutEnabled")]
public bool LockoutEnabled { get; set; }
[JsonPropertyName("lockoutEnd")]
public string? LockoutEnd { get; set; }
[JsonPropertyName("accessFailedCount")]
public int AccessFailedCount { get; set; }
[JsonPropertyName("roles")]
public List<string> Roles { get; set; } = [];
}

View File

@@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
namespace Marechai.Data.Models;
public sealed record UserRoleRequest
{
[Required]
[JsonPropertyName("roleName")]
public string RoleName { get; set; } = null!;
}

View File

@@ -0,0 +1,304 @@
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ---------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] -----------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ---------------------------------------------------------------------------
// Copyright © 2003-2026 Natalia Portillo
*******************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Marechai.Data.Models;
using Marechai.Database.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
namespace Marechai.Server.Controllers;
[ApiController]
[Route("users")]
[Authorize(Roles = ApplicationRole.RoleUberAdmin)]
public class UsersController(UserManager<ApplicationUser> userManager) : ControllerBase
{
[HttpGet]
[ProducesResponseType(typeof(List<UserDto>), StatusCodes.Status200OK, Description = "Returns a list of all users.")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[Produces("application/json")]
public async Task<ActionResult<List<UserDto>>> GetAll()
{
var users = userManager.Users.ToList();
var userDtos = new List<UserDto>();
foreach(ApplicationUser user in users)
{
IList<string> roles = await userManager.GetRolesAsync(user);
userDtos.Add(new UserDto
{
Id = user.Id,
UserName = user.UserName!,
Email = user.Email!,
EmailConfirmed = user.EmailConfirmed,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
LockoutEnabled = user.LockoutEnabled,
LockoutEnd = user.LockoutEnd?.ToString("O"),
AccessFailedCount = user.AccessFailedCount,
Roles = roles.ToList()
});
}
return Ok(userDtos);
}
[HttpGet("{id}")]
[ProducesResponseType(typeof(UserDto), StatusCodes.Status200OK, Description = "Returns a specific user by ID.")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Produces("application/json")]
public async Task<ActionResult<UserDto>> GetById(string id)
{
ApplicationUser user = await userManager.FindByIdAsync(id);
if(user == null) return NotFound("User not found");
IList<string> roles = await userManager.GetRolesAsync(user);
return Ok(new UserDto
{
Id = user.Id,
UserName = user.UserName!,
Email = user.Email!,
EmailConfirmed = user.EmailConfirmed,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
LockoutEnabled = user.LockoutEnabled,
LockoutEnd = user.LockoutEnd?.ToString("O"),
AccessFailedCount = user.AccessFailedCount,
Roles = roles.ToList()
});
}
[HttpPost]
[ProducesResponseType(typeof(UserDto), StatusCodes.Status201Created, Description = "Creates a new user.")]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[Produces("application/json")]
[Consumes("application/json")]
public async Task<ActionResult<UserDto>> Create([FromBody] CreateUserRequest request)
{
if(!ModelState.IsValid) return BadRequest(ModelState);
var user = new ApplicationUser
{
UserName = request.UserName,
Email = request.Email,
PhoneNumber = request.PhoneNumber
};
IdentityResult result = await userManager.CreateAsync(user, request.Password);
if(!result.Succeeded) return BadRequest(result.Errors);
IList<string> roles = await userManager.GetRolesAsync(user);
return CreatedAtAction(nameof(GetById),
new
{
id = user.Id
},
new UserDto
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
EmailConfirmed = user.EmailConfirmed,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
LockoutEnabled = user.LockoutEnabled,
LockoutEnd = user.LockoutEnd?.ToString("O"),
AccessFailedCount = user.AccessFailedCount,
Roles = roles.ToList()
});
}
[HttpPut("{id}")]
[ProducesResponseType(typeof(UserDto), StatusCodes.Status200OK, Description = "Updates an existing user.")]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Produces("application/json")]
[Consumes("application/json")]
public async Task<ActionResult<UserDto>> Update(string id, [FromBody] UpdateUserRequest request)
{
if(!ModelState.IsValid) return BadRequest(ModelState);
ApplicationUser user = await userManager.FindByIdAsync(id);
if(user == null) return NotFound("User not found");
user.UserName = request.UserName;
user.Email = request.Email;
user.PhoneNumber = request.PhoneNumber;
if(request.EmailConfirmed.HasValue) user.EmailConfirmed = request.EmailConfirmed.Value;
if(request.LockoutEnabled.HasValue) user.LockoutEnabled = request.LockoutEnabled.Value;
IdentityResult result = await userManager.UpdateAsync(user);
if(!result.Succeeded) return BadRequest(result.Errors);
IList<string> roles = await userManager.GetRolesAsync(user);
return Ok(new UserDto
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
EmailConfirmed = user.EmailConfirmed,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
LockoutEnabled = user.LockoutEnabled,
LockoutEnd = user.LockoutEnd?.ToString("O"),
AccessFailedCount = user.AccessFailedCount,
Roles = roles.ToList()
});
}
[HttpDelete("{id}")]
[ProducesResponseType(StatusCodes.Status204NoContent, Description = "Deletes a user.")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> Delete(string id)
{
ApplicationUser user = await userManager.FindByIdAsync(id);
if(user == null) return NotFound("User not found");
IdentityResult result = await userManager.DeleteAsync(user);
if(!result.Succeeded) return BadRequest(result.Errors);
return NoContent();
}
[HttpPost("{id}/password")]
[ProducesResponseType(StatusCodes.Status204NoContent, Description = "Changes a user's password.")]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Consumes("application/json")]
public async Task<IActionResult> ChangePassword(string id, [FromBody] ChangePasswordRequest request)
{
if(!ModelState.IsValid) return BadRequest(ModelState);
ApplicationUser user = await userManager.FindByIdAsync(id);
if(user == null) return NotFound("User not found");
// Remove old password and set new one
IdentityResult removeResult = await userManager.RemovePasswordAsync(user);
if(!removeResult.Succeeded) return BadRequest(removeResult.Errors);
IdentityResult addResult = await userManager.AddPasswordAsync(user, request.NewPassword);
if(!addResult.Succeeded) return BadRequest(addResult.Errors);
return NoContent();
}
[HttpPost("{id}/roles")]
[ProducesResponseType(StatusCodes.Status204NoContent, Description = "Adds a role to a user.")]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Consumes("application/json")]
public async Task<IActionResult> AddRole(string id, [FromBody] UserRoleRequest request)
{
if(!ModelState.IsValid) return BadRequest(ModelState);
ApplicationUser user = await userManager.FindByIdAsync(id);
if(user == null) return NotFound("User not found");
IdentityResult result = await userManager.AddToRoleAsync(user, request.RoleName);
if(!result.Succeeded) return BadRequest(result.Errors);
return NoContent();
}
[HttpDelete("{id}/roles/{roleName}")]
[ProducesResponseType(StatusCodes.Status204NoContent, Description = "Removes a role from a user.")]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> RemoveRole(string id, string roleName)
{
ApplicationUser user = await userManager.FindByIdAsync(id);
if(user == null) return NotFound("User not found");
IdentityResult result = await userManager.RemoveFromRoleAsync(user, roleName);
if(!result.Succeeded) return BadRequest(result.Errors);
return NoContent();
}
[HttpGet("roles")]
[ProducesResponseType(typeof(List<string>), StatusCodes.Status200OK, Description = "Returns all available roles.")]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[Produces("application/json")]
public IActionResult GetAllRoles()
{
var roles = new List<string>
{
ApplicationRole.RoleUberAdmin,
ApplicationRole.RoleWriter,
ApplicationRole.RoleProofreader,
ApplicationRole.RoleTranslator,
ApplicationRole.RoleSuperTranslator,
ApplicationRole.RoleCollaborator,
ApplicationRole.RoleCurator,
ApplicationRole.RolePhysicalCurator,
ApplicationRole.RoleTechnician,
ApplicationRole.RoleSuperTechnician,
ApplicationRole.RoleAdmin,
ApplicationRole.RoleNone
};
return Ok(roles);
}
}