mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-03-11 11:18:02 -04:00
Add settings table and service to client project (#145)
This commit is contained in:
@@ -43,7 +43,10 @@
|
||||
</div>
|
||||
<ul class="py-1 font-light text-gray-500 dark:text-gray-400" aria-labelledby="userMenuDropdownButton">
|
||||
<li>
|
||||
<a href="settings/vault" class="block py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-400 dark:hover:text-white">Vault settings</a>
|
||||
<a href="/settings/general" class="block py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-400 dark:hover:text-white">General settings</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/settings/vault" class="block py-2 px-4 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 dark:text-gray-400 dark:hover:text-white">Vault settings</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="py-1 font-light text-gray-500 dark:text-gray-400" aria-labelledby="dropdown">
|
||||
|
||||
146
src/AliasVault.Client/Main/Pages/Settings/General.razor
Normal file
146
src/AliasVault.Client/Main/Pages/Settings/General.razor
Normal file
@@ -0,0 +1,146 @@
|
||||
@page "/settings/general"
|
||||
@inherits MainBase
|
||||
@inject CredentialService CredentialService
|
||||
|
||||
<LayoutPageTitle>General settings</LayoutPageTitle>
|
||||
|
||||
<div class="grid grid-cols-1 px-4 pt-6 xl:grid-cols-3 xl:gap-4 dark:bg-gray-900">
|
||||
<div class="mb-4 col-span-full xl:mb-2">
|
||||
<Breadcrumb BreadcrumbItems="BreadcrumbItems" />
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl dark:text-white">General settings</h1>
|
||||
</div>
|
||||
<p>On this page you can configure general AliasVault settings.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
|
||||
<h3 class="mb-4 text-xl font-semibold dark:text-white">Export vault</h3>
|
||||
<div class="mb-4">
|
||||
<div>
|
||||
<button @onclick="ExportVaultSqlite" type="button" class="px-4 py-2 text-white bg-primary-600 rounded-lg hover:bg-primary-700 focus:ring-4 focus:ring-primary-300 dark:bg-primary-500 dark:hover:bg-primary-600 dark:focus:ring-primary-800">
|
||||
Export vault to unencrypted SQLite file
|
||||
</button>
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<button @onclick="ExportVaultCsv" type="button" class="px-4 py-2 text-white bg-primary-600 rounded-lg hover:bg-primary-700 focus:ring-4 focus:ring-primary-300 dark:bg-primary-500 dark:hover:bg-primary-600 dark:focus:ring-primary-800">
|
||||
Export vault to unencrypted CSV file
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
|
||||
<h3 class="mb-4 text-xl font-semibold dark:text-white">Import vault</h3>
|
||||
<div class="mb-4">
|
||||
<div>
|
||||
Import unencrypted CSV file:
|
||||
<InputFile OnChange="@LoadFiles" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (IsImporting)
|
||||
{
|
||||
<p>Loading...</p>
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(ImportErrorMessage))
|
||||
{
|
||||
<p class="text-danger">@ImportErrorMessage</p>
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(ImportSuccessMessage))
|
||||
{
|
||||
<p class="text-success">@ImportSuccessMessage</p>
|
||||
}
|
||||
|
||||
@code {
|
||||
private bool IsImporting = false;
|
||||
private string ImportErrorMessage = string.Empty;
|
||||
private string ImportSuccessMessage = string.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
BreadcrumbItems.Add(new BreadcrumbItem { DisplayName = "Vault settings" });
|
||||
}
|
||||
|
||||
private async Task ExportVaultSqlite()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Decode the base64 string to a byte array
|
||||
byte[] fileBytes = Convert.FromBase64String(await DbService.ExportSqliteToBase64Async());
|
||||
|
||||
// Create a memory stream from the byte array
|
||||
using (MemoryStream memoryStream = new MemoryStream(fileBytes))
|
||||
{
|
||||
// Invoke JavaScript to initiate the download
|
||||
await JsInteropService.DownloadFileFromStream("aliasvault-client.sqlite", memoryStream.ToArray());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error downloading file: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExportVaultCsv()
|
||||
{
|
||||
try
|
||||
{
|
||||
var credentials = await CredentialService.LoadAllAsync();
|
||||
|
||||
var csvBytes = CsvImportExport.CredentialCsvService.ExportCredentialsToCsv(credentials);
|
||||
|
||||
// Create a memory stream from the byte array
|
||||
using (MemoryStream memoryStream = new MemoryStream(csvBytes))
|
||||
{
|
||||
// Invoke JavaScript to initiate the download
|
||||
await JsInteropService.DownloadFileFromStream("aliasvault-client.csv", memoryStream.ToArray());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error downloading file: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadFiles(InputFileChangeEventArgs e)
|
||||
{
|
||||
IsImporting = true;
|
||||
StateHasChanged();
|
||||
ImportErrorMessage = string.Empty;
|
||||
ImportSuccessMessage = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
var file = e.File;
|
||||
var buffer = new byte[file.Size];
|
||||
await file.OpenReadStream().ReadAsync(buffer);
|
||||
var fileContent = System.Text.Encoding.UTF8.GetString(buffer);
|
||||
|
||||
var importedCredentials = CsvImportExport.CredentialCsvService.ImportCredentialsFromCsv(fileContent);
|
||||
|
||||
// Loop through the imported credentials and actually add them to the database
|
||||
foreach (var importedCredential in importedCredentials)
|
||||
{
|
||||
await CredentialService.InsertEntryAsync(importedCredential, false);
|
||||
}
|
||||
|
||||
// Save the database.
|
||||
await DbService.SaveDatabaseAsync();
|
||||
|
||||
ImportSuccessMessage = $"Succesfully imported {importedCredentials.Count} credentials.";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ImportErrorMessage = $"Error importing file: {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsImporting = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,7 @@ builder.Services.AddScoped<DbService>();
|
||||
builder.Services.AddScoped<GlobalNotificationService>();
|
||||
builder.Services.AddScoped<GlobalLoadingService>();
|
||||
builder.Services.AddScoped<JsInteropService>();
|
||||
builder.Services.AddScoped<SettingsService>();
|
||||
builder.Services.AddSingleton<ClipboardCopyService>();
|
||||
|
||||
builder.Services.AddAuthorizationCore();
|
||||
|
||||
185
src/AliasVault.Client/Services/SettingsService.cs
Normal file
185
src/AliasVault.Client/Services/SettingsService.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="SettingsService.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace AliasVault.Client.Services;
|
||||
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using AliasClientDb;
|
||||
|
||||
/// <summary>
|
||||
/// Service class for accessing and mutating general settings stored in database.
|
||||
/// </summary>
|
||||
public class SettingsService(DbService dbService)
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the DefaultEmailDomain setting asynchronously.
|
||||
/// </summary>
|
||||
/// <returns>Default email domain as string.</returns>
|
||||
public Task<string> GetDefaultEmailDomainAsync() => GetSettingAsync("DefaultEmailDomain");
|
||||
|
||||
/// <summary>
|
||||
/// Sets the DefaultEmailDomain setting asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="value">The new DeafultEmailDomain setting.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task SetDefaultEmailDomainAsync(string value) => SetSettingAsync("DefaultEmailDomain", value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the AutoEmailRefresh setting asynchronously as a string.
|
||||
/// </summary>
|
||||
/// <returns>AutoEmailRefresh setting as string.</returns>
|
||||
public Task<bool> GetAutoEmailRefreshAsync() => GetSettingAsync<bool>("AutoEmailRefresh");
|
||||
|
||||
/// <summary>
|
||||
/// Sets the AutoEmailRefresh setting asynchronously as a string.
|
||||
/// </summary>
|
||||
/// <param name="value">The new value.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public Task SetAutoEmailRefreshAsync(bool value) => SetSettingAsync<bool>("AutoEmailRefresh", value);
|
||||
|
||||
/// <summary>
|
||||
/// Get setting value from database.
|
||||
/// </summary>
|
||||
/// <param name="key">Key of setting to retrieve.</param>
|
||||
/// <returns>Setting as string value.</returns>
|
||||
private async Task<string> GetSettingAsync(string key)
|
||||
{
|
||||
var db = await dbService.GetDbContextAsync();
|
||||
var setting = await db.Settings.FindAsync(key);
|
||||
return setting?.Value ?? string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a setting asynchronously and casts it to the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to cast the setting to.</typeparam>
|
||||
/// <param name="key">The key of the setting.</param>
|
||||
/// <returns>The setting value cast to type T.</returns>
|
||||
private async Task<T?> GetSettingAsync<T>(string key)
|
||||
{
|
||||
string value = await GetSettingAsync(key);
|
||||
return CastSetting<T>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a setting asynchronously, converting the value to a string so its compatible with the database field.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value being set.</typeparam>
|
||||
/// <param name="key">The key of the setting.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
/// <returns>Task.</returns>
|
||||
private Task SetSettingAsync<T>(string key, T value)
|
||||
{
|
||||
string stringValue = ConvertToString(value);
|
||||
return SetSettingAsync(key, stringValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set setting value in database.
|
||||
/// </summary>
|
||||
/// <param name="key">Key of setting to set.</param>
|
||||
/// <param name="value">Value of setting to set.</param>
|
||||
/// <returns>Task.</returns>
|
||||
private async Task SetSettingAsync(string key, string value)
|
||||
{
|
||||
var db = await dbService.GetDbContextAsync();
|
||||
var setting = await db.Settings.FindAsync(key);
|
||||
if (setting == null)
|
||||
{
|
||||
setting = new Setting
|
||||
{
|
||||
Key = key,
|
||||
Value = value,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
UpdatedAt = DateTime.UtcNow,
|
||||
};
|
||||
db.Settings.Add(setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
setting.Value = value;
|
||||
setting.UpdatedAt = DateTime.UtcNow;
|
||||
db.Settings.Update(setting);
|
||||
}
|
||||
|
||||
await dbService.SaveDatabaseAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts a setting value from the database string type to the specified requested type.
|
||||
/// </summary>
|
||||
/// <param name="value">Value (string) to cast.</param>
|
||||
/// <typeparam name="T">Type to cast it to.</typeparam>
|
||||
/// <returns>The value casted to the requested type.</returns>
|
||||
private T? CastSetting<T>(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
if (default(T) is null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Cannot cast null or empty string to non-nullable type {typeof(T)}");
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(bool))
|
||||
{
|
||||
return (T)(object)(bool.TryParse(value, out bool result) && result);
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(int))
|
||||
{
|
||||
return (T)(object)int.Parse(value);
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(double))
|
||||
{
|
||||
return (T)(object)double.Parse(value);
|
||||
}
|
||||
|
||||
if (typeof(T) == typeof(string))
|
||||
{
|
||||
return (T)(object)value;
|
||||
}
|
||||
|
||||
// For complex types, attempt JSON deserialization
|
||||
try
|
||||
{
|
||||
var result = JsonSerializer.Deserialize<T>(value);
|
||||
if (result is null && default(T) is not null)
|
||||
{
|
||||
throw new InvalidOperationException($"Deserialization resulted in null for non-nullable type {typeof(T)}");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to deserialize value to type {typeof(T)}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a value of any type to a string.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to convert.</param>
|
||||
/// <typeparam name="T">The type of the existing value.</typeparam>
|
||||
/// <returns>Value converted to string.</returns>
|
||||
private string ConvertToString<T>(T value)
|
||||
{
|
||||
if (value is bool || value is int || value is double || value is string)
|
||||
{
|
||||
return value.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
// For complex types, use JSON serialization
|
||||
return JsonSerializer.Serialize(value);
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,11 @@ public class AliasClientDbContext : DbContext
|
||||
/// </summary>
|
||||
public DbSet<EncryptionKey> EncryptionKeys { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Settings DbSet.
|
||||
/// </summary>
|
||||
public DbSet<Setting> Settings { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The OnModelCreating method.
|
||||
/// </summary>
|
||||
|
||||
328
src/Databases/AliasClientDb/Migrations/20240805073413_1.2.0-AddSettingsTable.Designer.cs
generated
Normal file
328
src/Databases/AliasClientDb/Migrations/20240805073413_1.2.0-AddSettingsTable.Designer.cs
generated
Normal file
@@ -0,0 +1,328 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using AliasClientDb;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AliasClientDb.Migrations
|
||||
{
|
||||
[DbContext(typeof(AliasClientDbContext))]
|
||||
[Migration("20240805073413_1.2.0-AddSettingsTable")]
|
||||
partial class _120AddSettingsTable
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.7")
|
||||
.HasAnnotation("Proxies:ChangeTracking", false)
|
||||
.HasAnnotation("Proxies:CheckEquality", false)
|
||||
.HasAnnotation("Proxies:LazyLoading", true);
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Alias", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("AddressCity")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("VARCHAR");
|
||||
|
||||
b.Property<string>("AddressCountry")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("VARCHAR");
|
||||
|
||||
b.Property<string>("AddressState")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("VARCHAR");
|
||||
|
||||
b.Property<string>("AddressStreet")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("VARCHAR");
|
||||
|
||||
b.Property<string>("AddressZipCode")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("VARCHAR");
|
||||
|
||||
b.Property<string>("BankAccountIBAN")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("BirthDate")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("FirstName")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("VARCHAR");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("VARCHAR");
|
||||
|
||||
b.Property<string>("Hobbies")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("LastName")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("VARCHAR");
|
||||
|
||||
b.Property<string>("NickName")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("VARCHAR");
|
||||
|
||||
b.Property<string>("PhoneMobile")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Aliases");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Attachment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("Blob")
|
||||
.IsRequired()
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("CredentialId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Filename")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CredentialId");
|
||||
|
||||
b.ToTable("Attachment");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Credential", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("AliasId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("ServiceId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AliasId");
|
||||
|
||||
b.HasIndex("ServiceId");
|
||||
|
||||
b.ToTable("Credentials");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.EncryptionKey", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsPrimary")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("PrivateKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PublicKey")
|
||||
.IsRequired()
|
||||
.HasMaxLength(2000)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EncryptionKeys");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Password", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<Guid>("CredentialId")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CredentialId");
|
||||
|
||||
b.ToTable("Passwords");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Service", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<byte[]>("Logo")
|
||||
.HasColumnType("BLOB");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Services");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Setting", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Attachment", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Credential", "Credential")
|
||||
.WithMany("Attachments")
|
||||
.HasForeignKey("CredentialId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Credential");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Credential", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Alias", "Alias")
|
||||
.WithMany("Credentials")
|
||||
.HasForeignKey("AliasId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("AliasClientDb.Service", "Service")
|
||||
.WithMany("Credentials")
|
||||
.HasForeignKey("ServiceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Alias");
|
||||
|
||||
b.Navigation("Service");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Password", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Credential", "Credential")
|
||||
.WithMany("Passwords")
|
||||
.HasForeignKey("CredentialId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Credential");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Alias", b =>
|
||||
{
|
||||
b.Navigation("Credentials");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Credential", b =>
|
||||
{
|
||||
b.Navigation("Attachments");
|
||||
|
||||
b.Navigation("Passwords");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Service", b =>
|
||||
{
|
||||
b.Navigation("Credentials");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace AliasClientDb.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class _120AddSettingsTable : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Settings",
|
||||
columns: table => new
|
||||
{
|
||||
Key = table.Column<string>(type: "TEXT", maxLength: 255, nullable: false),
|
||||
Value = table.Column<string>(type: "TEXT", nullable: true),
|
||||
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Settings", x => x.Key);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Settings");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,6 +242,26 @@ namespace AliasClientDb.Migrations
|
||||
b.ToTable("Services");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Setting", b =>
|
||||
{
|
||||
b.Property<string>("Key")
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Key");
|
||||
|
||||
b.ToTable("Settings");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("AliasClientDb.Attachment", b =>
|
||||
{
|
||||
b.HasOne("AliasClientDb.Credential", "Credential")
|
||||
|
||||
38
src/Databases/AliasClientDb/Setting.cs
Normal file
38
src/Databases/AliasClientDb/Setting.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="Setting.cs" company="lanedirt">
|
||||
// Copyright (c) lanedirt. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
namespace AliasClientDb;
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
/// <summary>
|
||||
/// The service entity.
|
||||
/// </summary>
|
||||
public class Setting
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the setting key which is also the primary unique key.
|
||||
/// </summary>
|
||||
[Key]
|
||||
[StringLength(255)]
|
||||
public string Key { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the setting value. The field type is a string, but it can be used to store any type of data
|
||||
/// via serialization.
|
||||
/// </summary>
|
||||
public string? Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the created timestamp.
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the updated timestamp.
|
||||
/// </summary>
|
||||
public DateTime UpdatedAt { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user