backend phase 0: foundation, cross-cutting seams & starter cleanup
Remove the Order demo (entity/feature/repo/config/gRPC/proto) and the three pre-marketplace migrations; regenerate a fresh InitialBaseline migration. Stand up the REST surface (PingController + System/Ping CQRS) proving the Mediator -> behaviors -> OperationResult -> ApiResult envelope end to end. Close wiring gaps: register LoggingBehavior (outermost) and add the built-in rate limiter (per-IP global + otp/auth/sensitive policies), placed before authentication. Add current-user + audit plumbing: ICurrentUser (HttpContext + null impls), rename BaseEntity audit fields to CreatedAt/ModifiedAt (DateTimeOffset) + CreatedById/ModifiedById, stamped by a new AuditFieldInterceptor. Introduce five cross-cutting seams (IDateTimeProvider, IFieldEncryptor, ICacheService, IObjectStorage, INotificationDispatcher) with in-memory/local mocks registered via AddCrossCuttingSeams. Add Baya.Test.Foundation (encryptor, audit interceptor, ping handler) and update docs, contracts (swagger.v1.json), handoff, report, and mocks registry.
This commit is contained in:
+3
@@ -17,4 +17,7 @@
|
||||
<ProjectReference Include="..\Baya.Infrastructure.Identity\Baya.Infrastructure.Identity.csproj" />
|
||||
<ProjectReference Include="..\Baya.Infrastructure.Persistence\Baya.Infrastructure.Persistence.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
#nullable enable
|
||||
using Baya.Application.Contracts.Common;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Baya.Infrastructure.CrossCutting.Seams;
|
||||
|
||||
/// <summary>
|
||||
/// Local-disk implementation of <see cref="IObjectStorage"/> — the mock seam. Blobs are stored as
|
||||
/// files under a configured scratch root, keyed by an opaque storage key. The real implementation
|
||||
/// swaps to MinIO/S3/ArvanCloud (presigned URLs) behind the same interface.
|
||||
/// </summary>
|
||||
public sealed class LocalDiskObjectStorage : IObjectStorage
|
||||
{
|
||||
private readonly string _root;
|
||||
|
||||
public LocalDiskObjectStorage(IOptions<SeamOptions> options)
|
||||
{
|
||||
var configured = options.Value.ObjectStorage.RootPath;
|
||||
_root = string.IsNullOrWhiteSpace(configured)
|
||||
? Path.Combine(Path.GetTempPath(), "balinyaar-object-storage")
|
||||
: configured;
|
||||
|
||||
Directory.CreateDirectory(_root);
|
||||
}
|
||||
|
||||
public async ValueTask PutAsync(string key, Stream content, string contentType, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var path = ResolvePath(key);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path)!);
|
||||
|
||||
await using var file = File.Create(path);
|
||||
await content.CopyToAsync(file, cancellationToken);
|
||||
}
|
||||
|
||||
public ValueTask<Stream?> GetAsync(string key, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var path = ResolvePath(key);
|
||||
Stream? stream = File.Exists(path) ? File.OpenRead(path) : null;
|
||||
return ValueTask.FromResult(stream);
|
||||
}
|
||||
|
||||
public ValueTask DeleteAsync(string key, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var path = ResolvePath(key);
|
||||
if (File.Exists(path))
|
||||
File.Delete(path);
|
||||
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
public string GetUrl(string key) => new Uri(Path.Combine(_root, SanitizeKey(key))).AbsoluteUri;
|
||||
|
||||
private string ResolvePath(string key) => Path.Combine(_root, SanitizeKey(key));
|
||||
|
||||
// Keep the key from escaping the storage root; treat '/' as a folder separator only.
|
||||
private static string SanitizeKey(string key)
|
||||
{
|
||||
var normalized = key.Replace('\\', '/').TrimStart('/');
|
||||
var segments = normalized.Split('/', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Where(s => s != "." && s != "..");
|
||||
return Path.Combine([.. segments]);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
using Baya.Application.Contracts.Common;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Baya.Infrastructure.CrossCutting.Seams;
|
||||
|
||||
/// <summary>
|
||||
/// No-op implementation of <see cref="INotificationDispatcher"/> — the mock seam. It logs that a
|
||||
/// notification would be sent (no PII in the log). The real in-app write lands in backend-phase-15,
|
||||
/// with SMS/push channels added behind the same interface.
|
||||
/// </summary>
|
||||
public sealed class LogNotificationDispatcher(ILogger<LogNotificationDispatcher> logger) : INotificationDispatcher
|
||||
{
|
||||
public ValueTask DispatchAsync(Notification notification, CancellationToken cancellationToken = default)
|
||||
{
|
||||
logger.LogInformation(
|
||||
"Notification suppressed (mock dispatcher): channel {Channel} to user {UserId}",
|
||||
notification.Channel,
|
||||
notification.RecipientUserId);
|
||||
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
#nullable enable
|
||||
using Baya.Application.Contracts.Common;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
|
||||
namespace Baya.Infrastructure.CrossCutting.Seams;
|
||||
|
||||
/// <summary>
|
||||
/// In-process <see cref="IMemoryCache"/> implementation of <see cref="ICacheService"/> — the mock seam.
|
||||
/// The real implementation swaps to Redis (StackExchange.Redis) while keeping the same key/TTL scheme.
|
||||
/// </summary>
|
||||
public sealed class MemoryCacheService(IMemoryCache cache) : ICacheService
|
||||
{
|
||||
public ValueTask<T?> GetAsync<T>(string key, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return ValueTask.FromResult(cache.TryGetValue(key, out T? value) ? value : default);
|
||||
}
|
||||
|
||||
public ValueTask SetAsync<T>(string key, T value, TimeSpan? ttl = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = new MemoryCacheEntryOptions();
|
||||
if (ttl is { } expiry)
|
||||
options.AbsoluteExpirationRelativeToNow = expiry;
|
||||
|
||||
cache.Set(key, value, options);
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
public ValueTask RemoveAsync(string key, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cache.Remove(key);
|
||||
return ValueTask.CompletedTask;
|
||||
}
|
||||
|
||||
public async ValueTask<T> GetOrCreateAsync<T>(
|
||||
string key,
|
||||
Func<CancellationToken, ValueTask<T>> factory,
|
||||
TimeSpan? ttl = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (cache.TryGetValue(key, out T? cached) && cached is not null)
|
||||
return cached;
|
||||
|
||||
var value = await factory(cancellationToken);
|
||||
await SetAsync(key, value, ttl, cancellationToken);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace Baya.Infrastructure.CrossCutting.Seams;
|
||||
|
||||
/// <summary>
|
||||
/// Options bound from the <c>Seams</c> configuration section. The mock seams read non-secret defaults
|
||||
/// from here; production keys/paths come from environment variables or user-secrets, never committed.
|
||||
/// </summary>
|
||||
public sealed class SeamOptions
|
||||
{
|
||||
public const string SectionName = "Seams";
|
||||
|
||||
public FieldEncryptionOptions FieldEncryption { get; set; } = new();
|
||||
public ObjectStorageOptions ObjectStorage { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class FieldEncryptionOptions
|
||||
{
|
||||
/// <summary>Base64 32-byte AES key. Local-dev default only; override per environment.</summary>
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Base64 HMAC key used for deterministic lookup hashes.</summary>
|
||||
public string HashKey { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class ObjectStorageOptions
|
||||
{
|
||||
/// <summary>Filesystem root the local-disk mock writes blobs under.</summary>
|
||||
public string RootPath { get; set; } = string.Empty;
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Baya.Application.Contracts.Common;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Baya.Infrastructure.CrossCutting.Seams;
|
||||
|
||||
/// <summary>
|
||||
/// Local symmetric-key implementation of <see cref="IFieldEncryptor"/> — AES-256-CBC with a random
|
||||
/// per-value IV (prepended to the ciphertext) for at-rest reversibility, and a keyed HMAC-SHA256 for
|
||||
/// deterministic lookup hashes. This is the mock seam: the real implementation swaps to a KMS / Key
|
||||
/// Vault provider behind the same interface. Plaintext is never logged.
|
||||
/// </summary>
|
||||
public sealed class SymmetricFieldEncryptor : IFieldEncryptor
|
||||
{
|
||||
private readonly byte[] _key;
|
||||
private readonly byte[] _hashKey;
|
||||
|
||||
public SymmetricFieldEncryptor(IOptions<SeamOptions> options)
|
||||
{
|
||||
var settings = options.Value.FieldEncryption;
|
||||
|
||||
// Derive a stable 32-byte AES key from whatever the operator configured (any length/format),
|
||||
// so a human-friendly secret still yields a valid key. SHA-256 of the configured material.
|
||||
_key = SHA256.HashData(Encoding.UTF8.GetBytes(Require(settings.Key, nameof(settings.Key))));
|
||||
|
||||
var hashMaterial = string.IsNullOrEmpty(settings.HashKey) ? settings.Key : settings.HashKey;
|
||||
_hashKey = SHA256.HashData(Encoding.UTF8.GetBytes(Require(hashMaterial, nameof(settings.HashKey))));
|
||||
}
|
||||
|
||||
public string Encrypt(string plaintext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(plaintext))
|
||||
return plaintext;
|
||||
|
||||
using var aes = Aes.Create();
|
||||
aes.Key = _key;
|
||||
aes.GenerateIV();
|
||||
|
||||
using var encryptor = aes.CreateEncryptor();
|
||||
var plainBytes = Encoding.UTF8.GetBytes(plaintext);
|
||||
var cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
|
||||
|
||||
var result = new byte[aes.IV.Length + cipherBytes.Length];
|
||||
Buffer.BlockCopy(aes.IV, 0, result, 0, aes.IV.Length);
|
||||
Buffer.BlockCopy(cipherBytes, 0, result, aes.IV.Length, cipherBytes.Length);
|
||||
|
||||
return Convert.ToBase64String(result);
|
||||
}
|
||||
|
||||
public string Decrypt(string ciphertext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ciphertext))
|
||||
return ciphertext;
|
||||
|
||||
var cipherWithIv = Convert.FromBase64String(ciphertext);
|
||||
|
||||
using var aes = Aes.Create();
|
||||
aes.Key = _key;
|
||||
|
||||
var ivLength = aes.BlockSize / 8;
|
||||
var iv = new byte[ivLength];
|
||||
Buffer.BlockCopy(cipherWithIv, 0, iv, 0, ivLength);
|
||||
aes.IV = iv;
|
||||
|
||||
using var decryptor = aes.CreateDecryptor();
|
||||
var cipherBytes = decryptor.TransformFinalBlock(cipherWithIv, ivLength, cipherWithIv.Length - ivLength);
|
||||
|
||||
return Encoding.UTF8.GetString(cipherBytes);
|
||||
}
|
||||
|
||||
public string Hash(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return value;
|
||||
|
||||
using var hmac = new HMACSHA256(_hashKey);
|
||||
var hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(value));
|
||||
return Convert.ToHexString(hashBytes);
|
||||
}
|
||||
|
||||
private static string Require(string value, string name) =>
|
||||
string.IsNullOrWhiteSpace(value)
|
||||
? throw new InvalidOperationException($"Seams:FieldEncryption:{name} must be configured.")
|
||||
: value;
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
using Baya.Application.Contracts.Common;
|
||||
|
||||
namespace Baya.Infrastructure.CrossCutting.Seams;
|
||||
|
||||
/// <summary>Real system clock. Tests substitute <see cref="IDateTimeProvider"/> to freeze time.</summary>
|
||||
public sealed class SystemDateTimeProvider : IDateTimeProvider
|
||||
{
|
||||
public DateTimeOffset UtcNow => DateTimeOffset.UtcNow;
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
using Baya.Application.Contracts.Common;
|
||||
using Baya.Infrastructure.CrossCutting.Seams;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Baya.Infrastructure.CrossCutting.ServiceConfiguration;
|
||||
|
||||
public static class ServiceCollectionExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Registers the cross-cutting seams (time, PII encryption, cache, object storage, notifications)
|
||||
/// with their in-memory/local mock implementations. Swapping in a real provider later is a
|
||||
/// registration change here — callers depend only on the Application contracts.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddCrossCuttingSeams(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.Configure<SeamOptions>(configuration.GetSection(SeamOptions.SectionName));
|
||||
|
||||
services.AddMemoryCache();
|
||||
|
||||
services.AddSingleton<IDateTimeProvider, SystemDateTimeProvider>();
|
||||
services.AddSingleton<IFieldEncryptor, SymmetricFieldEncryptor>();
|
||||
services.AddSingleton<ICacheService, MemoryCacheService>();
|
||||
services.AddSingleton<IObjectStorage, LocalDiskObjectStorage>();
|
||||
services.AddScoped<INotificationDispatcher, LogNotificationDispatcher>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#nullable enable
|
||||
using System.Security.Claims;
|
||||
using Baya.Application.Contracts.Common;
|
||||
using Baya.SharedKernel.Extensions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Baya.Infrastructure.Identity.Identity.CurrentUser;
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the current user from the active HTTP request's claims. When there is no request or no
|
||||
/// authenticated principal (background work, startup), all members report "no user".
|
||||
/// </summary>
|
||||
public sealed class HttpContextCurrentUser(IHttpContextAccessor httpContextAccessor) : ICurrentUser
|
||||
{
|
||||
private ClaimsPrincipal? Principal => httpContextAccessor.HttpContext?.User;
|
||||
|
||||
public int? UserId
|
||||
{
|
||||
get
|
||||
{
|
||||
var rawId = Principal?.Identity?.GetUserId();
|
||||
return rawId.HasValue() && int.TryParse(rawId, out var id) ? id : null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAuthenticated => Principal?.Identity?.IsAuthenticated ?? false;
|
||||
|
||||
public IReadOnlyList<string> Roles =>
|
||||
Principal?.FindAll(ClaimTypes.Role).Select(c => c.Value).ToArray() ?? [];
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
using Baya.Application.Contracts.Common;
|
||||
|
||||
namespace Baya.Infrastructure.Identity.Identity.CurrentUser;
|
||||
|
||||
/// <summary>
|
||||
/// Null-object <see cref="ICurrentUser"/> for non-HTTP contexts (background jobs, tests) — reports an
|
||||
/// unauthenticated caller so audit stamping leaves the user fields null rather than failing.
|
||||
/// </summary>
|
||||
public sealed class NullCurrentUser : ICurrentUser
|
||||
{
|
||||
public int? UserId => null;
|
||||
|
||||
public bool IsAuthenticated => false;
|
||||
|
||||
public IReadOnlyList<string> Roles => [];
|
||||
}
|
||||
+5
@@ -1,10 +1,12 @@
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Baya.Application.Contracts;
|
||||
using Baya.Application.Contracts.Common;
|
||||
using Baya.Application.Contracts.Identity;
|
||||
using Baya.Application.Models.ApiResult;
|
||||
using Baya.Domain.Entities.User;
|
||||
using Baya.Infrastructure.Identity.Identity;
|
||||
using Baya.Infrastructure.Identity.Identity.CurrentUser;
|
||||
using Baya.Infrastructure.Identity.Identity.Dtos;
|
||||
using Baya.Infrastructure.Identity.Identity.Extensions;
|
||||
using Baya.Infrastructure.Identity.Identity.Manager;
|
||||
@@ -29,6 +31,9 @@ public static class ServiceCollectionExtension
|
||||
{
|
||||
public static IServiceCollection RegisterIdentityServices(this IServiceCollection services,IdentitySettings identitySettings)
|
||||
{
|
||||
services.AddHttpContextAccessor();
|
||||
services.AddScoped<ICurrentUser, HttpContextCurrentUser>();
|
||||
|
||||
services.AddScoped<IJwtService, JwtService>();
|
||||
services.AddScoped<IAppUserManager, AppUserManagerImplementation>();
|
||||
services.AddScoped<ISeedDataBase, SeedDataBase>();
|
||||
|
||||
@@ -18,7 +18,6 @@ public class ApplicationDbContext: IdentityDbContext<User, Role, int, UserClaim,
|
||||
private void OnSavingChanges(object sender, SavingChangesEventArgs e)
|
||||
{
|
||||
_cleanString();
|
||||
ConfigureEntityDates();
|
||||
}
|
||||
|
||||
private void _cleanString()
|
||||
@@ -62,30 +61,4 @@ public class ApplicationDbContext: IdentityDbContext<User, Role, int, UserClaim,
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void ConfigureEntityDates()
|
||||
{
|
||||
var updatedEntities = ChangeTracker.Entries().Where(x =>
|
||||
x.Entity is ITimeModification && x.State == EntityState.Modified).Select(x => x.Entity as ITimeModification);
|
||||
|
||||
var addedEntities = ChangeTracker.Entries().Where(x =>
|
||||
x.Entity is ITimeModification && x.State == EntityState.Added).Select(x => x.Entity as ITimeModification);
|
||||
|
||||
foreach (var entity in updatedEntities)
|
||||
{
|
||||
if (entity != null)
|
||||
{
|
||||
entity.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entity in addedEntities)
|
||||
{
|
||||
if (entity != null)
|
||||
{
|
||||
entity.CreatedTime = DateTime.Now;
|
||||
entity.ModifiedDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
using Baya.Domain.Entities.Order;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace Baya.Infrastructure.Persistence.Configuration.OrderConfig;
|
||||
|
||||
internal class OrderConfig:IEntityTypeConfiguration<Order>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Order> builder)
|
||||
{
|
||||
builder.HasOne(c => c.User).WithMany(c => c.Orders).HasForeignKey(c => c.UserId);
|
||||
|
||||
builder.HasQueryFilter(c => !c.IsDeleted);
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
#nullable enable
|
||||
using Baya.Application.Contracts.Common;
|
||||
using Baya.Domain.Common;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
|
||||
namespace Baya.Infrastructure.Persistence.Interceptors;
|
||||
|
||||
/// <summary>
|
||||
/// Stamps audit fields on every save: <c>CreatedAt</c>/<c>CreatedById</c> on insert and
|
||||
/// <c>ModifiedAt</c>/<c>ModifiedById</c> on update, sourcing time from <see cref="IDateTimeProvider"/>
|
||||
/// and the acting user from <see cref="ICurrentUser"/>. Handlers never set these fields.
|
||||
/// This is the extension point backend-phase-1 builds on to also write append-only audit-log rows.
|
||||
/// </summary>
|
||||
public sealed class AuditFieldInterceptor(ICurrentUser currentUser, IDateTimeProvider dateTimeProvider)
|
||||
: SaveChangesInterceptor
|
||||
{
|
||||
public override InterceptionResult<int> SavingChanges(
|
||||
DbContextEventData eventData,
|
||||
InterceptionResult<int> result)
|
||||
{
|
||||
Stamp(eventData.Context);
|
||||
return base.SavingChanges(eventData, result);
|
||||
}
|
||||
|
||||
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
|
||||
DbContextEventData eventData,
|
||||
InterceptionResult<int> result,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
Stamp(eventData.Context);
|
||||
return base.SavingChangesAsync(eventData, result, cancellationToken);
|
||||
}
|
||||
|
||||
private void Stamp(DbContext? context)
|
||||
{
|
||||
if (context is null)
|
||||
return;
|
||||
|
||||
var now = dateTimeProvider.UtcNow;
|
||||
var userId = currentUser.UserId;
|
||||
|
||||
foreach (var entry in context.ChangeTracker.Entries<ITimeModification>())
|
||||
{
|
||||
switch (entry.State)
|
||||
{
|
||||
case EntityState.Added:
|
||||
entry.Entity.CreatedAt = now;
|
||||
entry.Entity.ModifiedAt = now;
|
||||
if (entry.Entity is IAuditableEntity addedAuditable)
|
||||
{
|
||||
addedAuditable.CreatedById = userId;
|
||||
addedAuditable.ModifiedById = userId;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EntityState.Modified:
|
||||
entry.Entity.ModifiedAt = now;
|
||||
if (entry.Entity is IAuditableEntity modifiedAuditable)
|
||||
modifiedAuditable.ModifiedById = userId;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
server/src/Infrastructure/Baya.Infrastructure.Persistence/Migrations/20210327210004_Init.Designer.cs
Generated
-374
@@ -1,374 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Baya.Infrastructure.Persistence;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Persistence;
|
||||
|
||||
namespace Persistence.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20210327210004_Init")]
|
||||
partial class Init
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseIdentityColumns()
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128)
|
||||
.HasAnnotation("ProductVersion", "5.0.0");
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.Role", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.UseIdentityColumn();
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreatedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("Roles", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.RoleClaim", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.UseIdentityColumn();
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreatedClaim")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("RoleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("RoleClaims", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("UserId")
|
||||
.UseIdentityColumn();
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("FamilyName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("GeneratedCode")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("datetimeoffset");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("Users", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserClaim", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.UseIdentityColumn();
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("UserClaims", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserLogin", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<DateTime>("LoggedOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("UserLogins", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserRefreshToken", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("CreatedTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsValid")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("ModifiedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("UserRefreshTokens", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserRole", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("RoleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedUserRoleDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("UserRoles", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserToken", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<DateTime>("GeneratedTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("UserTokens", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.RoleClaim", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.Role", "Role")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Role");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserClaim", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserLogin", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserRefreshToken", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("UserRefreshTokens")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserRole", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.Role", "Role")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("UserRoles")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Role");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserToken", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("Tokens")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.Role", b =>
|
||||
{
|
||||
b.Navigation("Claims");
|
||||
|
||||
b.Navigation("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.User", b =>
|
||||
{
|
||||
b.Navigation("Claims");
|
||||
|
||||
b.Navigation("Logins");
|
||||
|
||||
b.Navigation("Tokens");
|
||||
|
||||
b.Navigation("UserRefreshTokens");
|
||||
|
||||
b.Navigation("UserRoles");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
-422
@@ -1,422 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Baya.Infrastructure.Persistence;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Persistence;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Persistence.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20221205084354_AddedOrderAndUserRelation")]
|
||||
partial class AddedOrderAndUserRelation
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.Order.Order", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ModifiedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("OrderName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Orders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.Role", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreatedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("DisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex")
|
||||
.HasFilter("[NormalizedName] IS NOT NULL");
|
||||
|
||||
b.ToTable("Roles", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.RoleClaim", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("CreatedClaim")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("RoleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("RoleClaims", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int")
|
||||
.HasColumnName("UserId");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("FamilyName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("GeneratedCode")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("datetimeoffset");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("nvarchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex")
|
||||
.HasFilter("[NormalizedUserName] IS NOT NULL");
|
||||
|
||||
b.ToTable("Users", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserClaim", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("UserClaims", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserLogin", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<DateTime>("LoggedOn")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("UserLogins", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserRefreshToken", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("CreatedTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsValid")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("ModifiedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("UserRefreshTokens", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserRole", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("RoleId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedUserRoleDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("UserRoles", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserToken", b =>
|
||||
{
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<DateTime>("GeneratedTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("UserTokens", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.Order.Order", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("Orders")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.RoleClaim", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.Role", "Role")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Role");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserClaim", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("Claims")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserLogin", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserRefreshToken", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("UserRefreshTokens")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserRole", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.Role", "Role")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("UserRoles")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Role");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.UserToken", b =>
|
||||
{
|
||||
b.HasOne("Domain.Entities.User.User", "User")
|
||||
.WithMany("Tokens")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.Role", b =>
|
||||
{
|
||||
b.Navigation("Claims");
|
||||
|
||||
b.Navigation("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Domain.Entities.User.User", b =>
|
||||
{
|
||||
b.Navigation("Claims");
|
||||
|
||||
b.Navigation("Logins");
|
||||
|
||||
b.Navigation("Orders");
|
||||
|
||||
b.Navigation("Tokens");
|
||||
|
||||
b.Navigation("UserRefreshTokens");
|
||||
|
||||
b.Navigation("UserRoles");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Persistence.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedOrderAndUserRelation : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Orders",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("SqlServer:Identity", "1, 1"),
|
||||
OrderName = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
UserId = table.Column<int>(type: "int", nullable: false),
|
||||
CreatedTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ModifiedDate = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Orders", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Orders_Users_UserId",
|
||||
column: x => x.UserId,
|
||||
principalSchema: "usr",
|
||||
principalTable: "Users",
|
||||
principalColumn: "UserId",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Orders_UserId",
|
||||
table: "Orders",
|
||||
column: "UserId");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Orders");
|
||||
}
|
||||
}
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Persistence.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedOrderDeleteFlag : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "IsDeleted",
|
||||
table: "Orders",
|
||||
type: "bit",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IsDeleted",
|
||||
table: "Orders");
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-53
@@ -9,52 +9,22 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Persistence.Migrations
|
||||
namespace Baya.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20231126140035_AddedOrderDeleteFlag")]
|
||||
partial class AddedOrderDeleteFlag
|
||||
[Migration("20260628191947_InitialBaseline")]
|
||||
partial class InitialBaseline
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.0")
|
||||
.HasAnnotation("ProductVersion", "10.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Baya.Domain.Entities.Order.Order", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("ModifiedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("OrderName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Orders");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Baya.Domain.Entities.User.Role", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -250,17 +220,20 @@ namespace Persistence.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.HasColumnType("datetimeoffset");
|
||||
|
||||
b.Property<DateTime>("CreatedTime")
|
||||
.HasColumnType("datetime2");
|
||||
b.Property<int?>("CreatedById")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("IsValid")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("ModifiedDate")
|
||||
.HasColumnType("datetime2");
|
||||
b.Property<DateTimeOffset?>("ModifiedAt")
|
||||
.HasColumnType("datetimeoffset");
|
||||
|
||||
b.Property<int?>("ModifiedById")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
@@ -312,17 +285,6 @@ namespace Persistence.Migrations
|
||||
b.ToTable("UserTokens", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Baya.Domain.Entities.Order.Order", b =>
|
||||
{
|
||||
b.HasOne("Baya.Domain.Entities.User.User", "User")
|
||||
.WithMany("Orders")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Baya.Domain.Entities.User.RoleClaim", b =>
|
||||
{
|
||||
b.HasOne("Baya.Domain.Entities.User.Role", "Role")
|
||||
@@ -410,8 +372,6 @@ namespace Persistence.Migrations
|
||||
|
||||
b.Navigation("Logins");
|
||||
|
||||
b.Navigation("Orders");
|
||||
|
||||
b.Navigation("Tokens");
|
||||
|
||||
b.Navigation("UserRefreshTokens");
|
||||
+11
-5
@@ -1,10 +1,14 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Persistence.Migrations
|
||||
#nullable disable
|
||||
|
||||
namespace Baya.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
public partial class Init : Migration
|
||||
/// <inheritdoc />
|
||||
public partial class InitialBaseline : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.EnsureSchema(
|
||||
@@ -135,10 +139,11 @@ namespace Persistence.Migrations
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
UserId = table.Column<int>(type: "int", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
IsValid = table.Column<bool>(type: "bit", nullable: false),
|
||||
CreatedTime = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ModifiedDate = table.Column<DateTime>(type: "datetime2", nullable: true)
|
||||
CreatedAt = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: false),
|
||||
ModifiedAt = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
|
||||
CreatedById = table.Column<int>(type: "int", nullable: true),
|
||||
ModifiedById = table.Column<int>(type: "int", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
@@ -256,6 +261,7 @@ namespace Persistence.Migrations
|
||||
filter: "[NormalizedUserName] IS NOT NULL");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
+11
-51
@@ -8,7 +8,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Persistence.Migrations
|
||||
namespace Baya.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||
@@ -17,41 +17,11 @@ namespace Persistence.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.0")
|
||||
.HasAnnotation("ProductVersion", "10.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Baya.Domain.Entities.Order.Order", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime>("CreatedTime")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<bool>("IsDeleted")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("ModifiedDate")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("OrderName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Orders", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Baya.Domain.Entities.User.Role", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -247,17 +217,20 @@ namespace Persistence.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
b.Property<DateTimeOffset>("CreatedAt")
|
||||
.HasColumnType("datetimeoffset");
|
||||
|
||||
b.Property<DateTime>("CreatedTime")
|
||||
.HasColumnType("datetime2");
|
||||
b.Property<int?>("CreatedById")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("IsValid")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("ModifiedDate")
|
||||
.HasColumnType("datetime2");
|
||||
b.Property<DateTimeOffset?>("ModifiedAt")
|
||||
.HasColumnType("datetimeoffset");
|
||||
|
||||
b.Property<int?>("ModifiedById")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("int");
|
||||
@@ -309,17 +282,6 @@ namespace Persistence.Migrations
|
||||
b.ToTable("UserTokens", "usr");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Baya.Domain.Entities.Order.Order", b =>
|
||||
{
|
||||
b.HasOne("Baya.Domain.Entities.User.User", "User")
|
||||
.WithMany("Orders")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Baya.Domain.Entities.User.RoleClaim", b =>
|
||||
{
|
||||
b.HasOne("Baya.Domain.Entities.User.Role", "Role")
|
||||
@@ -407,8 +369,6 @@ namespace Persistence.Migrations
|
||||
|
||||
b.Navigation("Logins");
|
||||
|
||||
b.Navigation("Orders");
|
||||
|
||||
b.Navigation("Tokens");
|
||||
|
||||
b.Navigation("UserRefreshTokens");
|
||||
|
||||
-2
@@ -7,13 +7,11 @@ public class UnitOfWork : IUnitOfWork
|
||||
private readonly ApplicationDbContext _db;
|
||||
|
||||
public IUserRefreshTokenRepository UserRefreshTokenRepository { get; }
|
||||
public IOrderRepository OrderRepository { get; }
|
||||
|
||||
public UnitOfWork(ApplicationDbContext db)
|
||||
{
|
||||
_db = db;
|
||||
UserRefreshTokenRepository = new UserRefreshTokenRepository(_db);
|
||||
OrderRepository= new OrderRepository(_db);
|
||||
}
|
||||
|
||||
public Task CommitAsync()
|
||||
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
using Baya.Application.Contracts.Persistence;
|
||||
using Baya.Domain.Entities.Order;
|
||||
using Baya.Infrastructure.Persistence.Repositories.Common;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Baya.Infrastructure.Persistence.Repositories;
|
||||
|
||||
internal class OrderRepository(ApplicationDbContext dbContext) : BaseAsyncRepository<Order>(dbContext), IOrderRepository
|
||||
{
|
||||
public async Task AddOrderAsync(Order order)
|
||||
{
|
||||
await base.AddAsync(order);
|
||||
}
|
||||
|
||||
public async Task<List<Order>> GetAllUserOrdersAsync(int userId)
|
||||
{
|
||||
return await base.TableNoTracking.Where(c => c.UserId == userId).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<Order>> GetAllOrdersWithRelatedUserAsync()
|
||||
{
|
||||
var orders = await base.TableNoTracking.Include(c => c.User).ToListAsync();
|
||||
|
||||
return orders;
|
||||
}
|
||||
|
||||
public async Task<Order> GetUserOrderByIdAndUserIdAsync(int userId, int orderId,bool trackEntity)
|
||||
{
|
||||
var order = await base.TableNoTracking.FirstOrDefaultAsync(c => c.UserId == userId && c.Id == orderId);
|
||||
|
||||
if (order is not null && trackEntity)
|
||||
base.DbContext.Attach(order);
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
public async Task DeleteUserOrdersAsync(int userId)
|
||||
{
|
||||
await UpdateAsync(c => c.UserId == userId, p => p.SetProperty(order => order.IsDeleted, true));
|
||||
}
|
||||
}
|
||||
+6
-2
@@ -1,4 +1,5 @@
|
||||
using Baya.Application.Contracts.Persistence;
|
||||
using Baya.Infrastructure.Persistence.Interceptors;
|
||||
using Baya.Infrastructure.Persistence.Repositories.Common;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -13,10 +14,13 @@ public static class ServiceCollectionExtensions
|
||||
{
|
||||
services.AddScoped<IUnitOfWork, UnitOfWork>();
|
||||
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
services.AddScoped<AuditFieldInterceptor>();
|
||||
|
||||
services.AddDbContext<ApplicationDbContext>((serviceProvider, options) =>
|
||||
{
|
||||
options
|
||||
.UseSqlServer(configuration.GetConnectionString("SqlServer"));
|
||||
.UseSqlServer(configuration.GetConnectionString("SqlServer"))
|
||||
.AddInterceptors(serviceProvider.GetRequiredService<AuditFieldInterceptor>());
|
||||
});
|
||||
|
||||
return services;
|
||||
|
||||
Reference in New Issue
Block a user