Refactoring some Code and clean Code

This commit is contained in:
franc
2025-04-09 15:37:44 +02:00
parent d248ccb1db
commit 127a60b621
19 changed files with 132 additions and 114 deletions
@@ -1,13 +1,8 @@
namespace Francesco.Recipes.World.Controller.Category namespace Francesco.Recipes.World.Controller.Category
{ {
using Francesco.Recipes.World.Models.BackendModels.Category;
using Francesco.Recipes.World.Models.BackendModels.Recipe;
using Francesco.Recipes.World.Repositories.Category; using Francesco.Recipes.World.Repositories.Category;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
[ValidateAntiForgeryToken]
[Route("Category")]
public class CategoryController : Controller public class CategoryController : Controller
{ {
private readonly ICategoryRepository _categoryRepository; private readonly ICategoryRepository _categoryRepository;
@@ -19,7 +14,7 @@
// GET: /Category // GET: /Category
[HttpGet] [HttpGet]
public async Task<ActionResult<IEnumerable<Category>>> Index() public async Task<IActionResult> Index()
{ {
var categories = await _categoryRepository.GetAllCategoriesAsync(); var categories = await _categoryRepository.GetAllCategoriesAsync();
return View(categories); return View(categories);
@@ -35,10 +30,10 @@
// GET: /Category/{id}/recipes // GET: /Category/{id}/recipes
[HttpGet("{id:guid}/recipes")] [HttpGet("{id:guid}/recipes")]
public async Task<ActionResult<IEnumerable<Recipe>>> GetRecipesByCategory(Guid id) public async Task<IActionResult> GetRecipesByCategory(Guid id)
{ {
var recipes = await _categoryRepository.GetRecipesByCategoryAsync(id); var recipes = await _categoryRepository.GetRecipesByCategoryAsync(id);
return View(recipes); return Ok(recipes);
} }
} }
} }
@@ -4,9 +4,7 @@
using Francesco.Recipes.World.Repositories.MediaFile; using Francesco.Recipes.World.Repositories.MediaFile;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
[ValidateAntiForgeryToken] [Route("Category/{categoryId}/Recipe")]
[Route("categories/{categoryId}/Recipe")]
public class MediaFileController : Controller public class MediaFileController : Controller
{ {
private readonly IMediaFileRepository _mediaFileRepository; private readonly IMediaFileRepository _mediaFileRepository;
@@ -20,6 +18,7 @@
// POST: /UploadImage // POST: /UploadImage
[HttpPost("UploadImage")] [HttpPost("UploadImage")]
[AutoValidateAntiforgeryToken]
public async Task<IActionResult> UploadImage(Guid recipeId, IFormFile? mediaFile) public async Task<IActionResult> UploadImage(Guid recipeId, IFormFile? mediaFile)
{ {
if (mediaFile is null) if (mediaFile is null)
@@ -44,5 +43,32 @@
{ {
return View(); return View();
} }
[HttpPost("ReplaceInstructionImage")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ReplaceInstructionImage(Guid instructionId, Guid mediaFileIdToReplace, IFormFile? newPhoto)
{
if (newPhoto is null)
{
return BadRequest("Photo is required.");
}
using (var memoryStream = new MemoryStream())
{
await newPhoto.CopyToAsync(memoryStream);
var newMediaData = memoryStream.ToArray();
try
{
await _mediaFileRepository.ReplaceInstructionImageAsync(instructionId, mediaFileIdToReplace, newPhoto.FileName, newPhoto.ContentType, newMediaData);
return Ok("Image replaced successfully.");
}
catch (Exception ex)
{
return StatusCode(500, $"Internal server error: {ex.Message}");
}
}
}
} }
} }
@@ -1,6 +1,5 @@
namespace Francesco.Recipes.World.Controller.Recipe namespace Francesco.Recipes.World.Controller.Recipe
{ {
using System.ComponentModel.DataAnnotations;
using Francesco.Recipes.World.Models.BackendModels.Recipe; using Francesco.Recipes.World.Models.BackendModels.Recipe;
using Francesco.Recipes.World.Repositories.Category; using Francesco.Recipes.World.Repositories.Category;
using Francesco.Recipes.World.Repositories.Favorit; using Francesco.Recipes.World.Repositories.Favorit;
@@ -14,8 +13,6 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
[ValidateAntiForgeryToken]
[Route("Recipe")]
public class RecipeController : Controller public class RecipeController : Controller
{ {
private readonly IRecipeRepository _recipeRepository; private readonly IRecipeRepository _recipeRepository;
@@ -24,13 +21,18 @@
private readonly IIngredientRepository _ingredientRepository; private readonly IIngredientRepository _ingredientRepository;
private readonly IMediaFileRepository _mediaFileRepository; private readonly IMediaFileRepository _mediaFileRepository;
private readonly IInstructionRepository _instructionRepository; private readonly IInstructionRepository _instructionRepository;
private readonly IFavoritRepository _favoritRepository; private readonly IFavoriteRepository _favoriteRepository;
[Display(Name = "Schwierigkeitsgrad")] public IReadOnlyCollection<Recipe> Recipes { get; set; }
[BindProperty(SupportsGet = true)]
public Difficulty? SelectedDifficulty { get; set; }
public RecipeController(IRecipeRepository recipeRepository, IUnitRepository unitRepository, ICategoryRepository categoryRepository, IIngredientRepository ingredientRepository, IMediaFileRepository mediaFileRepository, IInstructionRepository instructionRepository, IFavoritRepository favoritRepository) public RecipeController(
IRecipeRepository recipeRepository,
IUnitRepository unitRepository,
ICategoryRepository categoryRepository,
IIngredientRepository ingredientRepository,
IMediaFileRepository mediaFileRepository,
IInstructionRepository instructionRepository,
IFavoriteRepository favoriteRepository)
{ {
_recipeRepository = recipeRepository; _recipeRepository = recipeRepository;
_unitRepository = unitRepository; _unitRepository = unitRepository;
@@ -39,11 +41,9 @@
Recipes = new List<Recipe>(); Recipes = new List<Recipe>();
_mediaFileRepository = mediaFileRepository; _mediaFileRepository = mediaFileRepository;
_instructionRepository = instructionRepository; _instructionRepository = instructionRepository;
_favoritRepository = favoritRepository; _favoriteRepository = favoriteRepository;
} }
public IReadOnlyCollection<Recipe> Recipes { get; set; }
// GET: /Recipe/{recipeId}/AddOrCreateIngredient // GET: /Recipe/{recipeId}/AddOrCreateIngredient
[HttpGet("{recipeId}/AddOrCreateIngredient")] [HttpGet("{recipeId}/AddOrCreateIngredient")]
public async Task<IActionResult> AddOrCreateIngredient(Guid recipeId) public async Task<IActionResult> AddOrCreateIngredient(Guid recipeId)
@@ -71,24 +71,20 @@
[HttpGet("CategoryRecipes")] [HttpGet("CategoryRecipes")]
public async Task<IActionResult> CategoryRecipes() public async Task<IActionResult> CategoryRecipes()
{ {
var categories = await _categoryRepository.GetAllCategoriesAsync(); var categories = await _categoryRepository.GetAllCategoriesWithRecipesAsync();
var viewModel = new List<CategoryRecipesViewModel>();
foreach (var category in categories) var viewModel = categories.Select(c => new CategoryRecipesViewModel
{ {
var recipes = await _categoryRepository.GetRecipesByCategoryAsync(category.Id); Category = c,
viewModel.Add(new CategoryRecipesViewModel Recipes = c.Recipes,
{ }).ToList();
Category = category,
Recipes = recipes,
});
}
return View(viewModel); return View(viewModel);
} }
// POST: /Recipe/{recipeId}/AddOrCreateIngredient // POST: /Recipe/{recipeId}/AddOrCreateIngredient
[HttpPost("{recipeId}/AddOrCreateIngredient")] [HttpPost("{recipeId}/AddOrCreateIngredient")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddOrCreateIngredient(Guid recipeId, string ingredientName, int quantity, Guid unitId) public async Task<IActionResult> AddOrCreateIngredient(Guid recipeId, string ingredientName, int quantity, Guid unitId)
{ {
if (quantity <= 0) if (quantity <= 0)
@@ -123,6 +119,7 @@
// POST: /Recipe/Create/{categoryId} // POST: /Recipe/Create/{categoryId}
[HttpPost("Create/{categoryId}")] [HttpPost("Create/{categoryId}")]
[AutoValidateAntiforgeryToken]
public async Task<IActionResult> Create(Guid categoryId, string name, string description, Difficulty difficulty, int servings, TimeSpan preparationTime, TimeSpan cookingTime, IFormFile? photo) 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)) if (string.IsNullOrWhiteSpace(name))
@@ -153,6 +150,7 @@
return NotFound($"Kategorie mit ID {categoryId} wurde nicht gefunden."); 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); var recipe = await _recipeRepository.CreateRecipeForCategoryAsync(categoryEntity, name, description, difficulty, servings, preparationTime, cookingTime);
if (photo != null) if (photo != null)
{ {
@@ -176,13 +174,13 @@
ViewBag.RecipeId = recipeId; ViewBag.RecipeId = recipeId;
ViewBag.IngredientId = ingredientId; ViewBag.IngredientId = ingredientId;
ViewBag.IngredientName = ingredient.Name;
return View(); return View();
} }
// POST: /Recipe/{recipeId}/RemoveIngredient/{ingredientId} // POST: /Recipe/{recipeId}/RemoveIngredient/{ingredientId}
[HttpPost("{recipeId}/RemoveIngredient/{ingredientId}")] [HttpPost("{recipeId}/RemoveIngredient/{ingredientId}")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveIngredientConfirmed(Guid recipeId, Guid ingredientId) public async Task<IActionResult> RemoveIngredientConfirmed(Guid recipeId, Guid ingredientId)
{ {
await _recipeRepository.RemoveIngredientFromRecipeAsync(recipeId, ingredientId); await _recipeRepository.RemoveIngredientFromRecipeAsync(recipeId, ingredientId);
@@ -219,6 +217,7 @@
// POST: /Recipe/{recipeId}/AddInstruction // POST: /Recipe/{recipeId}/AddInstruction
[HttpPost("{recipeId}/AddInstruction")] [HttpPost("{recipeId}/AddInstruction")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddInstruction(Guid recipeId, string description, int number) public async Task<IActionResult> AddInstruction(Guid recipeId, string description, int number)
{ {
try try
@@ -239,23 +238,25 @@
[HttpGet("Favorites")] [HttpGet("Favorites")]
public async Task<IActionResult> Favorites() public async Task<IActionResult> Favorites()
{ {
var favoriteRecipes = await _favoritRepository.GetFavoriteRecipesAsync(); var favoriteRecipes = await _favoriteRepository.GetFavoriteRecipesAsync();
return View(favoriteRecipes); return View(favoriteRecipes);
} }
// POST: /Recipe/AddFavorite // POST: /Recipe/AddFavorite
[HttpPost("AddFavorite")] [HttpPost("AddFavorite")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> AddFavorite(Guid recipeId) public async Task<IActionResult> AddFavorite(Guid recipeId)
{ {
await _favoritRepository.AddFavoriteAsync(recipeId); await _favoriteRepository.AddFavoriteAsync(recipeId);
return RedirectToAction("Details", new { recipeId }); return RedirectToAction("Details", new { recipeId });
} }
// POST: /Recipe/RemoveFavorite // POST: /Recipe/RemoveFavorite
[HttpPost("RemoveFavorite")] [HttpPost("RemoveFavorite")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveFavorite(Guid recipeId) public async Task<IActionResult> RemoveFavorite(Guid recipeId)
{ {
await _favoritRepository.RemoveFavoriteAsync(recipeId); await _favoriteRepository.RemoveFavoriteAsync(recipeId);
return RedirectToAction("Details", new { recipeId }); return RedirectToAction("Details", new { recipeId });
} }
} }
@@ -1,11 +1,11 @@
namespace Francesco.Recipes.World.Controllers namespace Francesco.Recipes.World.Controllers
{ {
using Francesco.Recipes.World.Data; using Francesco.Recipes.World.Data;
using Francesco.Recipes.World.Models;
using Francesco.Recipes.World.Repositories.ShoppingList; using Francesco.Recipes.World.Repositories.ShoppingList;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
[Route("ShoppingList")]
public class ShoppingListController : Controller public class ShoppingListController : Controller
{ {
private readonly IShoppingListRepository _shoppingListRepository; private readonly IShoppingListRepository _shoppingListRepository;
@@ -18,7 +18,8 @@
} }
[HttpPost("CreateOrAddIngredients")] [HttpPost("CreateOrAddIngredients")]
public async Task<IActionResult> CreateOrAddIngredients([FromBody] CreateOrAddIngredientsRequest request) [ValidateAntiForgeryToken]
public async Task<IActionResult> CreateOrAddIngredients([FromBody] CreateOrAddIngredientRequestModel request)
{ {
if (request == null || request.IngredientIds == null || !request.IngredientIds.Any()) if (request == null || request.IngredientIds == null || !request.IngredientIds.Any())
{ {
@@ -39,12 +40,5 @@
return Json(new { shoppingListId = shoppingList.Id }); return Json(new { shoppingListId = shoppingList.Id });
} }
public class CreateOrAddIngredientsRequest
{
public Guid RecipeId { get; set; }
public List<Guid> IngredientIds { get; set; } = new ();
}
} }
} }
@@ -10,7 +10,7 @@
public virtual ShoppingList ShoppingList { get; set; } = new ShoppingList(); public virtual ShoppingList ShoppingList { get; set; } = new ShoppingList();
public virtual Recipe Recipe { get; set; } = new (); public virtual Recipe Recipe { get; set; } = new Recipe();
public virtual ICollection<RecipeIngredientShoppingList> SelectedIngredients { get; set; } = new List<RecipeIngredientShoppingList>(); public virtual ICollection<RecipeIngredientShoppingList> SelectedIngredients { get; set; } = new List<RecipeIngredientShoppingList>();
} }
@@ -0,0 +1,9 @@
namespace Francesco.Recipes.World.Models
{
public class CreateOrAddIngredientRequestModel
{
public Guid RecipeId { get; set; }
public List<Guid> IngredientIds { get; set; } = new ();
}
}
+2 -2
View File
@@ -39,7 +39,7 @@ builder.Services.AddScoped<IMediaFileRepository, MediaFileRepository>();
builder.Services.AddScoped<IInstructionRepository, InstructionRepository>(); builder.Services.AddScoped<IInstructionRepository, InstructionRepository>();
builder.Services.AddScoped<IFavoritRepository, FavoritRepository>(); builder.Services.AddScoped<IFavoriteRepository, FavoritRepository>();
var app = builder.Build(); var app = builder.Build();
@@ -64,6 +64,6 @@ app.MapDefaultControllerRoute();
app.MapControllerRoute( app.MapControllerRoute(
name: "default", name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"); pattern: "{controller=Category}/{action=Index}/{id?}");
app.Run(); app.Run();
@@ -41,5 +41,12 @@
return category.Recipes; return category.Recipes;
} }
public async Task<IEnumerable<Category>> GetAllCategoriesWithRecipesAsync()
{
return await _context.Categories
.Include(c => c.Recipes)
.ToListAsync();
}
} }
} }
@@ -13,5 +13,7 @@
Task<IEnumerable<Category>> GetAllCategoriesAsync(); Task<IEnumerable<Category>> GetAllCategoriesAsync();
Task<IEnumerable<Recipe>> GetRecipesByCategoryAsync(Guid categoryId); Task<IEnumerable<Recipe>> GetRecipesByCategoryAsync(Guid categoryId);
Task<IEnumerable<Category>> GetAllCategoriesWithRecipesAsync();
} }
} }
@@ -4,7 +4,7 @@
using Francesco.Recipes.World.Models.BackendModels.Recipe; using Francesco.Recipes.World.Models.BackendModels.Recipe;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
public class FavoritRepository : IFavoritRepository public class FavoritRepository : IFavoriteRepository
{ {
private readonly FrancescosRecipesWorldDbContext _context; private readonly FrancescosRecipesWorldDbContext _context;
@@ -2,7 +2,7 @@
{ {
using Francesco.Recipes.World.Models.BackendModels.Recipe; using Francesco.Recipes.World.Models.BackendModels.Recipe;
public interface IFavoritRepository public interface IFavoriteRepository
{ {
Task<IEnumerable<Recipe>> GetFavoriteRecipesAsync(); Task<IEnumerable<Recipe>> GetFavoriteRecipesAsync();
@@ -37,7 +37,6 @@ namespace Francesco.Recipes.World.Repositories.Ingredient
existingRecipeIngredient.Ingredient = recipeIngredient.Ingredient; existingRecipeIngredient.Ingredient = recipeIngredient.Ingredient;
existingRecipeIngredient.Unit = recipeIngredient.Unit; existingRecipeIngredient.Unit = recipeIngredient.Unit;
_context.RecipeIngredients.Update(existingRecipeIngredient);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
@@ -77,7 +76,6 @@ namespace Francesco.Recipes.World.Repositories.Ingredient
existingIngredient.Name = ingredient.Name; existingIngredient.Name = ingredient.Name;
_context.Ingredients.Update(existingIngredient);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
@@ -1,7 +1,6 @@
namespace Francesco.Recipes.World.Repositories.Instruction namespace Francesco.Recipes.World.Repositories.Instruction
{ {
using Francesco.Recipes.World.Models.BackendModels.Instruction; using Francesco.Recipes.World.Models.BackendModels.Instruction;
using Francesco.Recipes.World.Models.BackendModels.Recipe;
public interface IInstructionRepository public interface IInstructionRepository
{ {
@@ -11,6 +10,6 @@
Task<List<Instruction>> GetInstructionsByRecipeIdAsync(Guid recipeId); Task<List<Instruction>> GetInstructionsByRecipeIdAsync(Guid recipeId);
Task RemoveInstructionFromRecipeAsync(Recipe recipe, Guid instructionId); Task RemoveInstructionFromRecipeAsync(Guid recipeId, Guid instructionId);
} }
} }
@@ -2,7 +2,6 @@
{ {
using Francesco.Recipes.World.Data; using Francesco.Recipes.World.Data;
using Francesco.Recipes.World.Models.BackendModels.Instruction; using Francesco.Recipes.World.Models.BackendModels.Instruction;
using Francesco.Recipes.World.Models.BackendModels.Recipe;
using Francesco.Recipes.World.Repositories.Recipe; using Francesco.Recipes.World.Repositories.Recipe;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -51,18 +50,22 @@
return newInstruction; return newInstruction;
} }
public async Task RemoveInstructionFromRecipeAsync(Recipe recipe, Guid instructionId) public async Task RemoveInstructionFromRecipeAsync(Guid recipeId, Guid instructionId)
{ {
if (recipe == null) var recipe = await _recipeRepository.GetRecipeAsync(recipeId);
if (recipe.Instructions == null || !recipe.Instructions.Any())
{ {
throw new ArgumentNullException(nameof(recipe)); await _context.Entry(recipe)
.Collection(r => r.Instructions)
.LoadAsync();
} }
var instructionToRemove = recipe.Instructions.FirstOrDefault(i => i.Id == instructionId); var instructionToRemove = recipe.Instructions?.FirstOrDefault(i => i.Id == instructionId);
if (instructionToRemove != null) if (instructionToRemove != null)
{ {
recipe.Instructions.Remove(instructionToRemove); recipe.Instructions?.Remove(instructionToRemove);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
} }
@@ -2,7 +2,7 @@
{ {
public interface IMediaFileRepository public interface IMediaFileRepository
{ {
Task ReplaceInstructionImageAsync(Guid instructionId, Guid mediafileId, IFormFile? newPhoto); Task ReplaceInstructionImageAsync(Guid instructionId, Guid mediaFileIdToReplace, string fileName, string mimeType, byte[] newMediaData);
Task UploadInstructionImageAsync(Guid instructionId, IFormFile? photo); Task UploadInstructionImageAsync(Guid instructionId, IFormFile? photo);
@@ -2,6 +2,7 @@
{ {
using Francesco.Recipes.World.Data; using Francesco.Recipes.World.Data;
using Francesco.Recipes.World.Models.BackendModels.MediaFile; using Francesco.Recipes.World.Models.BackendModels.MediaFile;
using Francesco.Recipes.World.Models.BackendModels.Recipe;
using Francesco.Recipes.World.Repositories.Instruction; using Francesco.Recipes.World.Repositories.Instruction;
using Francesco.Recipes.World.Repositories.Recipe; using Francesco.Recipes.World.Repositories.Recipe;
@@ -18,13 +19,8 @@
_recipeRepository = recipeRepository; _recipeRepository = recipeRepository;
} }
public async Task ReplaceInstructionImageAsync(Guid instructionId, Guid mediaFileIdToReplace, IFormFile? newPhoto) public async Task ReplaceInstructionImageAsync(Guid instructionId, Guid mediaFileIdToReplace, string fileName, string mimeType, byte[] newMediaData)
{ {
if (newPhoto is null)
{
throw new ArgumentNullException(nameof(newPhoto));
}
var instruction = await _instructionRepository.GetInstructionAsync(instructionId); var instruction = await _instructionRepository.GetInstructionAsync(instructionId);
var mediaToReplace = instruction.MediaFiles.FirstOrDefault(m => m.Id == mediaFileIdToReplace); var mediaToReplace = instruction.MediaFiles.FirstOrDefault(m => m.Id == mediaFileIdToReplace);
@@ -36,23 +32,18 @@
_context.MediaFiles.Remove(mediaToReplace); _context.MediaFiles.Remove(mediaToReplace);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
using (var memoryStream = new MemoryStream())
{
await newPhoto.CopyToAsync(memoryStream);
var newMedia = new MediaFile var newMedia = new MediaFile
{ {
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
FileName = newPhoto.FileName, FileName = fileName,
MimeType = newPhoto.ContentType, MimeType = mimeType,
Data = memoryStream.ToArray(), Data = newMediaData,
Instruction = instruction, Instruction = instruction,
}; };
_context.MediaFiles.Add(newMedia); _context.MediaFiles.Add(newMedia);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
}
public async Task UploadInstructionImageAsync(Guid instructionId, IFormFile? photo) public async Task UploadInstructionImageAsync(Guid instructionId, IFormFile? photo)
{ {
@@ -89,11 +80,6 @@
var recipe = await _recipeRepository.GetRecipeAsync(recipeId); var recipe = await _recipeRepository.GetRecipeAsync(recipeId);
if (recipe == null)
{
throw new InvalidOperationException("The specified recipe does not exist.");
}
var isImage = mediaFile.ContentType.StartsWith("image/"); var isImage = mediaFile.ContentType.StartsWith("image/");
var isVideo = mediaFile.ContentType.StartsWith("video/"); var isVideo = mediaFile.ContentType.StartsWith("video/");
@@ -104,21 +90,11 @@
if (isImage) if (isImage)
{ {
var existingImage = recipe.MediaFiles?.FirstOrDefault(m => m.MimeType?.StartsWith("image/") == true); await RemoveExistingMediaAsync(recipe, "image/");
if (existingImage != null)
{
_context.MediaFiles.Remove(existingImage);
await _context.SaveChangesAsync();
}
} }
else if (isVideo) else if (isVideo)
{ {
var existingVideo = recipe.MediaFiles?.FirstOrDefault(m => m.MimeType?.StartsWith("video/") == true); await RemoveExistingMediaAsync(recipe, "video/");
if (existingVideo != null)
{
_context.MediaFiles.Remove(existingVideo);
await _context.SaveChangesAsync();
}
} }
using var memoryStream = new MemoryStream(); using var memoryStream = new MemoryStream();
@@ -136,5 +112,15 @@
_context.MediaFiles.Add(newMedia); _context.MediaFiles.Add(newMedia);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
private async Task RemoveExistingMediaAsync(Recipe recipe, string mediaTypePrefix)
{
var existingMedia = recipe.MediaFiles?.FirstOrDefault(m => m.MimeType?.StartsWith(mediaTypePrefix) == true);
if (existingMedia != null)
{
_context.MediaFiles.Remove(existingMedia);
await _context.SaveChangesAsync();
}
}
} }
} }
@@ -13,7 +13,7 @@
Task RemoveIngredientFromRecipeAsync(Guid recipeId, Guid ingredientId); Task RemoveIngredientFromRecipeAsync(Guid recipeId, Guid ingredientId);
Task<IEnumerable<Recipe>> GetRecipesByNameOrIngredientAsync(string name, string ingredient); Task<IEnumerable<Recipe>> GetRecipesByNameAndIngredientAsync(string name, string ingredient);
Task<IReadOnlyCollection<Recipe>> GetRecipesByDifficultyAsync(Difficulty? difficulty); Task<IReadOnlyCollection<Recipe>> GetRecipesByDifficultyAsync(Difficulty? difficulty);
@@ -37,6 +37,7 @@
.Include(r => r.RecipeIngredients) .Include(r => r.RecipeIngredients)
.ThenInclude(ri => ri.Unit) .ThenInclude(ri => ri.Unit)
.Include(r => r.MediaFiles) .Include(r => r.MediaFiles)
.Include(r => r.Instructions)
.FirstOrDefaultAsync(r => r.Id == recipeId); .FirstOrDefaultAsync(r => r.Id == recipeId);
} }
@@ -53,7 +54,7 @@
var ingredients = await _ingredientRepository.GetIngredientsByNameAsync(ingredientName); var ingredients = await _ingredientRepository.GetIngredientsByNameAsync(ingredientName);
Ingredient ingredient; Ingredient ingredient;
if (ingredients == null || !ingredients.Any()) if (!ingredients.Any())
{ {
ingredient = new Ingredient ingredient = new Ingredient
{ {
@@ -131,7 +132,6 @@
public async Task RemoveIngredientFromRecipeAsync(Guid recipeId, Guid ingredientId) public async Task RemoveIngredientFromRecipeAsync(Guid recipeId, Guid ingredientId)
{ {
var recipe = await GetRecipeAsync(recipeId);
var recipeIngredient = await _context.RecipeIngredients var recipeIngredient = await _context.RecipeIngredients
.FirstOrDefaultAsync(ri => ri.Recipe.Id == recipeId && ri.Ingredient.Id == ingredientId); .FirstOrDefaultAsync(ri => ri.Recipe.Id == recipeId && ri.Ingredient.Id == ingredientId);
@@ -144,7 +144,7 @@
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }
public async Task<IEnumerable<Recipe>> GetRecipesByNameOrIngredientAsync(string name, string ingredient) public async Task<IEnumerable<Recipe>> GetRecipesByNameAndIngredientAsync(string name, string ingredient)
{ {
var query = _context.Recipes var query = _context.Recipes
.Include(r => r.RecipeIngredients) .Include(r => r.RecipeIngredients)
@@ -114,7 +114,6 @@
public async Task<IEnumerable<RecipeIngredientShoppingList>> GetIngredientsOfRecipeInListAsync(Guid shoppingListRecipeId) public async Task<IEnumerable<RecipeIngredientShoppingList>> GetIngredientsOfRecipeInListAsync(Guid shoppingListRecipeId)
{ {
return await _context.RecipeIngredientsShoppingLists return await _context.RecipeIngredientsShoppingLists
.AsNoTracking()
.Include(i => i.RecipeIngredient) .Include(i => i.RecipeIngredient)
.ThenInclude(ri => ri.Ingredient) .ThenInclude(ri => ri.Ingredient)
.Include(i => i.RecipeIngredient.Unit) .Include(i => i.RecipeIngredient.Unit)
@@ -168,7 +167,6 @@
public async Task<Recipe?> GetRecipeByNameAndImageAsync(string recipeName, string imageFileName) public async Task<Recipe?> GetRecipeByNameAndImageAsync(string recipeName, string imageFileName)
{ {
return await _context.Recipes return await _context.Recipes
.AsNoTracking()
.Where(r => r.Name == recipeName && r.MediaFiles.Any(mf => mf.FileName == imageFileName)) .Where(r => r.Name == recipeName && r.MediaFiles.Any(mf => mf.FileName == imageFileName))
.Include(r => r.MediaFiles.Where(mf => mf.FileName == imageFileName)) .Include(r => r.MediaFiles.Where(mf => mf.FileName == imageFileName))
.FirstOrDefaultAsync(); .FirstOrDefaultAsync();