add CategoryController with endpoints
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
using Francesco.Recipes.World.Repositories.Category;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
[ValidateAntiForgeryToken]
|
||||
[Route("Category")]
|
||||
|
||||
public class CategoryController : Controller
|
||||
@@ -37,7 +38,7 @@
|
||||
public async Task<ActionResult<IEnumerable<Recipe>>> GetRecipesByCategory(Guid id)
|
||||
{
|
||||
var recipes = await _categoryRepository.GetRecipesByCategoryAsync(id);
|
||||
return Ok(recipes);
|
||||
return View(recipes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,48 @@
|
||||
namespace Francesco.Recipes.World.Controller.MediaFile
|
||||
{
|
||||
public class MediaFileController
|
||||
using Francesco.Recipes.World.Data;
|
||||
using Francesco.Recipes.World.Repositories.MediaFile;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
[ValidateAntiForgeryToken]
|
||||
|
||||
[Route("categories/{categoryId}/Recipe")]
|
||||
public class MediaFileController : Controller
|
||||
{
|
||||
private readonly IMediaFileRepository _mediaFileRepository;
|
||||
private readonly FrancescosRecipesWorldDbContext _context;
|
||||
|
||||
public MediaFileController(IMediaFileRepository mediaFileRepository, FrancescosRecipesWorldDbContext context)
|
||||
{
|
||||
_mediaFileRepository = mediaFileRepository;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
// POST: /UploadImage
|
||||
[HttpPost("UploadImage")]
|
||||
public async Task<IActionResult> UploadImage(Guid recipeId, IFormFile? mediaFile)
|
||||
{
|
||||
if (mediaFile is null)
|
||||
{
|
||||
return BadRequest("Photo is required.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _mediaFileRepository.UploadRecipeMediaAsync(recipeId, mediaFile);
|
||||
return Ok("Image uploaded successfully.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return StatusCode(500, $"Internal server error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// GET: /UploadImage
|
||||
[HttpGet("UploadImage")]
|
||||
public IActionResult UploadImageView()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,94 @@
|
||||
namespace Francesco.Recipes.World.Controller.Recipe
|
||||
{
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Recipe;
|
||||
using Francesco.Recipes.World.Repositories.Category;
|
||||
using Francesco.Recipes.World.Repositories.Favorit;
|
||||
using Francesco.Recipes.World.Repositories.Ingredient;
|
||||
using Francesco.Recipes.World.Repositories.Instruction;
|
||||
using Francesco.Recipes.World.Repositories.MediaFile;
|
||||
using Francesco.Recipes.World.Repositories.Recipe;
|
||||
using Francesco.Recipes.World.Repositories.Unit;
|
||||
using Francesco.Recipes.World.Views.Category;
|
||||
using Francesco.Recipes.World.Views.Recipe;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
[Route("categories/{categoryId}/Recipe")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[Route("Recipe")]
|
||||
public class RecipeController : Controller
|
||||
{
|
||||
private readonly IRecipeRepository _recipeRepository;
|
||||
private readonly IUnitRepository _unitRepository;
|
||||
private readonly ICategoryRepository _categoryRepository;
|
||||
private readonly IIngredientRepository _ingredientRepository;
|
||||
private readonly IMediaFileRepository _mediaFileRepository;
|
||||
private readonly IInstructionRepository _instructionRepository;
|
||||
private readonly IFavoritRepository _favoritRepository;
|
||||
|
||||
public RecipeController(IRecipeRepository recipeRepository, IUnitRepository unitRepository, ICategoryRepository categoryRepository, IIngredientRepository ingredientRepository)
|
||||
[Display(Name = "Schwierigkeitsgrad")]
|
||||
[BindProperty(SupportsGet = true)]
|
||||
public Difficulty? SelectedDifficulty { get; set; }
|
||||
|
||||
public RecipeController(IRecipeRepository recipeRepository, IUnitRepository unitRepository, ICategoryRepository categoryRepository, IIngredientRepository ingredientRepository, IMediaFileRepository mediaFileRepository, IInstructionRepository instructionRepository, IFavoritRepository favoritRepository)
|
||||
{
|
||||
_recipeRepository = recipeRepository;
|
||||
_unitRepository = unitRepository;
|
||||
_categoryRepository = categoryRepository;
|
||||
_ingredientRepository = ingredientRepository;
|
||||
Recipes = new List<Recipe>();
|
||||
_mediaFileRepository = mediaFileRepository;
|
||||
_instructionRepository = instructionRepository;
|
||||
_favoritRepository = favoritRepository;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<Recipe> Recipes { get; set; }
|
||||
|
||||
// GET: /Recipe/AddOrCreateIngredient
|
||||
// GET: /Recipe/{recipeId}/AddOrCreateIngredient
|
||||
[HttpGet("{recipeId}/AddOrCreateIngredient")]
|
||||
public async Task<IActionResult> AddOrCreateIngredient()
|
||||
public async Task<IActionResult> AddOrCreateIngredient(Guid recipeId)
|
||||
{
|
||||
var units = await _unitRepository.GetAllUnitsAsync();
|
||||
ViewBag.Units = new SelectList(units, "Id", "Name");
|
||||
ViewBag.RecipeId = recipeId;
|
||||
return View();
|
||||
}
|
||||
|
||||
// POST: /Recipe/AddOrCreateIngredient
|
||||
// GET: /Recipe/Details/{recipeId}
|
||||
[HttpGet("Details/{recipeId}")]
|
||||
public async Task<IActionResult> Details(Guid recipeId)
|
||||
{
|
||||
var recipe = await _recipeRepository.GetRecipeByIdAsync(recipeId);
|
||||
if (recipe == null)
|
||||
{
|
||||
return NotFound("Recipe not found.");
|
||||
}
|
||||
|
||||
return View(recipe);
|
||||
}
|
||||
|
||||
// GET: /Recipe/CategoryRecipes
|
||||
[HttpGet("CategoryRecipes")]
|
||||
public async Task<IActionResult> CategoryRecipes()
|
||||
{
|
||||
var categories = await _categoryRepository.GetAllCategoriesAsync();
|
||||
var viewModel = new List<CategoryRecipesViewModel>();
|
||||
|
||||
foreach (var category in categories)
|
||||
{
|
||||
var recipes = await _categoryRepository.GetRecipesByCategoryAsync(category.Id);
|
||||
viewModel.Add(new CategoryRecipesViewModel
|
||||
{
|
||||
Category = category,
|
||||
Recipes = recipes,
|
||||
});
|
||||
}
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// POST: /Recipe/{recipeId}/AddOrCreateIngredient
|
||||
[HttpPost("{recipeId}/AddOrCreateIngredient")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> AddOrCreateIngredient(Guid recipeId, string ingredientName, int quantity, Guid unitId)
|
||||
{
|
||||
if (quantity <= 0)
|
||||
@@ -56,8 +107,8 @@
|
||||
return RedirectToAction("Details", new { id = recipeId });
|
||||
}
|
||||
|
||||
// GET: /categories/{categoryId}/Recipe/Create
|
||||
[HttpGet("Create")]
|
||||
// GET: /Recipe/Create/{categoryId}
|
||||
[HttpGet("Create/{categoryId}")]
|
||||
public async Task<IActionResult> Create(Guid categoryId)
|
||||
{
|
||||
var category = await _categoryRepository.GetCategoryByIdAsync(categoryId);
|
||||
@@ -70,10 +121,9 @@
|
||||
return View();
|
||||
}
|
||||
|
||||
// POST: /categories/{categoryId}/Recipe/Create
|
||||
[HttpPost("Create")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Create(Guid categoryId, string name, string description, Difficulty difficulty, int servings, TimeSpan preparationTime, TimeSpan cookingTime)
|
||||
// POST: /Recipe/Create/{categoryId}
|
||||
[HttpPost("Create/{categoryId}")]
|
||||
public async Task<IActionResult> Create(Guid categoryId, string name, string description, Difficulty difficulty, int servings, TimeSpan preparationTime, TimeSpan cookingTime, IFormFile? photo)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
@@ -103,13 +153,18 @@
|
||||
return NotFound($"Kategorie mit ID {categoryId} wurde nicht gefunden.");
|
||||
}
|
||||
|
||||
await _recipeRepository.CreateRecipeForCategoryAsync(categoryEntity, name, description, difficulty, servings, preparationTime, cookingTime);
|
||||
var recipe = await _recipeRepository.CreateRecipeForCategoryAsync(categoryEntity, name, description, difficulty, servings, preparationTime, cookingTime);
|
||||
if (photo != null)
|
||||
{
|
||||
await _mediaFileRepository.UploadRecipeMediaAsync(recipe.Id, photo);
|
||||
}
|
||||
|
||||
return RedirectToAction("Details", "Category", new { id = categoryId });
|
||||
}
|
||||
|
||||
// GET: /categories/{categoryId}/Recipe/{recipeId}/RemoveIngredient/{ingredientId}
|
||||
// GET: /Recipe/{recipeId}/RemoveIngredient/{ingredientId}
|
||||
[HttpGet("{recipeId}/RemoveIngredient/{ingredientId}")]
|
||||
public async Task<IActionResult> RemoveIngredient(Guid categoryId, Guid recipeId, Guid ingredientId)
|
||||
public async Task<IActionResult> RemoveIngredient(Guid recipeId, Guid ingredientId)
|
||||
{
|
||||
var recipe = await _recipeRepository.GetRecipeAsync(recipeId);
|
||||
var ingredient = await _ingredientRepository.GetIngredientByIdAsync(ingredientId);
|
||||
@@ -121,28 +176,87 @@
|
||||
|
||||
ViewBag.RecipeId = recipeId;
|
||||
ViewBag.IngredientId = ingredientId;
|
||||
ViewBag.CategoryId = categoryId;
|
||||
ViewBag.IngredientName = ingredient.Name;
|
||||
|
||||
return View();
|
||||
}
|
||||
|
||||
// POST: /categories/{categoryId}/Recipe/{recipeId}/RemoveIngredient/{ingredientId}
|
||||
// POST: /Recipe/{recipeId}/RemoveIngredient/{ingredientId}
|
||||
[HttpPost("{recipeId}/RemoveIngredient/{ingredientId}")]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> RemoveIngredientConfirmed(Guid categoryId, Guid recipeId, Guid ingredientId)
|
||||
public async Task<IActionResult> RemoveIngredientConfirmed(Guid recipeId, Guid ingredientId)
|
||||
{
|
||||
await _recipeRepository.RemoveIngredientFromRecipeAsync(recipeId, ingredientId);
|
||||
TempData["SuccessMessage"] = "Ingredient removed successfully.";
|
||||
return RedirectToAction("Details", new { id = recipeId });
|
||||
}
|
||||
|
||||
// GET: /categories/{categoryId}/Recipe/FilterByDifficulty
|
||||
// GET: /Recipe/FilterByDifficulty
|
||||
[HttpGet("FilterByDifficulty")]
|
||||
public async Task<IActionResult> FilterByDifficulty(Difficulty? difficulty)
|
||||
public async Task<IActionResult> FilterByDifficulty(Difficulty? selectedDifficulty)
|
||||
{
|
||||
Recipes = await _recipeRepository.GetRecipesByDifficultyAsync(difficulty);
|
||||
return View(Recipes);
|
||||
var recipes = await _recipeRepository.GetRecipesByDifficultyAsync(selectedDifficulty);
|
||||
var viewModel = new FilterByDifficultyViewModel
|
||||
{
|
||||
SelectedDifficulty = selectedDifficulty,
|
||||
Recipes = recipes,
|
||||
};
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
// GET: /Recipe/{recipeId}/AddInstruction
|
||||
[HttpGet("{recipeId}/AddInstruction")]
|
||||
public async Task<IActionResult> AddInstruction(Guid recipeId)
|
||||
{
|
||||
var recipe = await _recipeRepository.GetRecipeByIdAsync(recipeId);
|
||||
if (recipe == null)
|
||||
{
|
||||
return NotFound("Recipe not found.");
|
||||
}
|
||||
|
||||
ViewBag.RecipeId = recipeId;
|
||||
return View(recipe);
|
||||
}
|
||||
|
||||
// POST: /Recipe/{recipeId}/AddInstruction
|
||||
[HttpPost("{recipeId}/AddInstruction")]
|
||||
public async Task<IActionResult> AddInstruction(Guid recipeId, string description, int number)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _instructionRepository.CreateInstructionToRecipeAsync(recipeId, description, number);
|
||||
return RedirectToAction("AddInstruction", new { recipeId });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ModelState.AddModelError(string.Empty, ex.Message);
|
||||
var recipe = await _recipeRepository.GetRecipeByIdAsync(recipeId);
|
||||
ViewBag.RecipeId = recipeId;
|
||||
return View(recipe);
|
||||
}
|
||||
}
|
||||
|
||||
// GET: /Recipe/Favorites
|
||||
[HttpGet("Favorites")]
|
||||
public async Task<IActionResult> Favorites()
|
||||
{
|
||||
var favoriteRecipes = await _favoritRepository.GetFavoriteRecipesAsync();
|
||||
return View(favoriteRecipes);
|
||||
}
|
||||
|
||||
// POST: /Recipe/AddFavorite
|
||||
[HttpPost("AddFavorite")]
|
||||
public async Task<IActionResult> AddFavorite(Guid recipeId)
|
||||
{
|
||||
await _favoritRepository.AddFavoriteAsync(recipeId);
|
||||
return RedirectToAction("Details", new { recipeId });
|
||||
}
|
||||
|
||||
// POST: /Recipe/RemoveFavorite
|
||||
[HttpPost("RemoveFavorite")]
|
||||
public async Task<IActionResult> RemoveFavorite(Guid recipeId)
|
||||
{
|
||||
await _favoritRepository.RemoveFavoriteAsync(recipeId);
|
||||
return RedirectToAction("Details", new { recipeId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,50 @@
|
||||
namespace Francesco.Recipes.World.Controller.ShoppingList
|
||||
namespace Francesco.Recipes.World.Controllers
|
||||
{
|
||||
public class ShoppingListController
|
||||
using Francesco.Recipes.World.Data;
|
||||
using Francesco.Recipes.World.Repositories.ShoppingList;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
[Route("ShoppingList")]
|
||||
public class ShoppingListController : Controller
|
||||
{
|
||||
private readonly IShoppingListRepository _shoppingListRepository;
|
||||
private readonly FrancescosRecipesWorldDbContext _context;
|
||||
|
||||
public ShoppingListController(IShoppingListRepository shoppingListRepository, FrancescosRecipesWorldDbContext context)
|
||||
{
|
||||
_shoppingListRepository = shoppingListRepository;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
[HttpPost("CreateOrAddIngredients")]
|
||||
public async Task<IActionResult> CreateOrAddIngredients([FromBody] CreateOrAddIngredientsRequest request)
|
||||
{
|
||||
if (request == null || request.IngredientIds == null || !request.IngredientIds.Any())
|
||||
{
|
||||
return BadRequest("No ingredients provided.");
|
||||
}
|
||||
|
||||
await _shoppingListRepository.AddIngredientsToShoppingListAsync(request.RecipeId, request.IngredientIds);
|
||||
|
||||
var shoppingList = await _context.ShoppingLists
|
||||
.Include(sl => sl.RecipeShoppingList)
|
||||
.ThenInclude(rsl => rsl.Recipe)
|
||||
.FirstOrDefaultAsync(sl => sl.RecipeShoppingList.Any(rsl => rsl.Recipe.Id == request.RecipeId));
|
||||
|
||||
if (shoppingList == null)
|
||||
{
|
||||
return BadRequest("Error creating shopping list.");
|
||||
}
|
||||
|
||||
return Json(new { shoppingListId = shoppingList.Id });
|
||||
}
|
||||
|
||||
public class CreateOrAddIngredientsRequest
|
||||
{
|
||||
public Guid RecipeId { get; set; }
|
||||
|
||||
public List<Guid> IngredientIds { get; set; } = new ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
using Francesco.Recipes.World.Models.BackendModels.MediaFile;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Recipe;
|
||||
using Francesco.Recipes.World.Models.BackendModels.RecipeIngredient;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Shoppinglist;
|
||||
using Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Shoppinglist;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Unit;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@@ -36,6 +37,8 @@
|
||||
|
||||
public DbSet<RecipeIngredientShoppingList> RecipeIngredientsShoppingLists => Set<RecipeIngredientShoppingList>();
|
||||
|
||||
public DbSet<RecipeShoppingList> RecipeShoppingLists => Set<RecipeShoppingList>();
|
||||
|
||||
public DbSet<ShoppingList> ShoppingLists => Set<ShoppingList>();
|
||||
|
||||
public DbSet<MediaFile> MediaFiles => Set<MediaFile>();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
@@ -45,5 +45,13 @@
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include=".\stylecop.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\Category\" />
|
||||
<Folder Include="Services\MediaFile\" />
|
||||
<Folder Include="Services\Ingredient\" />
|
||||
<Folder Include="Services\Instruction\" />
|
||||
<Folder Include="Services\ShoppingList\" />
|
||||
<Folder Include="Services\Recipe\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
+572
@@ -0,0 +1,572 @@
|
||||
// <auto-generated />
|
||||
|
||||
using Francesco.Recipes.World.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Francesco.Recipes.World.Migrations
|
||||
{
|
||||
[DbContext(typeof(FrancescosRecipesWorldDbContext))]
|
||||
[Migration("20250402120842_UpdateShoppingLIstLogic")]
|
||||
partial class UpdateShoppingLIstLogic
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.11")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Category.Category", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Categories");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = new Guid("b248244f-f21c-4555-a14d-5dd49a2717cf"),
|
||||
Name = "Vorspeisen & Snacks"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("5186c5d6-5aff-4a6e-baf4-b61b72d889fe"),
|
||||
Name = "Erste Gänge"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("abbc6bb0-97ea-49f5-b31e-6507eb784fd1"),
|
||||
Name = "Hauptgerichte"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("90deec39-dcd0-422d-9018-ac8389e332e1"),
|
||||
Name = "Desserts & Süßspeisen"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("28e39168-701a-4084-81da-d96c987c462f"),
|
||||
Name = "Beilagen & Salate"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("20585b74-4805-4aff-a6df-aa6b7af04ff1"),
|
||||
Name = "Kuchen"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("adfb75ce-3ef3-428b-a5ca-b0c4c619d5ec"),
|
||||
Name = "Hefegebäck & Brot"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("d332f88d-d241-48c5-a2f2-bfd124eada7e"),
|
||||
Name = "Soßen & Saucen"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("23b1c740-e427-44f9-a6ea-d33d3f30f05a"),
|
||||
Name = "Marmeladen & Eingemachtes"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("0a91a200-dc76-4e00-b38c-b38cab5b69d7"),
|
||||
Name = "Getränke"
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Favorit.Favorit", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Favorits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Ingredient.Ingredient", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Ingredients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.IngredientShoppingList.RecipeIngredientShoppingList", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("IngredientId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("IsChecked")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<Guid>("RecipeIngredientId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("RecipeShoppingListId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IngredientId");
|
||||
|
||||
b.HasIndex("RecipeIngredientId");
|
||||
|
||||
b.HasIndex("RecipeShoppingListId");
|
||||
|
||||
b.ToTable("RecipeIngredientsShoppingLists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Instruction.Instruction", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("Number")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<Guid>("RecipeId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RecipeId");
|
||||
|
||||
b.ToTable("Instructions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.MediaFile.MediaFile", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<byte[]>("Data")
|
||||
.HasColumnType("varbinary(max)");
|
||||
|
||||
b.Property<string>("FileName")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<Guid>("InstructionId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("MimeType")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<Guid?>("RecipeId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("InstructionId");
|
||||
|
||||
b.HasIndex("RecipeId");
|
||||
|
||||
b.ToTable("MediaFiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("CategoryId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<TimeSpan>("CookingTime")
|
||||
.HasColumnType("time");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("Difficulty")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<Guid>("FavoritId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("IsFavorite")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<DateTime?>("ModifiedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<TimeSpan>("PreparationTime")
|
||||
.HasColumnType("time");
|
||||
|
||||
b.Property<int>("Servings")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CategoryId");
|
||||
|
||||
b.HasIndex("FavoritId");
|
||||
|
||||
b.ToTable("Recipes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.RecipeIngredient.RecipeIngredient", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("IngredientId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<int>("Quantity")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<Guid>("RecipeId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("UnitId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("IngredientId");
|
||||
|
||||
b.HasIndex("RecipeId");
|
||||
|
||||
b.HasIndex("UnitId");
|
||||
|
||||
b.ToTable("RecipeIngredients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList.RecipeShoppingList", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("RecipeId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("ShoppingListId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RecipeId");
|
||||
|
||||
b.HasIndex("ShoppingListId");
|
||||
|
||||
b.ToTable("RecipeShoppingLists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Shoppinglist.ShoppingList", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime?>("ModifiedAt")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ShoppingLists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Unit.Unit", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Symbol")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Units");
|
||||
|
||||
b.HasData(
|
||||
new
|
||||
{
|
||||
Id = new Guid("62eb2c11-8768-46fb-9db0-c77f940bb4aa"),
|
||||
Name = "liter",
|
||||
Symbol = "l"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("6c41f7e6-ca75-49cc-8541-cebd5a9c560b"),
|
||||
Name = "gramm",
|
||||
Symbol = "g"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("7e3d1b86-ac48-45d6-814e-d3492a86db1d"),
|
||||
Name = "kilogramm",
|
||||
Symbol = "kg"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("0c3648ec-4981-42c8-abf8-18bf1a2ff4c2"),
|
||||
Name = "stücke",
|
||||
Symbol = "stk"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("d82f4abd-e4e4-4104-a9c0-1acdeaa701f5"),
|
||||
Name = "blatt",
|
||||
Symbol = "blatt"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("df5cb4c3-4de6-4c6f-be8c-da41b2986408"),
|
||||
Name = "messerspitze",
|
||||
Symbol = "msp"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("e45a3af2-2ed6-4ac4-b06f-b4175663a7be"),
|
||||
Name = "stange",
|
||||
Symbol = "stange"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("7ea2f51d-7493-4f19-a663-1f309186d3ae"),
|
||||
Name = "bund",
|
||||
Symbol = "bund"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("66556e0e-eb2b-4bc3-9a56-135dd508ed09"),
|
||||
Name = "zehe",
|
||||
Symbol = "zehe"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("2e9894ac-14fa-43fd-ba07-35cdd8ebd461"),
|
||||
Name = "teelöffel",
|
||||
Symbol = "TL"
|
||||
},
|
||||
new
|
||||
{
|
||||
Id = new Guid("24a91b89-3389-4465-89e4-2f70d2ea6fd7"),
|
||||
Name = "esslöffel",
|
||||
Symbol = "EL"
|
||||
});
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.IngredientShoppingList.RecipeIngredientShoppingList", b =>
|
||||
{
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Ingredient.Ingredient", null)
|
||||
.WithMany("IngredientShoppingLists")
|
||||
.HasForeignKey("IngredientId");
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.RecipeIngredient.RecipeIngredient", "RecipeIngredient")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipeIngredientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList.RecipeShoppingList", "RecipeShoppingList")
|
||||
.WithMany("SelectedIngredients")
|
||||
.HasForeignKey("RecipeShoppingListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("RecipeIngredient");
|
||||
|
||||
b.Navigation("RecipeShoppingList");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Instruction.Instruction", b =>
|
||||
{
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe", "Recipe")
|
||||
.WithMany("Instructions")
|
||||
.HasForeignKey("RecipeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Recipe");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.MediaFile.MediaFile", b =>
|
||||
{
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Instruction.Instruction", "Instruction")
|
||||
.WithMany("MediaFiles")
|
||||
.HasForeignKey("InstructionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe", "Recipe")
|
||||
.WithMany("MediaFiles")
|
||||
.HasForeignKey("RecipeId");
|
||||
|
||||
b.Navigation("Instruction");
|
||||
|
||||
b.Navigation("Recipe");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe", b =>
|
||||
{
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Category.Category", "Category")
|
||||
.WithMany("Recipes")
|
||||
.HasForeignKey("CategoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Favorit.Favorit", "Favorit")
|
||||
.WithMany("Recipe")
|
||||
.HasForeignKey("FavoritId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Category");
|
||||
|
||||
b.Navigation("Favorit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.RecipeIngredient.RecipeIngredient", b =>
|
||||
{
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Ingredient.Ingredient", "Ingredient")
|
||||
.WithMany("RecipeIngredients")
|
||||
.HasForeignKey("IngredientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe", "Recipe")
|
||||
.WithMany("RecipeIngredients")
|
||||
.HasForeignKey("RecipeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Unit.Unit", "Unit")
|
||||
.WithMany("RecipeIngredient")
|
||||
.HasForeignKey("UnitId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ingredient");
|
||||
|
||||
b.Navigation("Recipe");
|
||||
|
||||
b.Navigation("Unit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList.RecipeShoppingList", b =>
|
||||
{
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe", "Recipe")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Shoppinglist.ShoppingList", "ShoppingList")
|
||||
.WithMany("RecipeIngredientShoppingLists")
|
||||
.HasForeignKey("ShoppingListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Recipe");
|
||||
|
||||
b.Navigation("ShoppingList");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Category.Category", b =>
|
||||
{
|
||||
b.Navigation("Recipes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Favorit.Favorit", b =>
|
||||
{
|
||||
b.Navigation("Recipe");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Ingredient.Ingredient", b =>
|
||||
{
|
||||
b.Navigation("IngredientShoppingLists");
|
||||
|
||||
b.Navigation("RecipeIngredients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Instruction.Instruction", b =>
|
||||
{
|
||||
b.Navigation("MediaFiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe", b =>
|
||||
{
|
||||
b.Navigation("Instructions");
|
||||
|
||||
b.Navigation("MediaFiles");
|
||||
|
||||
b.Navigation("RecipeIngredients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList.RecipeShoppingList", b =>
|
||||
{
|
||||
b.Navigation("SelectedIngredients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Shoppinglist.ShoppingList", b =>
|
||||
{
|
||||
b.Navigation("RecipeIngredientShoppingLists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Unit.Unit", b =>
|
||||
{
|
||||
b.Navigation("RecipeIngredient");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Francesco.Recipes.World.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class UpdateShoppingLIstLogic : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
if (migrationBuilder is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(migrationBuilder));
|
||||
}
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_RecipeIngredientsShoppingLists_ShoppingLists_ShoppingListId",
|
||||
table: "RecipeIngredientsShoppingLists");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Recipes_Categories_CategoryId",
|
||||
table: "Recipes");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "ShoppingListId",
|
||||
table: "RecipeIngredientsShoppingLists",
|
||||
newName: "RecipeShoppingListId");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_RecipeIngredientsShoppingLists_ShoppingListId",
|
||||
table: "RecipeIngredientsShoppingLists",
|
||||
newName: "IX_RecipeIngredientsShoppingLists_RecipeShoppingListId");
|
||||
|
||||
migrationBuilder.AlterColumn<Guid>(
|
||||
name: "CategoryId",
|
||||
table: "Recipes",
|
||||
type: "uniqueidentifier",
|
||||
nullable: false,
|
||||
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
|
||||
oldClrType: typeof(Guid),
|
||||
oldType: "uniqueidentifier",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<bool>(
|
||||
name: "IsChecked",
|
||||
table: "RecipeIngredientsShoppingLists",
|
||||
type: "bit",
|
||||
nullable: false,
|
||||
defaultValue: false);
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "RecipeShoppingLists",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
ShoppingListId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
RecipeId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_RecipeShoppingLists", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_RecipeShoppingLists_Recipes_RecipeId",
|
||||
column: x => x.RecipeId,
|
||||
principalTable: "Recipes",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_RecipeShoppingLists_ShoppingLists_ShoppingListId",
|
||||
column: x => x.ShoppingListId,
|
||||
principalTable: "ShoppingLists",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_RecipeShoppingLists_RecipeId",
|
||||
table: "RecipeShoppingLists",
|
||||
column: "RecipeId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_RecipeShoppingLists_ShoppingListId",
|
||||
table: "RecipeShoppingLists",
|
||||
column: "ShoppingListId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_RecipeIngredientsShoppingLists_RecipeShoppingLists_RecipeShoppingListId",
|
||||
table: "RecipeIngredientsShoppingLists",
|
||||
column: "RecipeShoppingListId",
|
||||
principalTable: "RecipeShoppingLists",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.NoAction);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Recipes_Categories_CategoryId",
|
||||
table: "Recipes",
|
||||
column: "CategoryId",
|
||||
principalTable: "Categories",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
if (migrationBuilder is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(migrationBuilder));
|
||||
}
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_RecipeIngredientsShoppingLists_RecipeShoppingLists_RecipeShoppingListId",
|
||||
table: "RecipeIngredientsShoppingLists");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Recipes_Categories_CategoryId",
|
||||
table: "Recipes");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "RecipeShoppingLists");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IsChecked",
|
||||
table: "RecipeIngredientsShoppingLists");
|
||||
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "RecipeShoppingListId",
|
||||
table: "RecipeIngredientsShoppingLists",
|
||||
newName: "ShoppingListId");
|
||||
|
||||
migrationBuilder.RenameIndex(
|
||||
name: "IX_RecipeIngredientsShoppingLists_RecipeShoppingListId",
|
||||
table: "RecipeIngredientsShoppingLists",
|
||||
newName: "IX_RecipeIngredientsShoppingLists_ShoppingListId");
|
||||
|
||||
migrationBuilder.AlterColumn<Guid>(
|
||||
name: "CategoryId",
|
||||
table: "Recipes",
|
||||
type: "uniqueidentifier",
|
||||
nullable: true,
|
||||
oldClrType: typeof(Guid),
|
||||
oldType: "uniqueidentifier");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_RecipeIngredientsShoppingLists_ShoppingLists_ShoppingListId",
|
||||
table: "RecipeIngredientsShoppingLists",
|
||||
column: "ShoppingListId",
|
||||
principalTable: "ShoppingLists",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Recipes_Categories_CategoryId",
|
||||
table: "Recipes",
|
||||
column: "CategoryId",
|
||||
principalTable: "Categories",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
// <auto-generated />
|
||||
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
|
||||
|
||||
@@ -124,10 +127,13 @@ namespace Francesco.Recipes.World.Migrations
|
||||
b.Property<Guid?>("IngredientId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<bool>("IsChecked")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<Guid>("RecipeIngredientId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("ShoppingListId")
|
||||
b.Property<Guid>("RecipeShoppingListId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
@@ -136,7 +142,7 @@ namespace Francesco.Recipes.World.Migrations
|
||||
|
||||
b.HasIndex("RecipeIngredientId");
|
||||
|
||||
b.HasIndex("ShoppingListId");
|
||||
b.HasIndex("RecipeShoppingListId");
|
||||
|
||||
b.ToTable("RecipeIngredientsShoppingLists");
|
||||
});
|
||||
@@ -200,7 +206,7 @@ namespace Francesco.Recipes.World.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid?>("CategoryId")
|
||||
b.Property<Guid>("CategoryId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<TimeSpan>("CookingTime")
|
||||
@@ -272,6 +278,27 @@ namespace Francesco.Recipes.World.Migrations
|
||||
b.ToTable("RecipeIngredients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList.RecipeShoppingList", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("RecipeId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("ShoppingListId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RecipeId");
|
||||
|
||||
b.HasIndex("ShoppingListId");
|
||||
|
||||
b.ToTable("RecipeShoppingLists");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Shoppinglist.ShoppingList", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
@@ -388,15 +415,15 @@ namespace Francesco.Recipes.World.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Shoppinglist.ShoppingList", "ShoppingList")
|
||||
.WithMany("RecipeIngredientShoppingLists")
|
||||
.HasForeignKey("ShoppingListId")
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList.RecipeShoppingList", "RecipeShoppingList")
|
||||
.WithMany("SelectedIngredients")
|
||||
.HasForeignKey("RecipeShoppingListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("RecipeIngredient");
|
||||
|
||||
b.Navigation("ShoppingList");
|
||||
b.Navigation("RecipeShoppingList");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Instruction.Instruction", b =>
|
||||
@@ -429,9 +456,11 @@ namespace Francesco.Recipes.World.Migrations
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe", b =>
|
||||
{
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Category.Category", null)
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Category.Category", "Category")
|
||||
.WithMany("Recipes")
|
||||
.HasForeignKey("CategoryId");
|
||||
.HasForeignKey("CategoryId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Favorit.Favorit", "Favorit")
|
||||
.WithMany("Recipe")
|
||||
@@ -439,6 +468,8 @@ namespace Francesco.Recipes.World.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Category");
|
||||
|
||||
b.Navigation("Favorit");
|
||||
});
|
||||
|
||||
@@ -469,6 +500,25 @@ namespace Francesco.Recipes.World.Migrations
|
||||
b.Navigation("Unit");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList.RecipeShoppingList", b =>
|
||||
{
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe", "Recipe")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Francesco.Recipes.World.Models.BackendModels.Shoppinglist.ShoppingList", "ShoppingList")
|
||||
.WithMany("RecipeIngredientShoppingLists")
|
||||
.HasForeignKey("ShoppingListId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Recipe");
|
||||
|
||||
b.Navigation("ShoppingList");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Category.Category", b =>
|
||||
{
|
||||
b.Navigation("Recipes");
|
||||
@@ -500,6 +550,11 @@ namespace Francesco.Recipes.World.Migrations
|
||||
b.Navigation("RecipeIngredients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList.RecipeShoppingList", b =>
|
||||
{
|
||||
b.Navigation("SelectedIngredients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Francesco.Recipes.World.Models.BackendModels.Shoppinglist.ShoppingList", b =>
|
||||
{
|
||||
b.Navigation("RecipeIngredientShoppingLists");
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
namespace Francesco.Recipes.World.Models.BackendModels.Recipe
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Francesco.Recipes.World.Models.BackendModels.Recipe
|
||||
{
|
||||
public enum Difficulty
|
||||
{
|
||||
[Display(Name = "Sehr einfach")]
|
||||
VeryEasy = 0,
|
||||
|
||||
[Display(Name = "Einfach")]
|
||||
Easy = 1,
|
||||
|
||||
[Display(Name = "Mittel")]
|
||||
Medium = 2,
|
||||
|
||||
[Display(Name = "Schwer")]
|
||||
Hard = 3,
|
||||
|
||||
[Display(Name = "Experte")]
|
||||
Expert = 4,
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -1,14 +1,16 @@
|
||||
namespace Francesco.Recipes.World.Models.BackendModels.IngredientShoppingList
|
||||
{
|
||||
using Francesco.Recipes.World.Models.BackendModels.RecipeIngredient;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Shoppinglist;
|
||||
using Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList;
|
||||
|
||||
public class RecipeIngredientShoppingList
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public virtual ShoppingList ShoppingList { get; set; } = new ();
|
||||
public virtual RecipeShoppingList RecipeShoppingList { get; set; } = new ();
|
||||
|
||||
public virtual RecipeIngredient RecipeIngredient { get; set; } = new ();
|
||||
|
||||
public bool IsChecked { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList
|
||||
{
|
||||
using Francesco.Recipes.World.Models.BackendModels.IngredientShoppingList;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Recipe;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Shoppinglist;
|
||||
|
||||
public class RecipeShoppingList
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public virtual ShoppingList ShoppingList { get; set; } = new ShoppingList();
|
||||
|
||||
public virtual Recipe Recipe { get; set; } = new ();
|
||||
|
||||
public virtual ICollection<RecipeIngredientShoppingList> SelectedIngredients { get; set; } = new List<RecipeIngredientShoppingList>();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Francesco.Recipes.World.Models.BackendModels.Shoppinglist
|
||||
{
|
||||
using Francesco.Recipes.World.Models.BackendModels.IngredientShoppingList;
|
||||
using Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList;
|
||||
|
||||
public class ShoppingList : ITimeStampedEntity
|
||||
{
|
||||
@@ -10,6 +10,6 @@
|
||||
|
||||
public DateTime? ModifiedAt { get; set; }
|
||||
|
||||
public virtual ICollection<RecipeIngredientShoppingList> RecipeIngredientShoppingLists { get; set; } = new List<RecipeIngredientShoppingList>();
|
||||
public virtual ICollection<RecipeShoppingList> RecipeShoppingList { get; set; } = new List<RecipeShoppingList>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Francesco.Recipes.World.Data;
|
||||
using Francesco.Recipes.World.Repositories.Category;
|
||||
using Francesco.Recipes.World.Repositories.Favorit;
|
||||
using Francesco.Recipes.World.Repositories.Ingredient;
|
||||
using Francesco.Recipes.World.Repositories.Instruction;
|
||||
using Francesco.Recipes.World.Repositories.MediaFile;
|
||||
@@ -7,8 +8,6 @@ using Francesco.Recipes.World.Repositories.Recipe;
|
||||
using Francesco.Recipes.World.Repositories.ShoppingList;
|
||||
using Francesco.Recipes.World.Repositories.Unit;
|
||||
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
@@ -23,9 +22,6 @@ var connectionString = builder.Configuration.GetConnectionString("FrancescosReci
|
||||
services.AddDbContext<FrancescosRecipesWorldDbContext>(options =>
|
||||
options.UseSqlServer(connectionString));
|
||||
|
||||
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||
.AddEntityFrameworkStores<FrancescosRecipesWorldDbContext>();
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddControllersWithViews();
|
||||
|
||||
@@ -43,6 +39,8 @@ builder.Services.AddScoped<IMediaFileRepository, MediaFileRepository>();
|
||||
|
||||
builder.Services.AddScoped<IInstructionRepository, InstructionRepository>();
|
||||
|
||||
builder.Services.AddScoped<IFavoritRepository, FavoritRepository>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
@@ -62,10 +60,6 @@ app.UseStaticFiles();
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthentication();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapDefaultControllerRoute();
|
||||
|
||||
app.MapControllerRoute(
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Francesco.Recipes.World.Views.Category
|
||||
{
|
||||
using Francesco.Recipes.World.Models.BackendModels.Category;
|
||||
using Francesco.Recipes.World.Models.BackendModels.Recipe;
|
||||
|
||||
public class CategoryRecipesViewModel
|
||||
{
|
||||
public Category Category { get; set; } = new ();
|
||||
|
||||
public IEnumerable<Recipe> Recipes { get; set; } = new List<Recipe>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
@model Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Add Instructions";
|
||||
}
|
||||
|
||||
<h1>Add Instructions to @Model.Name</h1>
|
||||
|
||||
<div class="instructions-list">
|
||||
<h3>Existing Instructions</h3>
|
||||
<ul>
|
||||
@foreach (var instruction in Model.Instructions.OrderBy(i => i.Number))
|
||||
{
|
||||
<li>@instruction.Number. @instruction.Description</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="add-instruction-form">
|
||||
<h3>Add New Instruction</h3>
|
||||
<form id="instruction-form" method="post" asp-action="AddInstruction" asp-controller="Recipe">
|
||||
<input type="hidden" name="recipeId" value="@Model.Id" />
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<input type="text" class="form-control" id="description" name="description" required />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="number">Number</label>
|
||||
<input type="number" class="form-control" id="number" name="number" required min="1" />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary" onclick="addInstructionToRecipe()">Add Instruction</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
async function addInstructionToRecipe() {
|
||||
var form = document.getElementById('instruction-form');
|
||||
var recipeId = form.querySelector('input[name="recipeId"]').value;
|
||||
var description = form.querySelector('input[name="description"]').value;
|
||||
var number = form.querySelector('input[name="number"]').value;
|
||||
|
||||
var response = await fetch('/Recipe/' + recipeId + '/AddInstruction', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ recipeId: recipeId, description: description, number: number })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Failed to add instruction.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
}
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
@{
|
||||
ViewData["Title"] = "Add or Create Ingredient to Recipe";
|
||||
ViewData["Title"] = "Add or Create Ingredient to Recipe";
|
||||
}
|
||||
|
||||
<h2>@ViewData["Title"]</h2>
|
||||
|
||||
<form asp-action="AddOrCreateIngredient" method="post">
|
||||
<div class="form-group">
|
||||
<label for="RecipeId" class="control-label">Recipe Id</label>
|
||||
<input type="text" id="RecipeId" name="recipeId" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="IngredientName" class="control-label">Ingredient Name</label>
|
||||
<input type="text" id="IngredientName" name="ingredientName" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="Quantity" class="control-label">Quantity</label>
|
||||
<input type="number" id="Quantity" name="quantity" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="UnitId" class="control-label">Unit</label>
|
||||
<select id="UnitId" name="unitId" class="form-control" asp-items="ViewBag.Units"></select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Ingredient</button>
|
||||
<input type="hidden" id="RecipeId" name="recipeId" value="@ViewBag.RecipeId" />
|
||||
<div class="form-group">
|
||||
<label for="IngredientName" class="control-label">Ingredient Name</label>
|
||||
<input type="text" id="IngredientName" name="ingredientName" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="Quantity" class="control-label">Quantity</label>
|
||||
<input type="number" id="Quantity" name="quantity" class="form-control" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="UnitId" class="control-label">Unit</label>
|
||||
<select id="UnitId" name="unitId" class="form-control" asp-items="ViewBag.Units"></select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Add Ingredient</button>
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
<partial name="_ValidationScriptsPartial" />
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
@model IEnumerable<Francesco.Recipes.World.Views.Category.CategoryRecipesViewModel>
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Category Recipes";
|
||||
}
|
||||
|
||||
<h1>Category Recipes</h1>
|
||||
|
||||
@foreach (var categoryRecipes in Model)
|
||||
{
|
||||
<div class="category-section">
|
||||
<h2>@categoryRecipes.Category.Name</h2>
|
||||
<a asp-action="Create" asp-route-categoryId="@categoryRecipes.Category.Id" class="btn btn-primary">Rezept erstellen</a>
|
||||
<div class="recipes">
|
||||
@foreach (var recipe in categoryRecipes.Recipes)
|
||||
{
|
||||
<div class="recipe-card">
|
||||
<div class="recipe-image">
|
||||
@if (recipe.MediaFiles.Any() && recipe.MediaFiles.First().Data != null)
|
||||
{
|
||||
var mediaFile = recipe.MediaFiles.First();
|
||||
if (mediaFile.Data != null)
|
||||
{
|
||||
<img src="data:@mediaFile.MimeType;base64,@Convert.ToBase64String(mediaFile.Data)" alt="@recipe.Name" class="img-fluid" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="recipe-info">
|
||||
<h3>@recipe.Name</h3>
|
||||
<p>@recipe.Description</p>
|
||||
<p><strong>Difficulty:</strong> @recipe.Difficulty</p>
|
||||
<p><strong>Servings:</strong> @recipe.Servings</p>
|
||||
<p><strong>Preparation Time:</strong> @recipe.PreparationTime</p>
|
||||
<p><strong>Cooking Time:</strong> @recipe.CookingTime</p>
|
||||
<div class="recipe-favorite">
|
||||
@if (recipe.IsFavorite)
|
||||
{
|
||||
<form method="post" asp-action="RemoveFavorite" asp-controller="Recipe">
|
||||
<input type="hidden" name="recipeId" value="@recipe.Id" />
|
||||
<button type="submit" class="btn btn-danger">Remove from Favorites</button>
|
||||
</form>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form method="post" asp-action="AddFavorite" asp-controller="Recipe">
|
||||
<input type="hidden" name="recipeId" value="@recipe.Id" />
|
||||
<button type="submit" class="btn btn-primary">Add to Favorites</button>
|
||||
</form>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="recipe-card add-recipe-card">
|
||||
<a asp-action="Create" asp-route-categoryId="@categoryRecipes.Category.Id" class="btn btn-primary">Rezept hinzufügen</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<style>
|
||||
.category-section {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.recipes {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.recipe-card {
|
||||
width: 200px;
|
||||
margin: 1rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.recipe-image img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.recipe-info {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.add-recipe-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f8f8f8;
|
||||
border: 2px dashed #ccc;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,45 +1,53 @@
|
||||
@model Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe
|
||||
@using Francesco.Recipes.World.Models.BackendModels.Recipe
|
||||
@{
|
||||
ViewData["Title"] = "Create Recipe";
|
||||
ViewData["Title"] = "Create Recipe";
|
||||
}
|
||||
|
||||
<h1>Create Recipe</h1>
|
||||
|
||||
<form asp-action="Create" method="post">
|
||||
<div class="form-group">
|
||||
<label asp-for="Name" class="control-label"></label>
|
||||
<input asp-for="Name" class="form-control" />
|
||||
<span asp-validation-for="Name" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Description" class="control-label"></label>
|
||||
<textarea asp-for="Description" class="form-control"></textarea>
|
||||
<span asp-validation-for="Description" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Difficulty" class="control-label"></label>
|
||||
<select asp-for="Difficulty" class="form-control" asp-items="Html.GetEnumSelectList<Difficulty>()"></select>
|
||||
<span asp-validation-for="Difficulty" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Servings" class="control-label"></label>
|
||||
<input asp-for="Servings" class="form-control" />
|
||||
<span asp-validation-for="Servings" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="PreparationTime" class="control-label"></label>
|
||||
<input asp-for="PreparationTime" class="form-control" placeholder="hh:mm:ss" />
|
||||
<span asp-validation-for="PreparationTime" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="CookingTime" class="control-label"></label>
|
||||
<input asp-for="CookingTime" class="form-control" placeholder="hh:mm:ss" />
|
||||
<span asp-validation-for="CookingTime" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="submit" value="Create" class="btn btn-primary" />
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<label asp-for="Name"></label>
|
||||
<input asp-for="Name" class="form-control" />
|
||||
<span asp-validation-for="Name" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Description"></label>
|
||||
<textarea asp-for="Description" class="form-control"></textarea>
|
||||
<span asp-validation-for="Description" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Difficulty"></label>
|
||||
<select asp-for="Difficulty" class="form-control">
|
||||
<option value="">Select Difficulty</option>
|
||||
@foreach (var difficulty in Enum.GetValues(typeof(Difficulty)))
|
||||
{
|
||||
<option value="@difficulty">@difficulty</option>
|
||||
}
|
||||
</select>
|
||||
<span asp-validation-for="Difficulty" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Servings"></label>
|
||||
<input asp-for="Servings" class="form-control" />
|
||||
<span asp-validation-for="Servings" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="PreparationTime"></label>
|
||||
<input asp-for="PreparationTime" class="form-control" />
|
||||
<span asp-validation-for="PreparationTime" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="CookingTime"></label>
|
||||
<input asp-for="CookingTime" class="form-control" />
|
||||
<span asp-validation-for="CookingTime" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="photo">Photo</label>
|
||||
<input type="file" name="photo" class="form-control" />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Create</button>
|
||||
</form>
|
||||
|
||||
@section Scripts {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
@model Francesco.Recipes.World.Models.BackendModels.Recipe.Recipe
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Recipe Details";
|
||||
}
|
||||
|
||||
<h1>@Model.Name</h1>
|
||||
|
||||
<div class="recipe-details">
|
||||
<div class="recipe-image">
|
||||
@if (Model.MediaFiles.Any() && Model.MediaFiles.First().Data != null)
|
||||
{
|
||||
var mediaFile = Model.MediaFiles.First();
|
||||
if (mediaFile.Data != null)
|
||||
{
|
||||
<img src="data:@mediaFile.MimeType;base64,@Convert.ToBase64String(mediaFile.Data)" alt="@Model.Name" class="img-fluid" />
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="recipe-info">
|
||||
<p><strong>Description:</strong> @Model.Description</p>
|
||||
<p><strong>Difficulty:</strong> @Model.Difficulty</p>
|
||||
<p><strong>Servings:</strong> @Model.Servings</p>
|
||||
<p><strong>Preparation Time:</strong> @Model.PreparationTime</p>
|
||||
<p><strong>Cooking Time:</strong> @Model.CookingTime</p>
|
||||
</div>
|
||||
<div class="recipe-ingredients">
|
||||
<h3>Ingredients</h3>
|
||||
<form id="ingredient-form">
|
||||
<ul id="ingredient-list">
|
||||
@foreach (var ingredient in Model.RecipeIngredients)
|
||||
{
|
||||
<li id="ingredient-@ingredient.Id">
|
||||
<input type="checkbox" name="ingredientIds" value="@ingredient.Id" />
|
||||
@ingredient.Ingredient.Name - @ingredient.Quantity @(ingredient.Unit != null ? ingredient.Unit.Symbol : string.Empty)
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<button type="button" class="btn btn-primary" onclick="addSelectedIngredientsToShoppingList()">Add Selected to Shopping List</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
async function addSelectedIngredientsToShoppingList() {
|
||||
var form = document.getElementById('ingredient-form');
|
||||
var formData = new FormData(form);
|
||||
var selectedIngredientIds = formData.getAll('ingredientIds');
|
||||
|
||||
var response = await fetch('/ShoppingList/CreateOrAddIngredients', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ recipeId: '@Model.Id', ingredientIds: selectedIngredientIds })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
var result = await response.json();
|
||||
localStorage.setItem('shoppingListId', result.shoppingListId);
|
||||
alert('Shopping list updated.');
|
||||
} else {
|
||||
alert('Failed to update shopping list.');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@@ -1,42 +1,72 @@
|
||||
@model Francesco.Recipes.World.Views.Recipe.FilterByDifficultyViewModel
|
||||
@using Francesco.Recipes.World.Models.BackendModels.Recipe
|
||||
@using Francesco.Recipes.World.Models.BackendModels.Recipe
|
||||
@model Francesco.Recipes.World.Views.Recipe.FilterByDifficultyViewModel
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Filter Recipes by Difficulty";
|
||||
}
|
||||
<h1>Rezepte nach Schwierigkeitsgrad</h1>
|
||||
|
||||
<h1>Filter Recipes by Difficulty</h1>
|
||||
<div class="mb-3">
|
||||
<a asp-controller="Recipe" asp-action="Create" class="btn btn-primary">Neues Rezept erstellen</a>
|
||||
</div>
|
||||
|
||||
<form asp-action="FilterByDifficulty" method="get" id="filterForm">
|
||||
<div class="form-group">
|
||||
<label asp-for="SelectedDifficulty" class="control-label"></label>
|
||||
<select asp-for="SelectedDifficulty" class="form-control" asp-items="Html.GetEnumSelectList<Difficulty>()" class="form-select" onchange="submitForm()">
|
||||
<option value="">All Difficulties</option>
|
||||
</select>
|
||||
<span asp-validation-for="SelectedDifficulty" class="text-danger"></span>
|
||||
</div>
|
||||
</form>
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<form asp-controller="Recipe" asp-action="FilterByDifficulty" method="get" id="filterForm">
|
||||
<div class="form-group">
|
||||
<label asp-for="SelectedDifficulty" class="form-label">Schwierigkeitsgrad</label>
|
||||
<select asp-for="SelectedDifficulty" asp-items="Html.GetEnumSelectList<Difficulty>()" class="form-select" onchange="submitForm()">
|
||||
<option value="">Alle Schwierigkeitsgrade</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@if (Model.Recipes != null && Model.Recipes.Any())
|
||||
{
|
||||
<h2>Filtered Recipes</h2>
|
||||
<ul>
|
||||
@foreach (var recipe in Model.Recipes)
|
||||
{
|
||||
<li>@recipe.Name - @recipe.Difficulty.</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>No recipes found for the selected difficulty.</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
@if (Model?.Recipes != null && Model.Recipes.Any())
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Beschreibung</th>
|
||||
<th>Schwierigkeitsgrad</th>
|
||||
<th>Portionen</th>
|
||||
<th>Zubereitungszeit</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var recipe in Model.Recipes)
|
||||
{
|
||||
<tr>
|
||||
<td>@recipe.Name</td>
|
||||
<td>@(recipe.Description?.Length > 100 ? recipe.Description.Substring(0, 100) + "..." : recipe.Description)</td>
|
||||
<td>@recipe.?Difficulty</td>
|
||||
<td>@recipe.Servings</td>
|
||||
<td>@($"{recipe.PreparationTime.TotalMinutes} Min.")</td>
|
||||
<td>
|
||||
<a asp-controller="Recipe" asp-action="Details" asp-route-id="@recipe.Id" class="btn btn-sm btn-info">Details</a>
|
||||
<a asp-controller="Recipe" asp-action="Edit" asp-route-id="@recipe.Id" class="btn btn-sm btn-primary">Bearbeiten</a>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="col-12">
|
||||
<p>Keine Rezepte gefunden.</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
function submitForm() {
|
||||
document.getElementById('filterForm').submit();
|
||||
}
|
||||
</script>
|
||||
@await Html.PartialAsync("_ValidationScriptsPartial")
|
||||
<script>
|
||||
function submitForm() {
|
||||
document.getElementById('filterForm').submit();
|
||||
}
|
||||
</script>
|
||||
}
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
{
|
||||
public Difficulty? SelectedDifficulty { get; set; }
|
||||
|
||||
public List<Recipe> Recipes { get; set; } = new List<Recipe>();
|
||||
public IReadOnlyCollection<Recipe> Recipes { get; set; } = new List<Recipe>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
@model IEnumerable<Francesco.Recipes.World.Models.BackendModels.RecipeIngredient.RecipeIngredient>
|
||||
|
||||
<div class="recipe-ingredients">
|
||||
<h3>Zutaten</h3>
|
||||
<form id="ingredient-form">
|
||||
<ul id="ingredient-list">
|
||||
@foreach (var ingredient in Model)
|
||||
{
|
||||
<li id="ingredient-@ingredient.Id">
|
||||
<input type="checkbox" name="ingredientIds" value="@ingredient.Id" />
|
||||
@ingredient.Ingredient.Name - @ingredient.Quantity @ingredient.Unit.Symbol
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
<button type="button" class="btn btn-primary" onclick="addSelectedIngredientsToShoppingList()">Ausgewählte zur Einkaufsliste hinzufügen</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
function addSelectedIngredientsToShoppingList() {
|
||||
var form = document.getElementById('ingredient-form');
|
||||
var formData = new FormData(form);
|
||||
var selectedIngredientIds = formData.getAll('ingredientIds');
|
||||
|
||||
fetch('/ShoppingList/AddSelectedIngredients', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ ingredientIds: selectedIngredientIds })
|
||||
}).then(response => {
|
||||
if (response.ok) {
|
||||
alert('Ausgewählte Zutaten wurden zur Einkaufsliste hinzugefügt.');
|
||||
} else {
|
||||
alert('Fehler beim Hinzufügen der ausgewählten Zutaten zur Einkaufsliste.');
|
||||
}
|
||||
}).catch(error => {
|
||||
alert('Ein Fehler ist aufgetreten: ' + error.message);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
@model Francesco.Recipes.World.Models.BackendModels.Shoppinglist.ShoppingList
|
||||
@using Francesco.Recipes.World.Models.BackendModels.RecipeShoppingList
|
||||
@using Francesco.Recipes.World.Models.BackendModels.RecipeIngredient
|
||||
@using Francesco.Recipes.World.Models.BackendModels.Recipe
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Einkaufsliste Details";
|
||||
}
|
||||
|
||||
<h2>Einkaufsliste Details</h2>
|
||||
|
||||
@if (TempData["SuccessMessage"] != null)
|
||||
{
|
||||
<div class="alert alert-success">
|
||||
@TempData["SuccessMessage"]
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
<h4>Einkaufsliste</h4>
|
||||
<hr />
|
||||
<dl class="row">
|
||||
<dt class="col-sm-2">
|
||||
ID
|
||||
</dt>
|
||||
<dd class="col-sm-10">
|
||||
@Model.Id
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4>Rezepte</h4>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Rezeptname</th>
|
||||
<th>Zutaten</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var recipeShoppingList in Model.RecipeShoppingList)
|
||||
{
|
||||
<tr>
|
||||
<td>@recipeShoppingList.Recipe.Name</td>
|
||||
<td>
|
||||
<ul>
|
||||
@foreach (var ingredient in recipeShoppingList.SelectedIngredients)
|
||||
{
|
||||
<li>@ingredient.RecipeIngredient.Ingredient.Name - @ingredient.RecipeIngredient.Quantity @ingredient.RecipeIngredient.Unit.Name</li>
|
||||
}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
Reference in New Issue
Block a user