support for displaying ingredient metadata
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
# GITIGNORE FILES ADDED BY MIKAYLA
|
||||
__notes__
|
||||
*.env
|
||||
UnbinderSandbox
|
||||
|
||||
# Files for/generated by Docker Compose
|
||||
secrets
|
||||
|
||||
@@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.7.34031.279
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unbinder", "Unbinder\Unbinder.csproj", "{620A53DB-415A-4741-ABDE-5E2B78197CF7}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Unbinder", "Unbinder\Unbinder.csproj", "{620A53DB-415A-4741-ABDE-5E2B78197CF7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnbinderSandbox", "UnbinderSandbox\UnbinderSandbox.csproj", "{A75CD739-80D1-4D96-A828-52B3F49B8254}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -15,6 +17,10 @@ Global
|
||||
{620A53DB-415A-4741-ABDE-5E2B78197CF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{620A53DB-415A-4741-ABDE-5E2B78197CF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{620A53DB-415A-4741-ABDE-5E2B78197CF7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A75CD739-80D1-4D96-A828-52B3F49B8254}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A75CD739-80D1-4D96-A828-52B3F49B8254}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A75CD739-80D1-4D96-A828-52B3F49B8254}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A75CD739-80D1-4D96-A828-52B3F49B8254}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Unbinder.Models;
|
||||
using Unbinder.Repositories;
|
||||
using Unbinder.ViewModels;
|
||||
|
||||
namespace Unbinder.Controllers
|
||||
{
|
||||
public class RecipeController(IRecipeRepository recipeRepository) : Controller
|
||||
public class RecipeController(IRecipeRepository recipeRepository, IRecipeIngredientRepository recipeIngredientRepository) : Controller
|
||||
{
|
||||
private readonly IRecipeRepository _recipeRepository = recipeRepository;
|
||||
private readonly IRecipeIngredientRepository _recipeIngredientRepository = recipeIngredientRepository;
|
||||
|
||||
public IActionResult Index()
|
||||
{
|
||||
@@ -16,18 +18,19 @@ namespace Unbinder.Controllers
|
||||
: View(result);
|
||||
}
|
||||
|
||||
[Route("[controller]/{id}")]
|
||||
public IActionResult RecipeId(int id, bool editMode = false)
|
||||
[Route("[controller]/{recipeId}")]
|
||||
public IActionResult RecipeId(int recipeId, bool editMode = false)
|
||||
{
|
||||
var result = _recipeRepository.GetById(id);
|
||||
|
||||
Console.WriteLine(result == null ? "No result found" : result);
|
||||
|
||||
ViewBag.EditMode = editMode;
|
||||
|
||||
return result == null
|
||||
? NotFound()
|
||||
: View(result);
|
||||
var recipe = _recipeRepository.GetById(recipeId);
|
||||
if (recipe == null) return NotFound();
|
||||
var ingredients = _recipeIngredientRepository.GetIngredientsByRecipeId(recipeId);
|
||||
|
||||
|
||||
|
||||
RecipeViewModel recipeViewModel = new(recipe, ingredients);
|
||||
return View(recipeViewModel);
|
||||
}
|
||||
|
||||
[Route("[controller]/search")]
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using Unbinder.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Unbinder.Models;
|
||||
using Unbinder.Repositories;
|
||||
|
||||
namespace Unbinder.DB
|
||||
{
|
||||
public static class Initializer
|
||||
{
|
||||
private static readonly ILogger logger = new LoggerFactory().CreateLogger("DBInitializer");
|
||||
|
||||
public static int Seed(IApplicationBuilder applicationBuilder)
|
||||
{
|
||||
int totalInsertCount = 0;
|
||||
@@ -12,7 +15,7 @@ namespace Unbinder.DB
|
||||
using UnbinderDbContext context = applicationBuilder.ApplicationServices.CreateScope()
|
||||
.ServiceProvider.GetRequiredService<UnbinderDbContext>();
|
||||
|
||||
Console.WriteLine("Connection established, preparing to seed database...");
|
||||
logger.Log(LogLevel.Information, "Connection established, preparing to seed database...");
|
||||
|
||||
// if records are not already seeded, do an initial insert into DB
|
||||
WriteIfNotInitialized(context.Recipes, SeedData.InitialRecipes, context.Recipes.AddRange);
|
||||
@@ -20,7 +23,7 @@ namespace Unbinder.DB
|
||||
|
||||
// save changes so we can references them for establishing relations
|
||||
int insertCount = context.SaveChanges();
|
||||
Console.WriteLine($"Seeded {insertCount} records");
|
||||
logger.Log(LogLevel.Information, $"Seeded {insertCount} records");
|
||||
totalInsertCount += insertCount;
|
||||
|
||||
// establish relations if they do not already exist
|
||||
@@ -29,16 +32,14 @@ namespace Unbinder.DB
|
||||
|
||||
if (padThai != null)
|
||||
{
|
||||
Console.WriteLine("Found Pad Thai recipe, checking relations...");
|
||||
var padThaiIngredientNames = SeedData.PadThaiIngredients.Select(i => i.Name);
|
||||
AddRelations(context, padThaiIngredientNames, padThai.RecipeId);
|
||||
logger.Log(LogLevel.Information, "Found Pad Thai recipe, checking relations...");
|
||||
AddRelations(context, SeedData.PadThaiIngredientsWithDetails, padThai.RecipeId);
|
||||
}
|
||||
|
||||
if (pancakes != null)
|
||||
{
|
||||
Console.WriteLine("Found Pancakes recipe, checking relations...");
|
||||
var pancakeIngredientNames = SeedData.PancakeIngredients.Select(i => i.Name);
|
||||
AddRelations(context, pancakeIngredientNames, pancakes.RecipeId);
|
||||
logger.Log(LogLevel.Information, "Found Pancakes recipe, checking relations...");
|
||||
AddRelations(context, SeedData.PancakeIngredientsWithDetails, pancakes.RecipeId);
|
||||
}
|
||||
|
||||
totalInsertCount += context.SaveChanges();
|
||||
@@ -50,23 +51,31 @@ namespace Unbinder.DB
|
||||
private static void WriteIfNotInitialized<T>(IEnumerable<T> existingItems, IEnumerable<T> seedData, Callback<T> addRange)
|
||||
{
|
||||
if (existingItems.Any()) {
|
||||
Console.WriteLine("Record already exists in the database");
|
||||
logger.Log(LogLevel.Information, "Record already exists in the database");
|
||||
return;
|
||||
}
|
||||
|
||||
addRange(seedData);
|
||||
}
|
||||
|
||||
private static void AddRelations(UnbinderDbContext context, IEnumerable<string> names, int id)
|
||||
private static void AddRelations(UnbinderDbContext context, IngredientWithDetails[] details, int recipeId)
|
||||
{
|
||||
var names = details.Select(d => d.Ingredient.Name);
|
||||
|
||||
foreach (var ing in context.Ingredients)
|
||||
{
|
||||
if (names.Contains(ing.Name))
|
||||
{
|
||||
logger.Log(LogLevel.Information, $"Writing entry for {ing.Name}");
|
||||
|
||||
var entryForThis = details.Where(d => d.Ingredient.Name == ing.Name).FirstOrDefault();
|
||||
|
||||
context.RecipeIngredients.Add(new RecipeIngredient
|
||||
{
|
||||
RecipeId = id,
|
||||
RecipeId = recipeId,
|
||||
IngredientId = ing.IngredientId,
|
||||
Amount = entryForThis?.Details.Amount,
|
||||
Unit = entryForThis?.Details.Unit,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
3
Unbinder/DB/SQL/truncate_database.sql
Normal file
3
Unbinder/DB/SQL/truncate_database.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
TRUNCATE TABLE Ingredients;
|
||||
TRUNCATE TABLE RecipeIngredients;
|
||||
TRUNCATE TABLE Recipes;
|
||||
@@ -37,6 +37,69 @@ namespace Unbinder.DB
|
||||
|
||||
public static Recipe[] InitialRecipes => [PadThaiRecipe, PancakeRecipe];
|
||||
|
||||
public static IngredientWithDetails[] PadThaiIngredientsWithDetails
|
||||
{
|
||||
get
|
||||
{
|
||||
return [
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PadThaiIngredients[0],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 1,
|
||||
Unit = "Bunch, roughly chopped"
|
||||
}
|
||||
},
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PadThaiIngredients[1],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 1,
|
||||
Unit = "Lime (juice)"
|
||||
}
|
||||
},
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PadThaiIngredients[2],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 0.25,
|
||||
Unit = "Cup (chopped)",
|
||||
}
|
||||
},
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PadThaiIngredients[3],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 16,
|
||||
Unit = "oz."
|
||||
}
|
||||
},
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PadThaiIngredients[4],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 1,
|
||||
Unit = "Egg (scrambled)"
|
||||
}
|
||||
},
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PadThaiIngredients[5],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 1,
|
||||
Unit = "Block (diced)"
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public static Ingredient[] PadThaiIngredients
|
||||
{
|
||||
get
|
||||
@@ -104,6 +167,51 @@ namespace Unbinder.DB
|
||||
}
|
||||
}
|
||||
|
||||
public static IngredientWithDetails[] PancakeIngredientsWithDetails
|
||||
{
|
||||
get
|
||||
{
|
||||
return [
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PancakeIngredients[0],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 2,
|
||||
Unit = "cups",
|
||||
}
|
||||
},
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PancakeIngredients[1],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 1,
|
||||
Unit = "teaspoon"
|
||||
}
|
||||
},
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PancakeIngredients[2],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 1,
|
||||
Unit = "teaspoon",
|
||||
}
|
||||
},
|
||||
new IngredientWithDetails
|
||||
{
|
||||
Ingredient = PancakeIngredients[3],
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = 2,
|
||||
Unit = "tablespoons"
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public static Ingredient[] InitialIngredients => PadThaiIngredients.Concat(PancakeIngredients).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ using Unbinder.DB;
|
||||
|
||||
namespace Unbinder.Migrations
|
||||
{
|
||||
[DbContext(typeof(UnbinderDbContext))]
|
||||
[DbContext(typeof(Initializer))]
|
||||
[Migration("20231117145840_InitialMigration")]
|
||||
partial class InitialMigration
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ using Unbinder.DB;
|
||||
|
||||
namespace Unbinder.Migrations
|
||||
{
|
||||
[DbContext(typeof(UnbinderDbContext))]
|
||||
[DbContext(typeof(Initializer))]
|
||||
[Migration("20231117150919_RemoveIngredientArray")]
|
||||
partial class RemoveIngredientArray
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ using Unbinder.DB;
|
||||
|
||||
namespace Unbinder.Migrations
|
||||
{
|
||||
[DbContext(typeof(UnbinderDbContext))]
|
||||
[DbContext(typeof(Initializer))]
|
||||
[Migration("20231201185549_update-table-names")]
|
||||
partial class updatetablenames
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ using Unbinder.DB;
|
||||
|
||||
namespace Unbinder.Migrations
|
||||
{
|
||||
[DbContext(typeof(UnbinderDbContext))]
|
||||
[DbContext(typeof(Initializer))]
|
||||
[Migration("20231204172304_RecipeIngredientRelation")]
|
||||
partial class RecipeIngredientRelation
|
||||
{
|
||||
|
||||
108
Unbinder/Migrations/20231204213851_ModifyDataTypes.Designer.cs
generated
Normal file
108
Unbinder/Migrations/20231204213851_ModifyDataTypes.Designer.cs
generated
Normal file
@@ -0,0 +1,108 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Unbinder.DB;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Unbinder.Migrations
|
||||
{
|
||||
[DbContext(typeof(Initializer))]
|
||||
[Migration("20231204213851_ModifyDataTypes")]
|
||||
partial class ModifyDataTypes
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Unbinder.Models.Ingredient", b =>
|
||||
{
|
||||
b.Property<int>("IngredientId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("IngredientId"));
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("IngredientId");
|
||||
|
||||
b.ToTable("Ingredients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Unbinder.Models.Recipe", b =>
|
||||
{
|
||||
b.Property<int>("RecipeId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("RecipeId"));
|
||||
|
||||
b.Property<string>("Author")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("MainImageUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("RecipeText")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("S3Url")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("ShortDescription")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("RecipeId");
|
||||
|
||||
b.ToTable("Recipes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Unbinder.Models.RecipeIngredient", b =>
|
||||
{
|
||||
b.Property<int>("RecipeIngredientId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("RecipeIngredientId"));
|
||||
|
||||
b.Property<double?>("Amount")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<int>("IngredientId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("RecipeId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Unit")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("RecipeIngredientId");
|
||||
|
||||
b.ToTable("RecipeIngredients");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Unbinder/Migrations/20231204213851_ModifyDataTypes.cs
Normal file
36
Unbinder/Migrations/20231204213851_ModifyDataTypes.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Unbinder.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ModifyDataTypes : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<double>(
|
||||
name: "Amount",
|
||||
table: "RecipeIngredients",
|
||||
type: "float",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "nvarchar(max)",
|
||||
oldNullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Amount",
|
||||
table: "RecipeIngredients",
|
||||
type: "nvarchar(max)",
|
||||
nullable: true,
|
||||
oldClrType: typeof(double),
|
||||
oldType: "float",
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
@@ -9,7 +10,7 @@ using Unbinder.DB;
|
||||
|
||||
namespace Unbinder.Migrations
|
||||
{
|
||||
[DbContext(typeof(UnbinderDbContext))]
|
||||
[DbContext(typeof(Initializer))]
|
||||
partial class UnbinderDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
@@ -82,8 +83,8 @@ namespace Unbinder.Migrations
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("RecipeIngredientId"));
|
||||
|
||||
b.Property<string>("Amount")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
b.Property<double?>("Amount")
|
||||
.HasColumnType("float");
|
||||
|
||||
b.Property<int>("IngredientId")
|
||||
.HasColumnType("int");
|
||||
|
||||
15
Unbinder/Models/IngredientWithDetails.cs
Normal file
15
Unbinder/Models/IngredientWithDetails.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
namespace Unbinder.Models
|
||||
{
|
||||
public record IngredientWithDetails
|
||||
{
|
||||
|
||||
public Ingredient Ingredient { get; init; } = default!;
|
||||
public IngredientDetails Details { get; init; } = default!;
|
||||
}
|
||||
|
||||
public record IngredientDetails
|
||||
{
|
||||
public double? Amount { get; init; }
|
||||
public string? Unit { get; init; }
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace Unbinder.Models
|
||||
public int RecipeIngredientId { get; init; }
|
||||
public int RecipeId { get; init; }
|
||||
public int IngredientId { get; init; }
|
||||
public string? Amount { get; init; }
|
||||
public double? Amount { get; init; }
|
||||
public string? Unit { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ builder.Services.AddCors(options =>
|
||||
|
||||
builder.Services.AddScoped<IRecipeRepository, RecipeRepository>();
|
||||
builder.Services.AddScoped<IIngredientRepository, IngredientRepository>();
|
||||
builder.Services.AddScoped<IRecipeIngredientRepository, RecipeIngredientRepository>();
|
||||
|
||||
// include aws service
|
||||
builder.Services.AddTransient<S3Service>();
|
||||
|
||||
@@ -4,5 +4,6 @@ namespace Unbinder.Repositories
|
||||
{
|
||||
public interface IRecipeIngredientRepository : IBaseRepository<RecipeIngredient>
|
||||
{
|
||||
public IEnumerable<IngredientWithDetails>? GetIngredientsByRecipeId(int recipeId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Unbinder.Repositories
|
||||
public override IEnumerable<RecipeIngredient>? GetAll => null;
|
||||
public override RecipeIngredient? UpdateById(int id) => null;
|
||||
|
||||
// implemented methods:
|
||||
// overridden methods:
|
||||
public override RecipeIngredient? GetById(int id) => _dbContext.RecipeIngredients.Where(ri => ri.RecipeIngredientId == id).FirstOrDefault();
|
||||
|
||||
public override RecipeIngredient Post(RecipeIngredient entity)
|
||||
@@ -27,5 +27,51 @@ namespace Unbinder.Repositories
|
||||
_dbContext.SaveChanges();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// custom methods
|
||||
public IEnumerable<IngredientWithDetails>? GetIngredientsByRecipeId(int recipeId)
|
||||
{
|
||||
// get all ingredients associated with this recipe
|
||||
var ingredientDetails = _dbContext.RecipeIngredients
|
||||
.Where(ri => ri.RecipeId == recipeId)
|
||||
.ToArray();
|
||||
|
||||
if (ingredientDetails == null) return null;
|
||||
|
||||
// get the full DB listing for each ingredient
|
||||
var ingredientsForRecipe = _dbContext.Ingredients
|
||||
.Where(i => ingredientDetails.Select(d => d.IngredientId).Contains(i.IngredientId))
|
||||
.ToArray();
|
||||
|
||||
if (ingredientsForRecipe == null) return null;
|
||||
|
||||
// combine the two into a merged output
|
||||
return MergeIngredientsWithDetails(ingredientsForRecipe, ingredientDetails);
|
||||
|
||||
}
|
||||
|
||||
private static List<IngredientWithDetails> MergeIngredientsWithDetails(
|
||||
Ingredient[] ingredients, RecipeIngredient[] details)
|
||||
{
|
||||
List<IngredientWithDetails> output = [];
|
||||
|
||||
foreach (var ing in ingredients)
|
||||
{
|
||||
RecipeIngredient? CurrentDetails = details.Where(ri =>
|
||||
ri.IngredientId == ing.IngredientId).FirstOrDefault();
|
||||
|
||||
output.Add(new IngredientWithDetails
|
||||
{
|
||||
Ingredient = ing,
|
||||
Details = new IngredientDetails
|
||||
{
|
||||
Amount = CurrentDetails?.Amount,
|
||||
Unit = CurrentDetails?.Unit,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
<Folder Include="secrets\" />
|
||||
<Folder Include="TagHelpers\" />
|
||||
<Folder Include="__notes__\" />
|
||||
<Folder Include="ViewModels\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
10
Unbinder/ViewModels/RecipeViewModel.cs
Normal file
10
Unbinder/ViewModels/RecipeViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Unbinder.Models;
|
||||
|
||||
namespace Unbinder.ViewModels
|
||||
{
|
||||
public class RecipeViewModel(Recipe _recipe, IEnumerable<IngredientWithDetails>? _ingredients)
|
||||
{
|
||||
public Recipe Recipe { get; init; } = _recipe;
|
||||
public IEnumerable<IngredientWithDetails>? Ingredients { get; init; } = _ingredients;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,48 @@
|
||||
@model Recipe
|
||||
@model RecipeViewModel
|
||||
|
||||
@{
|
||||
var editMode = ViewBag.EditMode ?? false;
|
||||
Recipe recipe = Model.Recipe;
|
||||
IEnumerable<IngredientWithDetails>? entries = Model.Ingredients;
|
||||
}
|
||||
|
||||
<div id="recipe-details-by-id">
|
||||
<h1>@Model.Name</h1>
|
||||
<p>@Model.ShortDescription</p>
|
||||
<h1>@recipe.Name</h1>
|
||||
<p>@recipe.ShortDescription</p>
|
||||
|
||||
@if (Model.RecipeText != null)
|
||||
@if (entries != null)
|
||||
{
|
||||
<div id="ingredient-list">
|
||||
<h2>Ingredients:</h2>
|
||||
<div>
|
||||
@foreach (var entry in entries)
|
||||
{
|
||||
var measurementString = "";
|
||||
if (entry.Details.Amount != null) measurementString += entry.Details.Amount.ToString();
|
||||
if (entry.Details.Unit != null) measurementString += entry.Details.Unit;
|
||||
|
||||
<div>
|
||||
<p>@entry.Ingredient.Name -- @measurementString</p>
|
||||
</div>
|
||||
|
||||
}
|
||||
</div>
|
||||
|
||||
<br />
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (recipe.RecipeText != null)
|
||||
{
|
||||
<div id="recipe-text">
|
||||
<p>@Model.RecipeText</p>
|
||||
<p>@recipe.RecipeText</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (recipe.S3Url != null)
|
||||
{
|
||||
<div id="recipe-image-or-pdf">
|
||||
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
Reference in New Issue
Block a user