Refactoring some Code and clean Code
This commit is contained in:
@@ -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 ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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 ();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user