diff --git a/.editorconfig b/.editorconfig index 367a88a..6e06f07 100644 --- a/.editorconfig +++ b/.editorconfig @@ -126,7 +126,7 @@ dotnet_diagnostic.SA1601.severity = none dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none # SA1516: Elements should be separated by blank line -dotnet_diagnostic.SA1516.severity = none +dotnet_diagnostic.SA1516.severity = error # SA1649: File name should match first type name dotnet_diagnostic.SA1649.severity = none @@ -142,3 +142,11 @@ dotnet_diagnostic.SA1309.severity = none # SA1309: Make sure class members are allowed to call without "this" prefix dotnet_diagnostic.SA1101.severity = none +# SA1118: parameter spans multiple lines +dotnet_diagnostic.SA1118.severity = none +# SA1011: closing square bracket spacing +dotnet_diagnostic.SA1011.severity = none +# SA1517: no blank lines at start of file +dotnet_diagnostic.SA1517.severity = none +# SA1200: using directive should appear within a namespace +dotnet_diagnostic.SA1200.severity = none diff --git a/.gitignore b/.gitignore index ad9a362..ed90c2d 100644 --- a/.gitignore +++ b/.gitignore @@ -396,5 +396,5 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml -src/Recruitment.Tool.xml -/Francesco.Recipes.World/Migrations/20250304095839_AddFewNewBackendModels.Designer.cs +src/Francesco.Recipes.World.xml + diff --git a/Francesco.Recipes.World/Data/FrancescosRecipesWorldDbContext.cs b/Francesco.Recipes.World/Data/FrancescosRecipesWorldDbContext.cs index 5146867..67117c4 100644 --- a/Francesco.Recipes.World/Data/FrancescosRecipesWorldDbContext.cs +++ b/Francesco.Recipes.World/Data/FrancescosRecipesWorldDbContext.cs @@ -1,5 +1,5 @@ -namespace Francesco.Recipes.World.Data -{ +namespace Francesco.Recipes.World.Data; + using Francesco.Recipes.World.Models.BackendModels; using Francesco.Recipes.World.Models.BackendModels.Category; using Francesco.Recipes.World.Models.BackendModels.Favorit; @@ -21,15 +21,25 @@ } public DbSet Categories => Set(); + public DbSet Ingredients => Set(); + public DbSet Instructions => Set(); + public DbSet Recipes => Set(); + public DbSet RecipeIngredients => Set(); + public DbSet Units => Set(); + public DbSet Favorits => Set(); + public DbSet IngredientsShoppingLists => Set(); + public DbSet ShoppingLists => Set(); + public DbSet MediaFiles => Set(); + public override Task SaveChangesAsync(CancellationToken cancellationToken = default) { foreach (var entry in ChangeTracker.Entries()) @@ -104,4 +114,3 @@ ]; } } -} diff --git a/Francesco.Recipes.World/Francesco.Recipes.World.csproj b/Francesco.Recipes.World/Francesco.Recipes.World.csproj index f9e0493..728f575 100644 --- a/Francesco.Recipes.World/Francesco.Recipes.World.csproj +++ b/Francesco.Recipes.World/Francesco.Recipes.World.csproj @@ -6,10 +6,14 @@ enable be6a70eb-b657-40b2-b4a1-418e5c6ec131 + + true + $(SolutionDir)Francesco.Recipes.World.ruleset + - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -38,4 +42,11 @@ + + + + + + + diff --git a/Francesco.Recipes.World/Migrations/20250318150949_InitialMIgration.cs b/Francesco.Recipes.World/Migrations/20250318150949_InitialMIgration.cs index 2b14663..18ff0ed 100644 --- a/Francesco.Recipes.World/Migrations/20250318150949_InitialMIgration.cs +++ b/Francesco.Recipes.World/Migrations/20250318150949_InitialMIgration.cs @@ -1,12 +1,12 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable +#nullable disable #pragma warning disable CA1814 // Prefer jagged arrays over multidimensional namespace Francesco.Recipes.World.Migrations { + using System; + using Microsoft.EntityFrameworkCore.Migrations; + /// public partial class InitialMIgration : Migration { @@ -17,12 +17,13 @@ namespace Francesco.Recipes.World.Migrations { throw new ArgumentNullException(nameof(migrationBuilder)); } + migrationBuilder.CreateTable( name: "Categories", columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(max)", nullable: false) + Name = table.Column(type: "nvarchar(max)", nullable: false), }, constraints: table => { @@ -34,7 +35,7 @@ namespace Francesco.Recipes.World.Migrations columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), - CreatedAt = table.Column(type: "datetime2", nullable: false) + CreatedAt = table.Column(type: "datetime2", nullable: false), }, constraints: table => { @@ -46,7 +47,7 @@ namespace Francesco.Recipes.World.Migrations columns: table => new { Id = table.Column(type: "uniqueidentifier", nullable: false), - Name = table.Column(type: "nvarchar(max)", nullable: false) + Name = table.Column(type: "nvarchar(max)", nullable: false), }, constraints: table => { @@ -59,7 +60,7 @@ namespace Francesco.Recipes.World.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), CreatedAt = table.Column(type: "datetime2", nullable: false), - ModifiedAt = table.Column(type: "datetime2", nullable: true) + ModifiedAt = table.Column(type: "datetime2", nullable: true), }, constraints: table => { @@ -72,7 +73,7 @@ namespace Francesco.Recipes.World.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), Name = table.Column(type: "nvarchar(max)", nullable: false), - Symbol = table.Column(type: "nvarchar(max)", nullable: false) + Symbol = table.Column(type: "nvarchar(max)", nullable: false), }, constraints: table => { @@ -94,7 +95,7 @@ namespace Francesco.Recipes.World.Migrations CreatedAt = table.Column(type: "datetime2", nullable: false), ModifiedAt = table.Column(type: "datetime2", nullable: true), FavoritId = table.Column(type: "uniqueidentifier", nullable: false), - CategoryId = table.Column(type: "uniqueidentifier", nullable: true) + CategoryId = table.Column(type: "uniqueidentifier", nullable: true), }, constraints: table => { @@ -118,7 +119,7 @@ namespace Francesco.Recipes.World.Migrations { Id = table.Column(type: "uniqueidentifier", nullable: false), ShoppinglistId = table.Column(type: "uniqueidentifier", nullable: false), - IngredientId = table.Column(type: "uniqueidentifier", nullable: false) + IngredientId = table.Column(type: "uniqueidentifier", nullable: false), }, constraints: table => { @@ -144,7 +145,7 @@ namespace Francesco.Recipes.World.Migrations Id = table.Column(type: "uniqueidentifier", nullable: false), Description = table.Column(type: "nvarchar(max)", nullable: false), Number = table.Column(type: "nvarchar(max)", nullable: false), - RecipeId = table.Column(type: "uniqueidentifier", nullable: false) + RecipeId = table.Column(type: "uniqueidentifier", nullable: false), }, constraints: table => { @@ -165,7 +166,7 @@ namespace Francesco.Recipes.World.Migrations RecipeId = table.Column(type: "uniqueidentifier", nullable: false), IngredientId = table.Column(type: "uniqueidentifier", nullable: false), UnitId = table.Column(type: "uniqueidentifier", nullable: false), - Quantity = table.Column(type: "int", nullable: false) + Quantity = table.Column(type: "int", nullable: false), }, constraints: table => { @@ -199,7 +200,7 @@ namespace Francesco.Recipes.World.Migrations MimeType = table.Column(type: "nvarchar(max)", nullable: true), Data = table.Column(type: "varbinary(max)", nullable: true), RecipeId = table.Column(type: "uniqueidentifier", nullable: true), - InstructionId = table.Column(type: "uniqueidentifier", nullable: false) + InstructionId = table.Column(type: "uniqueidentifier", nullable: false), }, constraints: table => { @@ -231,7 +232,7 @@ namespace Francesco.Recipes.World.Migrations { new Guid("abbc6bb0-97ea-49f5-b31e-6507eb784fd1"), "Hauptgerichte" }, { new Guid("adfb75ce-3ef3-428b-a5ca-b0c4c619d5ec"), "Hefegebäck & Brot" }, { new Guid("b248244f-f21c-4555-a14d-5dd49a2717cf"), "Vorspeisen & Snacks" }, - { new Guid("d332f88d-d241-48c5-a2f2-bfd124eada7e"), "Soßen & Saucen" } + { new Guid("d332f88d-d241-48c5-a2f2-bfd124eada7e"), "Soßen & Saucen" }, }); migrationBuilder.InsertData( @@ -249,7 +250,7 @@ namespace Francesco.Recipes.World.Migrations { new Guid("7ea2f51d-7493-4f19-a663-1f309186d3ae"), "bund", "bund" }, { new Guid("d82f4abd-e4e4-4104-a9c0-1acdeaa701f5"), "blatt", "blatt" }, { new Guid("df5cb4c3-4de6-4c6f-be8c-da41b2986408"), "messerspitze", "msp" }, - { new Guid("e45a3af2-2ed6-4ac4-b06f-b4175663a7be"), "stange", "stange" } + { new Guid("e45a3af2-2ed6-4ac4-b06f-b4175663a7be"), "stange", "stange" }, }); migrationBuilder.CreateIndex( @@ -310,6 +311,7 @@ namespace Francesco.Recipes.World.Migrations { throw new ArgumentNullException(nameof(migrationBuilder)); } + migrationBuilder.DropTable( name: "IngredientsShoppingLists"); diff --git a/Francesco.Recipes.World/Migrations/FrancescosRecipesWorldDbContextModelSnapshot.cs b/Francesco.Recipes.World/Migrations/FrancescosRecipesWorldDbContextModelSnapshot.cs index e24e960..130fbf5 100644 --- a/Francesco.Recipes.World/Migrations/FrancescosRecipesWorldDbContextModelSnapshot.cs +++ b/Francesco.Recipes.World/Migrations/FrancescosRecipesWorldDbContextModelSnapshot.cs @@ -1,10 +1,9 @@ // -using System; + using Francesco.Recipes.World.Data; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + #nullable disable diff --git a/Francesco.Recipes.World/Models/BackendModels/Category/Category.cs b/Francesco.Recipes.World/Models/BackendModels/Category/Category.cs index 5fa42d4..b088952 100644 --- a/Francesco.Recipes.World/Models/BackendModels/Category/Category.cs +++ b/Francesco.Recipes.World/Models/BackendModels/Category/Category.cs @@ -1,10 +1,13 @@ namespace Francesco.Recipes.World.Models.BackendModels.Category { using Francesco.Recipes.World.Models.BackendModels.Recipe; + public class Category { public Guid Id { get; set; } - public string Name { get; set; } + + public string Name { get; set; } = string.Empty; + public virtual ICollection Recipes { get; set; } = new List(); } } diff --git a/Francesco.Recipes.World/Models/BackendModels/Favorit/Favorit.cs b/Francesco.Recipes.World/Models/BackendModels/Favorit/Favorit.cs index 65b9aa9..97e12ed 100644 --- a/Francesco.Recipes.World/Models/BackendModels/Favorit/Favorit.cs +++ b/Francesco.Recipes.World/Models/BackendModels/Favorit/Favorit.cs @@ -5,7 +5,9 @@ public class Favorit { public Guid Id { get; set; } + public DateTime CreatedAt { get; set; } + public virtual ICollection Recipe { get; set; } = new List(); } } diff --git a/Francesco.Recipes.World/Models/BackendModels/Ingredient/Ingredient.cs b/Francesco.Recipes.World/Models/BackendModels/Ingredient/Ingredient.cs index 2a3e4d4..c4c43c3 100644 --- a/Francesco.Recipes.World/Models/BackendModels/Ingredient/Ingredient.cs +++ b/Francesco.Recipes.World/Models/BackendModels/Ingredient/Ingredient.cs @@ -6,8 +6,11 @@ public class Ingredient { public Guid Id { get; set; } - public string Name { get; set; } + + public string Name { get; set; } = string.Empty; + public virtual ICollection RecipeIngredients { get; set; } = new List(); + public virtual ICollection IngredientShoppingLists { get; set; } = new List(); } } diff --git a/Francesco.Recipes.World/Models/BackendModels/IngredientShoppingList/IngredientsShoppingList.cs b/Francesco.Recipes.World/Models/BackendModels/IngredientShoppingList/IngredientsShoppingList.cs index c527693..78f92d7 100644 --- a/Francesco.Recipes.World/Models/BackendModels/IngredientShoppingList/IngredientsShoppingList.cs +++ b/Francesco.Recipes.World/Models/BackendModels/IngredientShoppingList/IngredientsShoppingList.cs @@ -6,7 +6,9 @@ public class IngredientsShoppingList { public Guid Id { get; set; } - public ShoppingList Shoppinglist { get; set; } = new(); - public Ingredient Ingredient { get; set; } = new(); + + public ShoppingList Shoppinglist { get; set; } = new (); + + public Ingredient Ingredient { get; set; } = new (); } } diff --git a/Francesco.Recipes.World/Models/BackendModels/Instruction/Instruction.cs b/Francesco.Recipes.World/Models/BackendModels/Instruction/Instruction.cs index 6f0919c..77a16d1 100644 --- a/Francesco.Recipes.World/Models/BackendModels/Instruction/Instruction.cs +++ b/Francesco.Recipes.World/Models/BackendModels/Instruction/Instruction.cs @@ -2,12 +2,17 @@ { using Francesco.Recipes.World.Models.BackendModels.MediaFile; using Francesco.Recipes.World.Models.BackendModels.Recipe; + public class Instruction { public Guid Id { get; set; } - public string Description { get; set; } - public string Number { get; set; } - public virtual Recipe Recipe { get; set; } = new(); + + public string Description { get; set; } = string.Empty; + + public int Number { get; set; } + + public virtual Recipe Recipe { get; set; } = new (); + public virtual ICollection MediaFiles { get; set; } = new List(); } } diff --git a/Francesco.Recipes.World/Models/BackendModels/MediaFile/MediaFile.cs b/Francesco.Recipes.World/Models/BackendModels/MediaFile/MediaFile.cs index 56c083a..f8a8218 100644 --- a/Francesco.Recipes.World/Models/BackendModels/MediaFile/MediaFile.cs +++ b/Francesco.Recipes.World/Models/BackendModels/MediaFile/MediaFile.cs @@ -2,6 +2,7 @@ { using Francesco.Recipes.World.Models.BackendModels.Instruction; using Francesco.Recipes.World.Models.BackendModels.Recipe; + public class MediaFile { public Guid Id { get; set; } = Guid.NewGuid(); @@ -11,7 +12,9 @@ public string? MimeType { get; set; } public byte[]? Data { get; set; } - public virtual Recipe? Recipe { get; set; } = new(); - public virtual Instruction Instruction { get; set; } = new(); + + public virtual Recipe? Recipe { get; set; } = new (); + + public virtual Instruction Instruction { get; set; } = new (); } } diff --git a/Francesco.Recipes.World/Models/BackendModels/Recipe/Difficulty.cs b/Francesco.Recipes.World/Models/BackendModels/Recipe/Difficulty.cs index 91d20a0..4456670 100644 --- a/Francesco.Recipes.World/Models/BackendModels/Recipe/Difficulty.cs +++ b/Francesco.Recipes.World/Models/BackendModels/Recipe/Difficulty.cs @@ -3,9 +3,13 @@ public enum Difficulty { VeryEasy = 1, + Easy = 2, + Medium = 3, + Hard = 4, + Expert = 5, } } diff --git a/Francesco.Recipes.World/Models/BackendModels/Recipe/Recipe.cs b/Francesco.Recipes.World/Models/BackendModels/Recipe/Recipe.cs index 7d4e01e..da673d7 100644 --- a/Francesco.Recipes.World/Models/BackendModels/Recipe/Recipe.cs +++ b/Francesco.Recipes.World/Models/BackendModels/Recipe/Recipe.cs @@ -8,17 +8,30 @@ using Francesco.Recipes.World.Models.BackendModels.RecipeIngredient; public class Recipe : ITimeStampedEntity { public Guid Id { get; set; } - public string Name { get; set; } + + public string Name { get; set; } = string.Empty; + public string? Description { get; set; } + public Difficulty Difficulty { get; set; } + public int Servings { get; set; } + public TimeSpan PreparationTime { get; set; } + public TimeSpan CookingTime { get; set; } + public bool IsFavorite { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime? ModifiedAt { get; set; } + public virtual ICollection RecipeIngredients { get; set; } = new List(); + public virtual ICollection Instructions { get; set; } = new List(); + public virtual ICollection MediaFiles { get; set; } = new List(); - public virtual Favorit Favorit { get; set; } = new(); + + public virtual Favorit Favorit { get; set; } = new (); } diff --git a/Francesco.Recipes.World/Models/BackendModels/RecipeIngredient/RecipeIngredient.cs b/Francesco.Recipes.World/Models/BackendModels/RecipeIngredient/RecipeIngredient.cs index 30456ad..d64abb5 100644 --- a/Francesco.Recipes.World/Models/BackendModels/RecipeIngredient/RecipeIngredient.cs +++ b/Francesco.Recipes.World/Models/BackendModels/RecipeIngredient/RecipeIngredient.cs @@ -3,12 +3,17 @@ using Francesco.Recipes.World.Models.BackendModels.Ingredient; using Francesco.Recipes.World.Models.BackendModels.Recipe; using Francesco.Recipes.World.Models.BackendModels.Unit; + public class RecipeIngredient { public Guid Id { get; set; } - public virtual Recipe Recipe { get; set; } = new(); - public virtual Ingredient Ingredient { get; set; } = new(); - public virtual Unit Unit { get; set; } = new(); + + public virtual Recipe Recipe { get; set; } = new (); + + public virtual Ingredient Ingredient { get; set; } = new (); + + public virtual Unit Unit { get; set; } = new (); + public int Quantity { get; set; } } } diff --git a/Francesco.Recipes.World/Models/BackendModels/Shoppinglist/ShoppingList.cs b/Francesco.Recipes.World/Models/BackendModels/Shoppinglist/ShoppingList.cs index a6f764e..71fc7e7 100644 --- a/Francesco.Recipes.World/Models/BackendModels/Shoppinglist/ShoppingList.cs +++ b/Francesco.Recipes.World/Models/BackendModels/Shoppinglist/ShoppingList.cs @@ -1,12 +1,15 @@ -using Francesco.Recipes.World.Models.BackendModels.IngredientShoppingList; - -namespace Francesco.Recipes.World.Models.BackendModels.Shoppinglist +namespace Francesco.Recipes.World.Models.BackendModels.Shoppinglist { + using Francesco.Recipes.World.Models.BackendModels.IngredientShoppingList; + public class ShoppingList : ITimeStampedEntity { public Guid Id { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime? ModifiedAt { get; set; } + public virtual ICollection IngredientsShoppingLists { get; set; } = new List(); } } diff --git a/Francesco.Recipes.World/Models/BackendModels/Unit/Unit.cs b/Francesco.Recipes.World/Models/BackendModels/Unit/Unit.cs index e11bce3..ba8a539 100644 --- a/Francesco.Recipes.World/Models/BackendModels/Unit/Unit.cs +++ b/Francesco.Recipes.World/Models/BackendModels/Unit/Unit.cs @@ -1,14 +1,15 @@ - - -namespace Francesco.Recipes.World.Models.BackendModels.Unit +namespace Francesco.Recipes.World.Models.BackendModels.Unit { - using Francesco.Recipes.World.Models.BackendModels.Ingredient; using Francesco.Recipes.World.Models.BackendModels.RecipeIngredient; + public class Unit { - public Guid Id{ get; set; } - public string Name { get; set; } - public string Symbol { get; set; } + public Guid Id { get; set; } + + public string Name { get; set; } = string.Empty; + + public string Symbol { get; set; } = string.Empty; + public virtual ICollection RecipeIngredient { get; set; } = new List(); - } + } } diff --git a/Francesco.Recipes.World/Program.cs b/Francesco.Recipes.World/Program.cs index c36c4ac..6d773ec 100644 --- a/Francesco.Recipes.World/Program.cs +++ b/Francesco.Recipes.World/Program.cs @@ -1,15 +1,22 @@ using Francesco.Recipes.World.Data; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using Serilog; +using Francesco.Recipes.World.Repositories; + +using FrancescoRecipesWorld.Repositories; + +using Microsoft.AspNetCore.Identity; + +using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); + var services = builder.Services; + var configuration = builder.Configuration; var connectionString = builder.Configuration.GetConnectionString("FrancescosRecipesWorldDbContextConnection") ?? throw new InvalidOperationException("Connection string 'FrancescosRecipesWorldDbContextConnection' not found."); + services.AddDbContext(options => options.UseSqlServer(connectionString)); @@ -19,6 +26,14 @@ services.AddDefaultIdentity(options => options.SignIn.RequireConfi // Add services to the container. builder.Services.AddControllersWithViews(); +builder.Services.AddScoped(); + +builder.Services.AddScoped(); + +builder.Services.AddScoped(); + +builder.Services.AddScoped(); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -31,9 +46,11 @@ if (!app.Environment.IsDevelopment()) } app.UseHttpsRedirection(); + app.UseStaticFiles(); app.UseRouting(); + app.UseAuthentication(); app.UseAuthorization();