This commit is contained in:
Fergal Moran
2024-03-23 17:45:36 +00:00
parent 4cfa7d5385
commit 24826c551b
12 changed files with 522 additions and 367 deletions

View File

@@ -1,5 +1,6 @@
using System.Security.Claims; using System.Security.Claims;
using Humanizer; using Humanizer;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using TvNoms.Core.Entities; using TvNoms.Core.Entities;
@@ -13,6 +14,7 @@ using TvNoms.Server.Services;
namespace TvNoms.Server.ApiService.Endpoints; namespace TvNoms.Server.ApiService.Endpoints;
[EnableCors("WebAppCors")]
public class UserEndpoints : Shared.Endpoints { public class UserEndpoints : Shared.Endpoints {
public UserEndpoints(IEndpointRouteBuilder endpointRouteBuilder) public UserEndpoints(IEndpointRouteBuilder endpointRouteBuilder)
: base(endpointRouteBuilder) { : base(endpointRouteBuilder) {
@@ -59,10 +61,12 @@ public class UserEndpoints : Shared.Endpoints {
return Results.Ok(); return Results.Ok();
} }
[EnableCors("WebAppCors")]
public async Task<IResult> SignInAsync([FromServices] IUserService userService, [FromBody] SignInForm form) { public async Task<IResult> SignInAsync([FromServices] IUserService userService, [FromBody] SignInForm form) {
return Results.Ok(await userService.SignInAsync(form)); return Results.Ok(await userService.SignInAsync(form));
} }
[EnableCors("WebAppCors")]
public async Task<IResult> SignInWithAsync( public async Task<IResult> SignInWithAsync(
[FromServices] IUserService userService, [FromServices] IUserService userService,
[FromServices] SignInManager<User> signInManager, [FromServices] SignInManager<User> signInManager,
@@ -99,6 +103,7 @@ public class UserEndpoints : Shared.Endpoints {
return Results.Ok(await userService.SignInWithAsync(form)); return Results.Ok(await userService.SignInWithAsync(form));
} }
[EnableCors("WebAppCors")]
public IResult SignInWithRedirectAsync( public IResult SignInWithRedirectAsync(
[FromServices] SignInManager<User> signInManager, [FromServices] SignInManager<User> signInManager,
[FromServices] IConfiguration configuration, [FromServices] IConfiguration configuration,

View File

@@ -1,10 +1,14 @@
using System.Net; using System.Net;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authentication.Google; using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Serilog;
using Serilog.Settings.Configuration;
using server.ServiceDefaults; using server.ServiceDefaults;
using TvNoms.Core.Entities; using TvNoms.Core.Entities;
using TvNoms.Core.Models; using TvNoms.Core.Models;
@@ -21,6 +25,19 @@ using TvNoms.Server.Data.Repositories;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
var assemblies = AssemblyHelper.GetAssemblies().ToArray(); var assemblies = AssemblyHelper.GetAssemblies().ToArray();
Log.Logger = new LoggerConfiguration()
.ReadFrom
.Configuration(
builder.Configuration,
new ConfigurationReaderOptions { SectionName = "SerilogOptions" })
.Enrich
.FromLogContext()
.CreateLogger();
builder.Logging.ClearProviders();
builder.Host.UseSerilog(Log.Logger);
// Add service defaults & Aspire components. // Add service defaults & Aspire components.
builder.AddServiceDefaults(); builder.AddServiceDefaults();
@@ -118,7 +135,23 @@ builder.Services.AddLocalFileStorage(options => {
options.WebRootPath = "/uploads"; options.WebRootPath = "/uploads";
}); });
builder.Services.AddDocumentations(); builder.Services.AddDocumentations();
builder.Services.AddWebAppCors(); builder.Services.AddWebAppCors(builder.Configuration);
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
builder.Services.ConfigureHttpJsonOptions(options => {
options.SerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase;
options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
options.SerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
options.SerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
options.SerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
var app = builder.Build(); var app = builder.Build();

View File

@@ -23,6 +23,11 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup> </ItemGroup>

View File

@@ -18,12 +18,13 @@
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"AllowedOrigins": [ "AllowedOrigins": [
"https://tvnoms.dev.fergl.ie:3000" "https://tvnoms.dev.fergl.ie:3000",
"http://localhost:3000"
], ],
"BearerAuthOptions": { "BearerAuthOptions": {
"Secret": null, "Secret": null,
"Issuer": null, "Issuer": null,
"Audience": "https://tvnoms.dev.fergl.ie:5001", "Audience": "https://tvnoms.dev.fergl.ie:3000",
"AccessTokenExpiresIn": "60.00:00:00", "AccessTokenExpiresIn": "60.00:00:00",
"RefreshTokenExpiresIn": "60.00:00:00", "RefreshTokenExpiresIn": "60.00:00:00",
"AllowMultipleSessions": true "AllowMultipleSessions": true

View File

@@ -1,9 +1,51 @@
{ {
"Logging": { "SerilogOptions": {
"LogLevel": { "Using": [
"Default": "Information", "Serilog.Sinks.Console",
"Microsoft.AspNetCore": "Warning" "Serilog.Sinks.File"
} ],
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Debug",
"Microsoft.AspNetCore": "Debug",
"System": "Debug"
}
},
"Enrich": [
"FromLogContext",
"WithMachineName",
"WithThreadId"
],
"WriteTo": [
{
"Name": "Console",
"Args": {
"theme": "Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme::Sixteen, Serilog.Sinks.Console",
"outputTemplate": "{Timestamp:HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
}
},
{
"Name": "File",
"Args": {
"path": "/tmp/tvnoms/logs/info-.txt",
"outputTemplate": "{Timestamp:HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"restrictedToMinimumLevel": "Information"
}
},
{
"Name": "File",
"Args": {
"path": "/tmp/tvnoms/logs/error-.txt",
"outputTemplate": "{Timestamp:HH:mm:ss} [{Level:u3}] {Message:lj}{NewLine}{Exception}",
"rollingInterval": "Day",
"retainedFileCountLimit": 7,
"restrictedToMinimumLevel": "Error"
}
}
]
}, },
"AllowedHosts": "*" "AllowedHosts": "*"
} }

View File

@@ -7,7 +7,7 @@ public interface IEntity {
Guid Id { get; } Guid Id { get; }
} }
public class BaseEntity : IEntity { public abstract class BaseEntity : IEntity {
[Key] [Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; } public Guid Id { get; set; }

View File

@@ -3,8 +3,6 @@ using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using TvNoms.Core.Entities; using TvNoms.Core.Entities;
using TvNoms.Core.Utilities;
using TvNoms.Server.Data.Extensions;
namespace TvNoms.Server.Data; namespace TvNoms.Server.Data;
@@ -13,18 +11,19 @@ public class AppDbContext(IConfiguration configuration) :
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
optionsBuilder.UseNpgsql(configuration.GetConnectionString("DefaultConnection")); optionsBuilder.UseNpgsql(configuration.GetConnectionString("DefaultConnection"));
protected override void OnModelCreating(ModelBuilder builder) { // protected override void OnModelCreating(ModelBuilder builder) {
base.OnModelCreating(builder); // base.OnModelCreating(builder);
var assemblies = AssemblyHelper.GetAssemblies(); // var assemblies = AssemblyHelper.GetAssemblies();
//
// builder.ApplyEntities(assemblies);
// builder.ApplyConfigurations(assemblies);
// }
builder.ApplyEntities(assemblies); public DbSet<User> Users { get; set; }
builder.ApplyConfigurations(assemblies); public DbSet<UserSession> UserSessions { get; set; }
} public DbSet<Role> Roles { get; set; }
public DbSet<Client> Clients { get; set; }
// public DbSet<User> Users { get; set; } public DbSet<Show> Shows { get; set; }
// public DbSet<UserRole> UserRoles { get; set; } public DbSet<Movie> Movies { get; set; }
// public DbSet<Client> Clients { get; set; } public DbSet<Media> Media { get; set; }
// public DbSet<Show> Shows { get; set; }
// public DbSet<Movie> Movies { get; set; }
// public DbSet<Media> Media { get; set; }
} }

View File

@@ -12,7 +12,8 @@ public static class DbContextExtensions {
.SelectMany(_ => _.DefinedTypes) .SelectMany(_ => _.DefinedTypes)
.Select(_ => _.AsType()) .Select(_ => _.AsType())
.Where(type => type is { IsClass: true, IsAbstract: false, IsGenericType: false } && .Where(type => type is { IsClass: true, IsAbstract: false, IsGenericType: false } &&
type.IsCompatibleWith(typeof(IEntity)) && (predicate?.Invoke(type) ?? true)); (type.IsCompatibleWith(typeof(IEntity)) || type is BaseEntity) &&
(predicate?.Invoke(type) ?? true));
foreach (var entityType in entityTypes) { foreach (var entityType in entityTypes) {
modelBuilder.Entity(entityType); modelBuilder.Entity(entityType);

View File

@@ -12,7 +12,7 @@ using TvNoms.Server.Data;
namespace TvNoms.Server.Data.Migrations namespace TvNoms.Server.Data.Migrations
{ {
[DbContext(typeof(AppDbContext))] [DbContext(typeof(AppDbContext))]
[Migration("20240322200711_Initial")] [Migration("20240322213634_Initial")]
partial class Initial partial class Initial
{ {
/// <inheritdoc /> /// <inheritdoc />
@@ -164,7 +164,99 @@ namespace TvNoms.Server.Data.Migrations
b.ToTable("AspNetUserTokens", (string)null); b.ToTable("AspNetUserTokens", (string)null);
}); });
modelBuilder.Entity("TvNoms.Core.Entities.BaseEntity", b => modelBuilder.Entity("TvNoms.Core.Entities.Client", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Active")
.HasColumnType("boolean");
b.Property<string>("ConnectionId")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("ConnectionTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateCreated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateUpdated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<string>("DeviceId")
.HasColumnType("text");
b.Property<string>("IpAddress")
.HasColumnType("text");
b.Property<string>("UserAgent")
.HasColumnType("text");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Clients");
});
modelBuilder.Entity("TvNoms.Core.Entities.Media", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("ContentType")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateCreated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateUpdated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<int?>("Height")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Path")
.IsRequired()
.HasColumnType("text");
b.Property<long>("Size")
.HasColumnType("bigint");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.Property<int?>("Width")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("Media");
});
modelBuilder.Entity("TvNoms.Core.Entities.Movie", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -178,18 +270,36 @@ namespace TvNoms.Server.Data.Migrations
.ValueGeneratedOnAddOrUpdate() .ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
b.Property<string>("Discriminator") b.Property<string>("Title")
.IsRequired() .IsRequired()
.HasMaxLength(13) .HasColumnType("text");
.HasColumnType("character varying(13)");
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("BaseEntity"); b.ToTable("Movies");
});
b.HasDiscriminator<string>("Discriminator").HasValue("BaseEntity"); modelBuilder.Entity("TvNoms.Core.Entities.Show", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.UseTphMappingStrategy(); b.Property<DateTime>("DateCreated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateUpdated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Shows");
}); });
modelBuilder.Entity("TvNoms.Core.Entities.User", b => modelBuilder.Entity("TvNoms.Core.Entities.User", b =>
@@ -315,7 +425,7 @@ namespace TvNoms.Server.Data.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("UserSession"); b.ToTable("UserSessions");
}); });
modelBuilder.Entity("TvNoms.Core.Entities.Role", b => modelBuilder.Entity("TvNoms.Core.Entities.Role", b =>
@@ -325,102 +435,6 @@ namespace TvNoms.Server.Data.Migrations
b.HasDiscriminator().HasValue("Role"); b.HasDiscriminator().HasValue("Role");
}); });
modelBuilder.Entity("TvNoms.Core.Entities.Client", b =>
{
b.HasBaseType("TvNoms.Core.Entities.BaseEntity");
b.Property<bool>("Active")
.HasColumnType("boolean");
b.Property<string>("ConnectionId")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("ConnectionTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("DeviceId")
.HasColumnType("text");
b.Property<string>("IpAddress")
.HasColumnType("text");
b.Property<string>("UserAgent")
.HasColumnType("text");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasIndex("UserId");
b.HasDiscriminator().HasValue("Client");
});
modelBuilder.Entity("TvNoms.Core.Entities.Media", b =>
{
b.HasBaseType("TvNoms.Core.Entities.BaseEntity");
b.Property<string>("ContentType")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<int?>("Height")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Path")
.IsRequired()
.HasColumnType("text");
b.Property<long>("Size")
.HasColumnType("bigint");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.Property<int?>("Width")
.HasColumnType("integer");
b.HasDiscriminator().HasValue("Media");
});
modelBuilder.Entity("TvNoms.Core.Entities.Movie", b =>
{
b.HasBaseType("TvNoms.Core.Entities.BaseEntity");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.HasDiscriminator().HasValue("Movie");
});
modelBuilder.Entity("TvNoms.Core.Entities.Show", b =>
{
b.HasBaseType("TvNoms.Core.Entities.BaseEntity");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.ToTable("BaseEntity", t =>
{
t.Property("Title")
.HasColumnName("Show_Title");
});
b.HasDiscriminator().HasValue("Show");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{ {
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<System.Guid>", null) b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<System.Guid>", null)
@@ -472,6 +486,15 @@ namespace TvNoms.Server.Data.Migrations
.IsRequired(); .IsRequired();
}); });
modelBuilder.Entity("TvNoms.Core.Entities.Client", b =>
{
b.HasOne("TvNoms.Core.Entities.User", "User")
.WithMany("Clients")
.HasForeignKey("UserId");
b.Navigation("User");
});
modelBuilder.Entity("TvNoms.Core.Entities.User", b => modelBuilder.Entity("TvNoms.Core.Entities.User", b =>
{ {
b.HasOne("TvNoms.Core.Entities.Media", "Avatar") b.HasOne("TvNoms.Core.Entities.Media", "Avatar")
@@ -492,15 +515,6 @@ namespace TvNoms.Server.Data.Migrations
b.Navigation("User"); b.Navigation("User");
}); });
modelBuilder.Entity("TvNoms.Core.Entities.Client", b =>
{
b.HasOne("TvNoms.Core.Entities.User", "User")
.WithMany("Clients")
.HasForeignKey("UserId");
b.Navigation("User");
});
modelBuilder.Entity("TvNoms.Core.Entities.User", b => modelBuilder.Entity("TvNoms.Core.Entities.User", b =>
{ {
b.Navigation("Clients"); b.Navigation("Clients");

View File

@@ -27,6 +27,56 @@ namespace TvNoms.Server.Data.Migrations
table.PrimaryKey("PK_AspNetRoles", x => x.Id); table.PrimaryKey("PK_AspNetRoles", x => x.Id);
}); });
migrationBuilder.CreateTable(
name: "Media",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Size = table.Column<long>(type: "bigint", nullable: false),
Path = table.Column<string>(type: "text", nullable: false),
ContentType = table.Column<string>(type: "text", nullable: false),
Type = table.Column<int>(type: "integer", nullable: false),
Width = table.Column<int>(type: "integer", nullable: true),
Height = table.Column<int>(type: "integer", nullable: true),
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DateUpdated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Media", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Movies",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Title = table.Column<string>(type: "text", nullable: false),
DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DateUpdated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Movies", x => x.Id);
});
migrationBuilder.CreateTable(
name: "Shows",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Title = table.Column<string>(type: "text", nullable: false),
DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
DateUpdated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Shows", x => x.Id);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "AspNetRoleClaims", name: "AspNetRoleClaims",
columns: table => new columns: table => new
@@ -48,53 +98,6 @@ namespace TvNoms.Server.Data.Migrations
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Cascade);
}); });
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
RoleId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "AspNetUsers", name: "AspNetUsers",
columns: table => new columns: table => new
@@ -127,6 +130,76 @@ namespace TvNoms.Server.Data.Migrations
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_AspNetUsers", x => x.Id); table.PrimaryKey("PK_AspNetUsers", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUsers_Media_AvatarId",
column: x => x.AvatarId,
principalTable: "Media",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "AspNetUserClaims",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
ClaimType = table.Column<string>(type: "text", nullable: true),
ClaimValue = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
table.ForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserLogins",
columns: table => new
{
LoginProvider = table.Column<string>(type: "text", nullable: false),
ProviderKey = table.Column<string>(type: "text", nullable: false),
ProviderDisplayName = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
table.ForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "AspNetUserRoles",
columns: table => new
{
UserId = table.Column<Guid>(type: "uuid", nullable: false),
RoleId = table.Column<Guid>(type: "uuid", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
column: x => x.RoleId,
principalTable: "AspNetRoles",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
column: x => x.UserId,
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
@@ -150,44 +223,32 @@ namespace TvNoms.Server.Data.Migrations
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "BaseEntity", name: "Clients",
columns: table => new columns: table => new
{ {
Id = table.Column<Guid>(type: "uuid", nullable: false), Id = table.Column<Guid>(type: "uuid", nullable: false),
DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), ConnectionId = table.Column<string>(type: "text", nullable: false),
DateUpdated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false), ConnectionTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: false),
Discriminator = table.Column<string>(type: "character varying(13)", maxLength: 13, nullable: false),
ConnectionId = table.Column<string>(type: "text", nullable: true),
ConnectionTime = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
IpAddress = table.Column<string>(type: "text", nullable: true), IpAddress = table.Column<string>(type: "text", nullable: true),
DeviceId = table.Column<string>(type: "text", nullable: true), DeviceId = table.Column<string>(type: "text", nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: true), UserId = table.Column<Guid>(type: "uuid", nullable: true),
UserAgent = table.Column<string>(type: "text", nullable: true), UserAgent = table.Column<string>(type: "text", nullable: true),
Active = table.Column<bool>(type: "boolean", nullable: true), Active = table.Column<bool>(type: "boolean", nullable: false),
Name = table.Column<string>(type: "text", nullable: true), DateCreated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Size = table.Column<long>(type: "bigint", nullable: true), DateUpdated = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
Path = table.Column<string>(type: "text", nullable: true),
ContentType = table.Column<string>(type: "text", nullable: true),
Type = table.Column<int>(type: "integer", nullable: true),
Width = table.Column<int>(type: "integer", nullable: true),
Height = table.Column<int>(type: "integer", nullable: true),
CreatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
UpdatedAt = table.Column<DateTimeOffset>(type: "timestamp with time zone", nullable: true),
Title = table.Column<string>(type: "text", nullable: true),
Show_Title = table.Column<string>(type: "text", nullable: true)
}, },
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_BaseEntity", x => x.Id); table.PrimaryKey("PK_Clients", x => x.Id);
table.ForeignKey( table.ForeignKey(
name: "FK_BaseEntity_AspNetUsers_UserId", name: "FK_Clients_AspNetUsers_UserId",
column: x => x.UserId, column: x => x.UserId,
principalTable: "AspNetUsers", principalTable: "AspNetUsers",
principalColumn: "Id"); principalColumn: "Id");
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "UserSession", name: "UserSessions",
columns: table => new columns: table => new
{ {
Id = table.Column<Guid>(type: "uuid", nullable: false), Id = table.Column<Guid>(type: "uuid", nullable: false),
@@ -199,9 +260,9 @@ namespace TvNoms.Server.Data.Migrations
}, },
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_UserSession", x => x.Id); table.PrimaryKey("PK_UserSessions", x => x.Id);
table.ForeignKey( table.ForeignKey(
name: "FK_UserSession_AspNetUsers_UserId", name: "FK_UserSessions_AspNetUsers_UserId",
column: x => x.UserId, column: x => x.UserId,
principalTable: "AspNetUsers", principalTable: "AspNetUsers",
principalColumn: "Id", principalColumn: "Id",
@@ -251,54 +312,19 @@ namespace TvNoms.Server.Data.Migrations
unique: true); unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_BaseEntity_UserId", name: "IX_Clients_UserId",
table: "BaseEntity", table: "Clients",
column: "UserId"); column: "UserId");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_UserSession_UserId", name: "IX_UserSessions_UserId",
table: "UserSession", table: "UserSessions",
column: "UserId"); column: "UserId");
migrationBuilder.AddForeignKey(
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
table: "AspNetUserClaims",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
table: "AspNetUserLogins",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
table: "AspNetUserRoles",
column: "UserId",
principalTable: "AspNetUsers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_AspNetUsers_BaseEntity_AvatarId",
table: "AspNetUsers",
column: "AvatarId",
principalTable: "BaseEntity",
principalColumn: "Id");
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.DropForeignKey(
name: "FK_BaseEntity_AspNetUsers_UserId",
table: "BaseEntity");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "AspNetRoleClaims"); name: "AspNetRoleClaims");
@@ -315,7 +341,16 @@ namespace TvNoms.Server.Data.Migrations
name: "AspNetUserTokens"); name: "AspNetUserTokens");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "UserSession"); name: "Clients");
migrationBuilder.DropTable(
name: "Movies");
migrationBuilder.DropTable(
name: "Shows");
migrationBuilder.DropTable(
name: "UserSessions");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "AspNetRoles"); name: "AspNetRoles");
@@ -324,7 +359,7 @@ namespace TvNoms.Server.Data.Migrations
name: "AspNetUsers"); name: "AspNetUsers");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "BaseEntity"); name: "Media");
} }
} }
} }

View File

@@ -161,7 +161,99 @@ namespace TvNoms.Server.Data.Migrations
b.ToTable("AspNetUserTokens", (string)null); b.ToTable("AspNetUserTokens", (string)null);
}); });
modelBuilder.Entity("TvNoms.Core.Entities.BaseEntity", b => modelBuilder.Entity("TvNoms.Core.Entities.Client", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("Active")
.HasColumnType("boolean");
b.Property<string>("ConnectionId")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("ConnectionTime")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateCreated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateUpdated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<string>("DeviceId")
.HasColumnType("text");
b.Property<string>("IpAddress")
.HasColumnType("text");
b.Property<string>("UserAgent")
.HasColumnType("text");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Clients");
});
modelBuilder.Entity("TvNoms.Core.Entities.Media", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("ContentType")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateCreated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateUpdated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<int?>("Height")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Path")
.IsRequired()
.HasColumnType("text");
b.Property<long>("Size")
.HasColumnType("bigint");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.Property<int?>("Width")
.HasColumnType("integer");
b.HasKey("Id");
b.ToTable("Media");
});
modelBuilder.Entity("TvNoms.Core.Entities.Movie", b =>
{ {
b.Property<Guid>("Id") b.Property<Guid>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
@@ -175,18 +267,36 @@ namespace TvNoms.Server.Data.Migrations
.ValueGeneratedOnAddOrUpdate() .ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone"); .HasColumnType("timestamp with time zone");
b.Property<string>("Discriminator") b.Property<string>("Title")
.IsRequired() .IsRequired()
.HasMaxLength(13) .HasColumnType("text");
.HasColumnType("character varying(13)");
b.HasKey("Id"); b.HasKey("Id");
b.ToTable("BaseEntity"); b.ToTable("Movies");
});
b.HasDiscriminator<string>("Discriminator").HasValue("BaseEntity"); modelBuilder.Entity("TvNoms.Core.Entities.Show", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.UseTphMappingStrategy(); b.Property<DateTime>("DateCreated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<DateTime>("DateUpdated")
.ValueGeneratedOnAddOrUpdate()
.HasColumnType("timestamp with time zone");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Shows");
}); });
modelBuilder.Entity("TvNoms.Core.Entities.User", b => modelBuilder.Entity("TvNoms.Core.Entities.User", b =>
@@ -312,7 +422,7 @@ namespace TvNoms.Server.Data.Migrations
b.HasIndex("UserId"); b.HasIndex("UserId");
b.ToTable("UserSession"); b.ToTable("UserSessions");
}); });
modelBuilder.Entity("TvNoms.Core.Entities.Role", b => modelBuilder.Entity("TvNoms.Core.Entities.Role", b =>
@@ -322,102 +432,6 @@ namespace TvNoms.Server.Data.Migrations
b.HasDiscriminator().HasValue("Role"); b.HasDiscriminator().HasValue("Role");
}); });
modelBuilder.Entity("TvNoms.Core.Entities.Client", b =>
{
b.HasBaseType("TvNoms.Core.Entities.BaseEntity");
b.Property<bool>("Active")
.HasColumnType("boolean");
b.Property<string>("ConnectionId")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("ConnectionTime")
.HasColumnType("timestamp with time zone");
b.Property<string>("DeviceId")
.HasColumnType("text");
b.Property<string>("IpAddress")
.HasColumnType("text");
b.Property<string>("UserAgent")
.HasColumnType("text");
b.Property<Guid?>("UserId")
.HasColumnType("uuid");
b.HasIndex("UserId");
b.HasDiscriminator().HasValue("Client");
});
modelBuilder.Entity("TvNoms.Core.Entities.Media", b =>
{
b.HasBaseType("TvNoms.Core.Entities.BaseEntity");
b.Property<string>("ContentType")
.IsRequired()
.HasColumnType("text");
b.Property<DateTimeOffset>("CreatedAt")
.HasColumnType("timestamp with time zone");
b.Property<int?>("Height")
.HasColumnType("integer");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<string>("Path")
.IsRequired()
.HasColumnType("text");
b.Property<long>("Size")
.HasColumnType("bigint");
b.Property<int>("Type")
.HasColumnType("integer");
b.Property<DateTimeOffset>("UpdatedAt")
.HasColumnType("timestamp with time zone");
b.Property<int?>("Width")
.HasColumnType("integer");
b.HasDiscriminator().HasValue("Media");
});
modelBuilder.Entity("TvNoms.Core.Entities.Movie", b =>
{
b.HasBaseType("TvNoms.Core.Entities.BaseEntity");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.HasDiscriminator().HasValue("Movie");
});
modelBuilder.Entity("TvNoms.Core.Entities.Show", b =>
{
b.HasBaseType("TvNoms.Core.Entities.BaseEntity");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("text");
b.ToTable("BaseEntity", t =>
{
t.Property("Title")
.HasColumnName("Show_Title");
});
b.HasDiscriminator().HasValue("Show");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b => modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<System.Guid>", b =>
{ {
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<System.Guid>", null) b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<System.Guid>", null)
@@ -469,6 +483,15 @@ namespace TvNoms.Server.Data.Migrations
.IsRequired(); .IsRequired();
}); });
modelBuilder.Entity("TvNoms.Core.Entities.Client", b =>
{
b.HasOne("TvNoms.Core.Entities.User", "User")
.WithMany("Clients")
.HasForeignKey("UserId");
b.Navigation("User");
});
modelBuilder.Entity("TvNoms.Core.Entities.User", b => modelBuilder.Entity("TvNoms.Core.Entities.User", b =>
{ {
b.HasOne("TvNoms.Core.Entities.Media", "Avatar") b.HasOne("TvNoms.Core.Entities.Media", "Avatar")
@@ -489,15 +512,6 @@ namespace TvNoms.Server.Data.Migrations
b.Navigation("User"); b.Navigation("User");
}); });
modelBuilder.Entity("TvNoms.Core.Entities.Client", b =>
{
b.HasOne("TvNoms.Core.Entities.User", "User")
.WithMany("Clients")
.HasForeignKey("UserId");
b.Navigation("User");
});
modelBuilder.Entity("TvNoms.Core.Entities.User", b => modelBuilder.Entity("TvNoms.Core.Entities.User", b =>
{ {
b.Navigation("Clients"); b.Navigation("Clients");

View File

@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using TvNoms.Core.Entities; using TvNoms.Core.Entities;
using TvNoms.Core.Extensions.Identity; using TvNoms.Core.Extensions.Identity;
@@ -9,14 +10,19 @@ using TvNoms.Server.Services;
namespace TvNoms.Infrastructure.Identity; namespace TvNoms.Infrastructure.Identity;
public static class ServiceCollectionExtensions { public static class ServiceCollectionExtensions {
public static IServiceCollection AddWebAppCors(this IServiceCollection services) { public static IServiceCollection AddWebAppCors(this IServiceCollection services, IConfiguration config) {
services.AddCors(options => { services.AddCors(options => {
options.AddPolicy("WebAppPolicy", builder => { options.AddPolicy("WebAppCors", policy => {
builder var allowedOrigins =
config.GetSection("AllowedOrigins")?.Get<string[]>() ?? Array.Empty<string>();
policy
.WithOrigins(allowedOrigins)
.AllowAnyMethod() .AllowAnyMethod()
.AllowAnyHeader() .AllowAnyHeader()
.AllowCredentials() .AllowCredentials()
.WithOrigins("https://tvnoms.dev.fergl.ie:3000/"); .WithExposedHeaders("Content-Disposition")
.SetPreflightMaxAge(TimeSpan.FromMinutes(10));
}); });
}); });
return services; return services;