From 7d11eaf7efabeb15b14f1d923d68d1df2881ed3b Mon Sep 17 00:00:00 2001 From: franc Date: Tue, 15 Apr 2025 16:10:42 +0200 Subject: [PATCH 01/27] Implement two methods for the sorting logic on the service --- .../Instruction/IInstructionRepository.cs | 4 ++ .../Instruction/InstructionRepository.cs | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs index 963099b..528f6b8 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs @@ -11,5 +11,9 @@ Task> GetInstructionsByRecipeIdAsync(Guid recipeId); Task RemoveInstructionFromRecipeAsync(Guid recipeId, Guid instructionId); + + Task SwapInstructionOrderAsync(Instruction a, Instruction b); + + Task GetInstructionWithRecipeAsync(Guid instructionId); } } diff --git a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs index b487d57..0a71b5f 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs @@ -77,5 +77,44 @@ .Where(i => i.Recipe.Id == recipeId) .ToListAsync(); } + + public async Task GetInstructionWithRecipeAsync(Guid instructionId) + { + var instruction = await _context.Instructions + .Include(i => i.Recipe) + .ThenInclude(r => r.Instructions) + .FirstOrDefaultAsync(i => i.Id == instructionId); + + if (instruction == null) + { + throw new InvalidDataException($"Instruction with ID {instructionId} not found."); + } + + if (instruction.Recipe == null) + { + throw new InvalidDataException($"The Recipe for Instruction with ID {instructionId} is not loaded or does not exist."); + } + + return instruction; + } + + public async Task SwapInstructionOrderAsync(Instruction a, Instruction b) + { + if (a == null) + { + throw new ArgumentNullException(nameof(a), "Instruction 'a' cannot be null."); + } + + if (b == null) + { + throw new ArgumentNullException(nameof(b), "Instruction 'b' cannot be null."); + } + + var temp = a.Number; + a.Number = b.Number; + b.Number = temp; + + await _context.SaveChangesAsync(); + } } } From 71ebfcf4bee42b279c74490aaa4d86b96544ca1a Mon Sep 17 00:00:00 2001 From: franc Date: Tue, 15 Apr 2025 16:11:07 +0200 Subject: [PATCH 02/27] Implement the Sorting Logic --- .../Instruction/IInstructionService.cs | 9 ++++ .../Instruction/InstructionService.cs | 54 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 Francesco.Recipes.World/Services/Instruction/IInstructionService.cs create mode 100644 Francesco.Recipes.World/Services/Instruction/InstructionService.cs diff --git a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs new file mode 100644 index 0000000..fa514a1 --- /dev/null +++ b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs @@ -0,0 +1,9 @@ +namespace Francesco.Recipes.World.Services.Instruction +{ + public interface IInstructionService + { + Task MoveInstructionUpAsync(Guid instructionId); + + Task MoveInstructionDownAsync(Guid instructionId); + } +} diff --git a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs new file mode 100644 index 0000000..5015426 --- /dev/null +++ b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs @@ -0,0 +1,54 @@ +using Francesco.Recipes.World.Repositories.Instruction; + +namespace Francesco.Recipes.World.Services.Instruction +{ + public class InstructionService : IInstructionService + { + private readonly IInstructionRepository _instructionRepository; + + public InstructionService(IInstructionRepository instructionRepository) + { + _instructionRepository = instructionRepository; + } + + public async Task MoveInstructionDownAsync(Guid instructionId) + { + var instruction = await _instructionRepository.GetInstructionWithRecipeAsync(instructionId); + + var instructions = await _instructionRepository.GetInstructionsByRecipeIdAsync(instruction.Recipe.Id); + + var maxStep = instructions.Max(i => i.Number); + + if (instruction.Number >= maxStep) + { + return; + } + + var neighbor = instructions.FirstOrDefault(i => i.Number == instruction.Number + 1); + + if (neighbor != null) + { + await _instructionRepository.SwapInstructionOrderAsync(instruction, neighbor); + } + } + + public async Task MoveInstructionUpAsync(Guid instructionId) + { + var instruction = await _instructionRepository.GetInstructionWithRecipeAsync(instructionId); + + if (instruction.Number == 1) + { + return; + } + + var instructions = await _instructionRepository.GetInstructionsByRecipeIdAsync(instruction.Recipe.Id); + + var neighbor = instructions.FirstOrDefault(i => i.Number == instruction.Number - 1); + + if (neighbor != null) + { + await _instructionRepository.SwapInstructionOrderAsync(instruction, neighbor); + } + } + } +} From 4b084eea9879a8af1ebf0b50dd148e26851dffa8 Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 16 Apr 2025 17:22:19 +0200 Subject: [PATCH 03/27] Refactoring some code and change logic and make sure to reduce db calls and avoid redundants --- .../Instruction/IInstructionRepository.cs | 4 +- .../Instruction/InstructionRepository.cs | 21 ++-------- .../Instruction/IInstructionService.cs | 2 + .../Instruction/InstructionService.cs | 42 ++++++++----------- 4 files changed, 25 insertions(+), 44 deletions(-) diff --git a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs index 528f6b8..057eb02 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs @@ -8,12 +8,10 @@ Task CreateInstructionToRecipeAsync(Guid recipeId, string description, int number); - Task> GetInstructionsByRecipeIdAsync(Guid recipeId); - Task RemoveInstructionFromRecipeAsync(Guid recipeId, Guid instructionId); Task SwapInstructionOrderAsync(Instruction a, Instruction b); - Task GetInstructionWithRecipeAsync(Guid instructionId); + Task> GetInstructionsByInstructionIdAsync(Guid instructionId); } } diff --git a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs index 0a71b5f..a95e22d 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs @@ -70,32 +70,19 @@ } } - public async Task> GetInstructionsByRecipeIdAsync(Guid recipeId) - { - return await _context.Instructions - .Include(i => i.Recipe) - .Where(i => i.Recipe.Id == recipeId) - .ToListAsync(); - } - - public async Task GetInstructionWithRecipeAsync(Guid instructionId) + public async Task> GetInstructionsByInstructionIdAsync(Guid instructionId) { var instruction = await _context.Instructions .Include(i => i.Recipe) .ThenInclude(r => r.Instructions) .FirstOrDefaultAsync(i => i.Id == instructionId); - if (instruction == null) + if (instruction?.Recipe == null) { - throw new InvalidDataException($"Instruction with ID {instructionId} not found."); + throw new InvalidDataException($"Instruction with ID {instructionId} or its Recipe not found."); } - if (instruction.Recipe == null) - { - throw new InvalidDataException($"The Recipe for Instruction with ID {instructionId} is not loaded or does not exist."); - } - - return instruction; + return instruction.Recipe.Instructions.ToList(); } public async Task SwapInstructionOrderAsync(Instruction a, Instruction b) diff --git a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs index fa514a1..efb6b00 100644 --- a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs @@ -5,5 +5,7 @@ Task MoveInstructionUpAsync(Guid instructionId); Task MoveInstructionDownAsync(Guid instructionId); + + Task MoveInstructionAsync(Guid instructionId, bool moveUp); } } diff --git a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs index 5015426..895cf66 100644 --- a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs @@ -11,39 +11,33 @@ namespace Francesco.Recipes.World.Services.Instruction _instructionRepository = instructionRepository; } - public async Task MoveInstructionDownAsync(Guid instructionId) + public Task MoveInstructionUpAsync(Guid instructionId) + => MoveInstructionAsync(instructionId, moveUp: true); + + public Task MoveInstructionDownAsync(Guid instructionId) + => MoveInstructionAsync(instructionId, moveUp: false); + + private async Task MoveInstructionAsync(Guid instructionId, bool moveUp) { - var instruction = await _instructionRepository.GetInstructionWithRecipeAsync(instructionId); + var instructions = await _instructionRepository.GetInstructionsByInstructionIdAsync(instructionId); - var instructions = await _instructionRepository.GetInstructionsByRecipeIdAsync(instruction.Recipe.Id); + var instruction = instructions.FirstOrDefault(i => i.Id == instructionId); + if (instruction == null) + { + throw new InvalidDataException($"Instruction with ID {instructionId} not found."); + } + + var minStep = 1; var maxStep = instructions.Max(i => i.Number); - if (instruction.Number >= maxStep) + if ((moveUp && instruction.Number == minStep) || (!moveUp && instruction.Number >= maxStep)) { return; } - var neighbor = instructions.FirstOrDefault(i => i.Number == instruction.Number + 1); - - if (neighbor != null) - { - await _instructionRepository.SwapInstructionOrderAsync(instruction, neighbor); - } - } - - public async Task MoveInstructionUpAsync(Guid instructionId) - { - var instruction = await _instructionRepository.GetInstructionWithRecipeAsync(instructionId); - - if (instruction.Number == 1) - { - return; - } - - var instructions = await _instructionRepository.GetInstructionsByRecipeIdAsync(instruction.Recipe.Id); - - var neighbor = instructions.FirstOrDefault(i => i.Number == instruction.Number - 1); + var targetNumber = moveUp ? instruction.Number - 1 : instruction.Number + 1; + var neighbor = instructions.FirstOrDefault(i => i.Number == targetNumber); if (neighbor != null) { From b7706de30c8db5b590caebbc76dee7ea42f5e8d7 Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 16 Apr 2025 17:27:08 +0200 Subject: [PATCH 04/27] Remove the interface declaration for MoveInstructionAsync since it's now a private method --- .../Services/Instruction/IInstructionService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs index efb6b00..8ddedf5 100644 --- a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs @@ -6,6 +6,5 @@ Task MoveInstructionDownAsync(Guid instructionId); - Task MoveInstructionAsync(Guid instructionId, bool moveUp); } } From 032e2caf1b956be574d3844517f777ec5cda5e57 Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 16 Apr 2025 17:27:41 +0200 Subject: [PATCH 05/27] Remove Blank line --- .../Services/Instruction/IInstructionService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs index 8ddedf5..fa514a1 100644 --- a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs @@ -5,6 +5,5 @@ Task MoveInstructionUpAsync(Guid instructionId); Task MoveInstructionDownAsync(Guid instructionId); - } } From 71ac7eb03fb94eda51a42b593bab3bca21383a7f Mon Sep 17 00:00:00 2001 From: franc Date: Thu, 17 Apr 2025 10:34:12 +0200 Subject: [PATCH 06/27] Rename Refactoring --- .../Repositories/Instruction/IInstructionRepository.cs | 4 ++-- .../Repositories/Instruction/InstructionRepository.cs | 4 ++-- .../Services/Instruction/InstructionService.cs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs index 057eb02..e1fd1e6 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs @@ -10,8 +10,8 @@ Task RemoveInstructionFromRecipeAsync(Guid recipeId, Guid instructionId); - Task SwapInstructionOrderAsync(Instruction a, Instruction b); + Task SwapInstructionNumbersAsync(Instruction a, Instruction b); - Task> GetInstructionsByInstructionIdAsync(Guid instructionId); + Task> GetInstructionsOfRecipeAsync(Guid instructionId); } } diff --git a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs index a95e22d..9a4445d 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs @@ -70,7 +70,7 @@ } } - public async Task> GetInstructionsByInstructionIdAsync(Guid instructionId) + public async Task> GetInstructionsOfRecipeAsync(Guid instructionId) { var instruction = await _context.Instructions .Include(i => i.Recipe) @@ -85,7 +85,7 @@ return instruction.Recipe.Instructions.ToList(); } - public async Task SwapInstructionOrderAsync(Instruction a, Instruction b) + public async Task SwapInstructionNumbersAsync(Instruction a, Instruction b) { if (a == null) { diff --git a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs index 895cf66..c7a4acc 100644 --- a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs @@ -19,7 +19,7 @@ namespace Francesco.Recipes.World.Services.Instruction private async Task MoveInstructionAsync(Guid instructionId, bool moveUp) { - var instructions = await _instructionRepository.GetInstructionsByInstructionIdAsync(instructionId); + var instructions = await _instructionRepository.GetInstructionsOfRecipeAsync(instructionId); var instruction = instructions.FirstOrDefault(i => i.Id == instructionId); @@ -36,12 +36,12 @@ namespace Francesco.Recipes.World.Services.Instruction return; } - var targetNumber = moveUp ? instruction.Number - 1 : instruction.Number + 1; + var targetNumber = moveUp ? instruction.Number + 1 : instruction.Number - 1; var neighbor = instructions.FirstOrDefault(i => i.Number == targetNumber); if (neighbor != null) { - await _instructionRepository.SwapInstructionOrderAsync(instruction, neighbor); + await _instructionRepository.SwapInstructionNumbersAsync(instruction, neighbor); } } } From 0fb9333b82ac64c1c9547196a499945a55cc3cbf Mon Sep 17 00:00:00 2001 From: franc Date: Tue, 15 Apr 2025 16:10:42 +0200 Subject: [PATCH 07/27] Implement two methods for the sorting logic on the service --- .../Instruction/IInstructionRepository.cs | 4 ++ .../Instruction/InstructionRepository.cs | 39 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs index 963099b..528f6b8 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs @@ -11,5 +11,9 @@ Task> GetInstructionsByRecipeIdAsync(Guid recipeId); Task RemoveInstructionFromRecipeAsync(Guid recipeId, Guid instructionId); + + Task SwapInstructionOrderAsync(Instruction a, Instruction b); + + Task GetInstructionWithRecipeAsync(Guid instructionId); } } diff --git a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs index b487d57..0a71b5f 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs @@ -77,5 +77,44 @@ .Where(i => i.Recipe.Id == recipeId) .ToListAsync(); } + + public async Task GetInstructionWithRecipeAsync(Guid instructionId) + { + var instruction = await _context.Instructions + .Include(i => i.Recipe) + .ThenInclude(r => r.Instructions) + .FirstOrDefaultAsync(i => i.Id == instructionId); + + if (instruction == null) + { + throw new InvalidDataException($"Instruction with ID {instructionId} not found."); + } + + if (instruction.Recipe == null) + { + throw new InvalidDataException($"The Recipe for Instruction with ID {instructionId} is not loaded or does not exist."); + } + + return instruction; + } + + public async Task SwapInstructionOrderAsync(Instruction a, Instruction b) + { + if (a == null) + { + throw new ArgumentNullException(nameof(a), "Instruction 'a' cannot be null."); + } + + if (b == null) + { + throw new ArgumentNullException(nameof(b), "Instruction 'b' cannot be null."); + } + + var temp = a.Number; + a.Number = b.Number; + b.Number = temp; + + await _context.SaveChangesAsync(); + } } } From d2560e297124e58f64c0d29ce354fed4a9836ed0 Mon Sep 17 00:00:00 2001 From: franc Date: Tue, 15 Apr 2025 16:11:07 +0200 Subject: [PATCH 08/27] Implement the Sorting Logic --- .../Instruction/IInstructionService.cs | 9 ++++ .../Instruction/InstructionService.cs | 54 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 Francesco.Recipes.World/Services/Instruction/IInstructionService.cs create mode 100644 Francesco.Recipes.World/Services/Instruction/InstructionService.cs diff --git a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs new file mode 100644 index 0000000..fa514a1 --- /dev/null +++ b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs @@ -0,0 +1,9 @@ +namespace Francesco.Recipes.World.Services.Instruction +{ + public interface IInstructionService + { + Task MoveInstructionUpAsync(Guid instructionId); + + Task MoveInstructionDownAsync(Guid instructionId); + } +} diff --git a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs new file mode 100644 index 0000000..5015426 --- /dev/null +++ b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs @@ -0,0 +1,54 @@ +using Francesco.Recipes.World.Repositories.Instruction; + +namespace Francesco.Recipes.World.Services.Instruction +{ + public class InstructionService : IInstructionService + { + private readonly IInstructionRepository _instructionRepository; + + public InstructionService(IInstructionRepository instructionRepository) + { + _instructionRepository = instructionRepository; + } + + public async Task MoveInstructionDownAsync(Guid instructionId) + { + var instruction = await _instructionRepository.GetInstructionWithRecipeAsync(instructionId); + + var instructions = await _instructionRepository.GetInstructionsByRecipeIdAsync(instruction.Recipe.Id); + + var maxStep = instructions.Max(i => i.Number); + + if (instruction.Number >= maxStep) + { + return; + } + + var neighbor = instructions.FirstOrDefault(i => i.Number == instruction.Number + 1); + + if (neighbor != null) + { + await _instructionRepository.SwapInstructionOrderAsync(instruction, neighbor); + } + } + + public async Task MoveInstructionUpAsync(Guid instructionId) + { + var instruction = await _instructionRepository.GetInstructionWithRecipeAsync(instructionId); + + if (instruction.Number == 1) + { + return; + } + + var instructions = await _instructionRepository.GetInstructionsByRecipeIdAsync(instruction.Recipe.Id); + + var neighbor = instructions.FirstOrDefault(i => i.Number == instruction.Number - 1); + + if (neighbor != null) + { + await _instructionRepository.SwapInstructionOrderAsync(instruction, neighbor); + } + } + } +} From 825818645a274b8b3b7903e9c2f9833496d1456a Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 16 Apr 2025 17:22:19 +0200 Subject: [PATCH 09/27] Refactoring some code and change logic and make sure to reduce db calls and avoid redundants --- .../Instruction/IInstructionRepository.cs | 4 +- .../Instruction/InstructionRepository.cs | 21 ++-------- .../Instruction/IInstructionService.cs | 2 + .../Instruction/InstructionService.cs | 42 ++++++++----------- 4 files changed, 25 insertions(+), 44 deletions(-) diff --git a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs index 528f6b8..057eb02 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs @@ -8,12 +8,10 @@ Task CreateInstructionToRecipeAsync(Guid recipeId, string description, int number); - Task> GetInstructionsByRecipeIdAsync(Guid recipeId); - Task RemoveInstructionFromRecipeAsync(Guid recipeId, Guid instructionId); Task SwapInstructionOrderAsync(Instruction a, Instruction b); - Task GetInstructionWithRecipeAsync(Guid instructionId); + Task> GetInstructionsByInstructionIdAsync(Guid instructionId); } } diff --git a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs index 0a71b5f..a95e22d 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs @@ -70,32 +70,19 @@ } } - public async Task> GetInstructionsByRecipeIdAsync(Guid recipeId) - { - return await _context.Instructions - .Include(i => i.Recipe) - .Where(i => i.Recipe.Id == recipeId) - .ToListAsync(); - } - - public async Task GetInstructionWithRecipeAsync(Guid instructionId) + public async Task> GetInstructionsByInstructionIdAsync(Guid instructionId) { var instruction = await _context.Instructions .Include(i => i.Recipe) .ThenInclude(r => r.Instructions) .FirstOrDefaultAsync(i => i.Id == instructionId); - if (instruction == null) + if (instruction?.Recipe == null) { - throw new InvalidDataException($"Instruction with ID {instructionId} not found."); + throw new InvalidDataException($"Instruction with ID {instructionId} or its Recipe not found."); } - if (instruction.Recipe == null) - { - throw new InvalidDataException($"The Recipe for Instruction with ID {instructionId} is not loaded or does not exist."); - } - - return instruction; + return instruction.Recipe.Instructions.ToList(); } public async Task SwapInstructionOrderAsync(Instruction a, Instruction b) diff --git a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs index fa514a1..efb6b00 100644 --- a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs @@ -5,5 +5,7 @@ Task MoveInstructionUpAsync(Guid instructionId); Task MoveInstructionDownAsync(Guid instructionId); + + Task MoveInstructionAsync(Guid instructionId, bool moveUp); } } diff --git a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs index 5015426..895cf66 100644 --- a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs @@ -11,39 +11,33 @@ namespace Francesco.Recipes.World.Services.Instruction _instructionRepository = instructionRepository; } - public async Task MoveInstructionDownAsync(Guid instructionId) + public Task MoveInstructionUpAsync(Guid instructionId) + => MoveInstructionAsync(instructionId, moveUp: true); + + public Task MoveInstructionDownAsync(Guid instructionId) + => MoveInstructionAsync(instructionId, moveUp: false); + + private async Task MoveInstructionAsync(Guid instructionId, bool moveUp) { - var instruction = await _instructionRepository.GetInstructionWithRecipeAsync(instructionId); + var instructions = await _instructionRepository.GetInstructionsByInstructionIdAsync(instructionId); - var instructions = await _instructionRepository.GetInstructionsByRecipeIdAsync(instruction.Recipe.Id); + var instruction = instructions.FirstOrDefault(i => i.Id == instructionId); + if (instruction == null) + { + throw new InvalidDataException($"Instruction with ID {instructionId} not found."); + } + + var minStep = 1; var maxStep = instructions.Max(i => i.Number); - if (instruction.Number >= maxStep) + if ((moveUp && instruction.Number == minStep) || (!moveUp && instruction.Number >= maxStep)) { return; } - var neighbor = instructions.FirstOrDefault(i => i.Number == instruction.Number + 1); - - if (neighbor != null) - { - await _instructionRepository.SwapInstructionOrderAsync(instruction, neighbor); - } - } - - public async Task MoveInstructionUpAsync(Guid instructionId) - { - var instruction = await _instructionRepository.GetInstructionWithRecipeAsync(instructionId); - - if (instruction.Number == 1) - { - return; - } - - var instructions = await _instructionRepository.GetInstructionsByRecipeIdAsync(instruction.Recipe.Id); - - var neighbor = instructions.FirstOrDefault(i => i.Number == instruction.Number - 1); + var targetNumber = moveUp ? instruction.Number - 1 : instruction.Number + 1; + var neighbor = instructions.FirstOrDefault(i => i.Number == targetNumber); if (neighbor != null) { From 32aaec7d65d83c0ca28359e4429035af87771c08 Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 16 Apr 2025 17:27:08 +0200 Subject: [PATCH 10/27] Remove the interface declaration for MoveInstructionAsync since it's now a private method --- .../Services/Instruction/IInstructionService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs index efb6b00..8ddedf5 100644 --- a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs @@ -6,6 +6,5 @@ Task MoveInstructionDownAsync(Guid instructionId); - Task MoveInstructionAsync(Guid instructionId, bool moveUp); } } From 059e93cb86542ab12c1597d2a87a16be2ac38fa9 Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 16 Apr 2025 17:27:41 +0200 Subject: [PATCH 11/27] Remove Blank line --- .../Services/Instruction/IInstructionService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs index 8ddedf5..fa514a1 100644 --- a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs @@ -5,6 +5,5 @@ Task MoveInstructionUpAsync(Guid instructionId); Task MoveInstructionDownAsync(Guid instructionId); - } } From 1bdb14e9d3d5642ae63b3e37fcddc0d71d988980 Mon Sep 17 00:00:00 2001 From: franc Date: Thu, 17 Apr 2025 10:34:12 +0200 Subject: [PATCH 12/27] Rename Refactoring --- .../Repositories/Instruction/IInstructionRepository.cs | 4 ++-- .../Repositories/Instruction/InstructionRepository.cs | 4 ++-- .../Services/Instruction/InstructionService.cs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs index 057eb02..e1fd1e6 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs @@ -10,8 +10,8 @@ Task RemoveInstructionFromRecipeAsync(Guid recipeId, Guid instructionId); - Task SwapInstructionOrderAsync(Instruction a, Instruction b); + Task SwapInstructionNumbersAsync(Instruction a, Instruction b); - Task> GetInstructionsByInstructionIdAsync(Guid instructionId); + Task> GetInstructionsOfRecipeAsync(Guid instructionId); } } diff --git a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs index a95e22d..9a4445d 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs @@ -70,7 +70,7 @@ } } - public async Task> GetInstructionsByInstructionIdAsync(Guid instructionId) + public async Task> GetInstructionsOfRecipeAsync(Guid instructionId) { var instruction = await _context.Instructions .Include(i => i.Recipe) @@ -85,7 +85,7 @@ return instruction.Recipe.Instructions.ToList(); } - public async Task SwapInstructionOrderAsync(Instruction a, Instruction b) + public async Task SwapInstructionNumbersAsync(Instruction a, Instruction b) { if (a == null) { diff --git a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs index 895cf66..c7a4acc 100644 --- a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs @@ -19,7 +19,7 @@ namespace Francesco.Recipes.World.Services.Instruction private async Task MoveInstructionAsync(Guid instructionId, bool moveUp) { - var instructions = await _instructionRepository.GetInstructionsByInstructionIdAsync(instructionId); + var instructions = await _instructionRepository.GetInstructionsOfRecipeAsync(instructionId); var instruction = instructions.FirstOrDefault(i => i.Id == instructionId); @@ -36,12 +36,12 @@ namespace Francesco.Recipes.World.Services.Instruction return; } - var targetNumber = moveUp ? instruction.Number - 1 : instruction.Number + 1; + var targetNumber = moveUp ? instruction.Number + 1 : instruction.Number - 1; var neighbor = instructions.FirstOrDefault(i => i.Number == targetNumber); if (neighbor != null) { - await _instructionRepository.SwapInstructionOrderAsync(instruction, neighbor); + await _instructionRepository.SwapInstructionNumbersAsync(instruction, neighbor); } } } From 0859e3aa2b9b84a6aff0de1b3e838e560a9346db Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 23 Apr 2025 13:27:51 +0200 Subject: [PATCH 13/27] Add recipeid to the methods seperate the Id logic between instructionId and recipeId --- .../Services/Instruction/IInstructionService.cs | 4 ++-- .../Services/Instruction/InstructionService.cs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs index fa514a1..41bfe0f 100644 --- a/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/IInstructionService.cs @@ -2,8 +2,8 @@ { public interface IInstructionService { - Task MoveInstructionUpAsync(Guid instructionId); + Task MoveInstructionUpAsync(Guid recipeId, Guid instructionId); - Task MoveInstructionDownAsync(Guid instructionId); + Task MoveInstructionDownAsync(Guid recipeId, Guid instructionId); } } diff --git a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs index c7a4acc..ed95792 100644 --- a/Francesco.Recipes.World/Services/Instruction/InstructionService.cs +++ b/Francesco.Recipes.World/Services/Instruction/InstructionService.cs @@ -11,15 +11,15 @@ namespace Francesco.Recipes.World.Services.Instruction _instructionRepository = instructionRepository; } - public Task MoveInstructionUpAsync(Guid instructionId) - => MoveInstructionAsync(instructionId, moveUp: true); + public Task MoveInstructionUpAsync(Guid recipeId, Guid instructionId) + => MoveInstructionAsync(recipeId, instructionId, moveUp: true); - public Task MoveInstructionDownAsync(Guid instructionId) - => MoveInstructionAsync(instructionId, moveUp: false); + public Task MoveInstructionDownAsync(Guid recipeId, Guid instructionId) + => MoveInstructionAsync(recipeId, instructionId, moveUp: false); - private async Task MoveInstructionAsync(Guid instructionId, bool moveUp) + private async Task MoveInstructionAsync(Guid recipeId, Guid instructionId, bool moveUp) { - var instructions = await _instructionRepository.GetInstructionsOfRecipeAsync(instructionId); + var instructions = await _instructionRepository.GetInstructionsOfRecipeAsync(recipeId); var instruction = instructions.FirstOrDefault(i => i.Id == instructionId); @@ -36,7 +36,7 @@ namespace Francesco.Recipes.World.Services.Instruction return; } - var targetNumber = moveUp ? instruction.Number + 1 : instruction.Number - 1; + var targetNumber = moveUp ? instruction.Number - 1 : instruction.Number + 1; var neighbor = instructions.FirstOrDefault(i => i.Number == targetNumber); if (neighbor != null) From 0d1f18ecf688e0d4fd25aaf7420ec17f4a6de21a Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 23 Apr 2025 13:28:24 +0200 Subject: [PATCH 14/27] Just add scope for InstructionService --- Francesco.Recipes.World/Program.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Francesco.Recipes.World/Program.cs b/Francesco.Recipes.World/Program.cs index 40317b6..1caf8cf 100644 --- a/Francesco.Recipes.World/Program.cs +++ b/Francesco.Recipes.World/Program.cs @@ -7,6 +7,7 @@ using Francesco.Recipes.World.Repositories.MediaFile; using Francesco.Recipes.World.Repositories.Recipe; using Francesco.Recipes.World.Repositories.ShoppingList; using Francesco.Recipes.World.Repositories.Unit; +using Francesco.Recipes.World.Services.Instruction; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); @@ -40,6 +41,8 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); + var app = builder.Build(); // Configure the HTTP request pipeline. From 146cdf9bffb310005a70dcc0b9754ef8a577223e Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 23 Apr 2025 13:32:18 +0200 Subject: [PATCH 15/27] Remove unnecessary context dependency --- .../Controller/MediaFile/MediaFileController.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs b/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs index 0d9ddf3..5e2ebde 100644 --- a/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs +++ b/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs @@ -8,12 +8,10 @@ public class MediaFileController : Controller { private readonly IMediaFileRepository _mediaFileRepository; - private readonly FrancescosRecipesWorldDbContext _context; public MediaFileController(IMediaFileRepository mediaFileRepository, FrancescosRecipesWorldDbContext context) { _mediaFileRepository = mediaFileRepository; - _context = context; } // POST: /UploadImage From 7035a9b64ddafdb89187cd548ec6fca201fadb6d Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 23 Apr 2025 13:33:33 +0200 Subject: [PATCH 16/27] Add also here recipeId --- .../Instruction/InstructionController.cs | 61 ++++++++++++- .../MediaFile/MediaFileController.cs | 4 +- .../Controller/Recipe/RecipeController.cs | 1 - .../Instruction/IInstructionRepository.cs | 2 +- .../Instruction/InstructionRepository.cs | 16 ++-- .../Views/Shared/_GetInstructions.cshtml | 89 +++++++++++++++++++ 6 files changed, 160 insertions(+), 13 deletions(-) create mode 100644 Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml diff --git a/Francesco.Recipes.World/Controller/Instruction/InstructionController.cs b/Francesco.Recipes.World/Controller/Instruction/InstructionController.cs index d86aadf..4ce79ef 100644 --- a/Francesco.Recipes.World/Controller/Instruction/InstructionController.cs +++ b/Francesco.Recipes.World/Controller/Instruction/InstructionController.cs @@ -1,6 +1,65 @@ namespace Francesco.Recipes.World.Controller.Instruction { - public class InstructionController + using Francesco.Recipes.World.Repositories.Instruction; + using Francesco.Recipes.World.Services.Instruction; + using Microsoft.AspNetCore.Mvc; + + public class InstructionController : Controller { + private readonly IInstructionService _instructionService; + private readonly IInstructionRepository _instructionRepository; + + public InstructionController(IInstructionService instructionService, IInstructionRepository instructionRepository) + { + _instructionService = instructionService; + _instructionRepository = instructionRepository; + } + + [HttpPost("Recipe/{recipeId}/Instruction/{instructionId}/move-up")] + [ValidateAntiForgeryToken] + public async Task MoveUp(Guid recipeId, Guid instructionId) + { + try + { + await _instructionService.MoveInstructionUpAsync(recipeId, instructionId); + return Ok(new { Message = "Instruction moved up successfully." }); + } + catch (Exception ex) + { + return BadRequest(new { Error = ex.Message }); + } + } + + [HttpPost("Recipe/{recipeId}/Instruction/{instructionId}/move-down")] + [ValidateAntiForgeryToken] + public async Task MoveDown(Guid recipeId, Guid instructionId) + { + try + { + await _instructionService.MoveInstructionDownAsync(recipeId, instructionId); + return Ok(new { Message = "Instruction moved down successfully." }); + } + catch (Exception ex) + { + return BadRequest(new { Error = ex.Message }); + } + } + + [HttpGet("Recipe/{recipeId}/Instructions")] + public async Task GetInstructions(Guid recipeId) + { + try + { + var instructions = await _instructionRepository.GetInstructionsOfRecipeAsync(recipeId); + var sortedInstructions = instructions.OrderBy(i => i.Number).ToList(); + ViewData["RecipeId"] = recipeId; + + return View("~/Views/Shared/_GetInstructions.cshtml", sortedInstructions); + } + catch (Exception ex) + { + return BadRequest(new { Error = ex.Message }); + } + } } } diff --git a/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs b/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs index 5e2ebde..c624b4a 100644 --- a/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs +++ b/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs @@ -1,6 +1,6 @@ namespace Francesco.Recipes.World.Controller.MediaFile { - using Francesco.Recipes.World.Data; + using Francesco.Recipes.World.Repositories.MediaFile; using Microsoft.AspNetCore.Mvc; @@ -9,7 +9,7 @@ { private readonly IMediaFileRepository _mediaFileRepository; - public MediaFileController(IMediaFileRepository mediaFileRepository, FrancescosRecipesWorldDbContext context) + public MediaFileController(IMediaFileRepository mediaFileRepository) { _mediaFileRepository = mediaFileRepository; } diff --git a/Francesco.Recipes.World/Controller/Recipe/RecipeController.cs b/Francesco.Recipes.World/Controller/Recipe/RecipeController.cs index 24d9618..7f31c54 100644 --- a/Francesco.Recipes.World/Controller/Recipe/RecipeController.cs +++ b/Francesco.Recipes.World/Controller/Recipe/RecipeController.cs @@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; - public class RecipeController : Controller { private readonly IRecipeRepository _recipeRepository; diff --git a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs index e1fd1e6..2b17a6f 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs @@ -12,6 +12,6 @@ Task SwapInstructionNumbersAsync(Instruction a, Instruction b); - Task> GetInstructionsOfRecipeAsync(Guid instructionId); + Task> GetInstructionsOfRecipeAsync(Guid recipeId); } } diff --git a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs index 9a4445d..e94fd34 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs @@ -70,19 +70,19 @@ } } - public async Task> GetInstructionsOfRecipeAsync(Guid instructionId) + public async Task> GetInstructionsOfRecipeAsync(Guid recipeId) { - var instruction = await _context.Instructions - .Include(i => i.Recipe) - .ThenInclude(r => r.Instructions) - .FirstOrDefaultAsync(i => i.Id == instructionId); + var instructions = await _context.Instructions + .Where(i => i.Recipe.Id == recipeId) + .OrderBy(i => i.Number) + .ToListAsync(); - if (instruction?.Recipe == null) + if (!instructions.Any()) { - throw new InvalidDataException($"Instruction with ID {instructionId} or its Recipe not found."); + throw new InvalidDataException($"No instructions found for Recipe ID {recipeId}."); } - return instruction.Recipe.Instructions.ToList(); + return instructions; } public async Task SwapInstructionNumbersAsync(Instruction a, Instruction b) diff --git a/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml b/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml new file mode 100644 index 0000000..251b4fc --- /dev/null +++ b/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml @@ -0,0 +1,89 @@ +@Html.AntiForgeryToken() +
+ @for (int i = 0; i < Model.Count; i++) + { +
+
+ + + +
+
+ + +
+
+ } +
+ + + +@section Scripts { + +} From e169e94c8e22fe3908edeebed2ccb5ec589f7af0 Mon Sep 17 00:00:00 2001 From: franc Date: Wed, 23 Apr 2025 13:40:27 +0200 Subject: [PATCH 17/27] Solve format --- .../Controller/MediaFile/MediaFileController.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs b/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs index c624b4a..1f17d7a 100644 --- a/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs +++ b/Francesco.Recipes.World/Controller/MediaFile/MediaFileController.cs @@ -1,6 +1,5 @@ namespace Francesco.Recipes.World.Controller.MediaFile { - using Francesco.Recipes.World.Repositories.MediaFile; using Microsoft.AspNetCore.Mvc; From bcc0a606694c3b6f719cc63c10fc9e29430d6180 Mon Sep 17 00:00:00 2001 From: franc Date: Mon, 28 Apr 2025 13:10:41 +0200 Subject: [PATCH 18/27] Update Controller stuff with Repo Methods --- .../Controller/Recipe/RecipeController.cs | 45 ++++++++++++++++++- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/Francesco.Recipes.World/Controller/Recipe/RecipeController.cs b/Francesco.Recipes.World/Controller/Recipe/RecipeController.cs index 7f31c54..72bf903 100644 --- a/Francesco.Recipes.World/Controller/Recipe/RecipeController.cs +++ b/Francesco.Recipes.World/Controller/Recipe/RecipeController.cs @@ -188,6 +188,47 @@ return RedirectToAction("Details", new { id = recipeId }); } + // GET: /Recipe/{recipeId}/RemoveInstruction/{instructionId} + [HttpGet("{recipeId}/RemoveInstruction/{instructionId}")] + public async Task RemoveInstruction(Guid recipeId, Guid instructionId) + { + var recipe = await _recipeRepository.GetRecipeAsync(recipeId); + + if (recipe == null) + { + return NotFound("Recipe not found."); + } + + var instruction = recipe.Instructions?.FirstOrDefault(i => i.Id == instructionId); + if (instruction == null) + { + return NotFound("Instruction not found in the specified recipe."); + } + + ViewBag.RecipeId = recipeId; + ViewBag.InstructionId = instructionId; + + return View(); + } + + // POST: /Recipe/{recipeId}/RemoveInstruction/{instructionId} + [HttpPost("{recipeId}/RemoveInstruction/{instructionId}")] + [ValidateAntiForgeryToken] + public async Task RemoveInstructionConfirmed(Guid recipeId, Guid instructionId) + { + try + { + await _instructionRepository.RemoveInstructionFromRecipeAsync(recipeId, instructionId); + TempData["SuccessMessage"] = "Instruction removed successfully."; + return RedirectToAction("Details", new { recipeId }); + } + catch (Exception ex) + { + TempData["ErrorMessage"] = $"An error occurred while removing the instruction: {ex.Message}"; + return RedirectToAction("Details", new { recipeId }); + } + } + // GET: /Recipe/FilterByDifficulty [HttpGet("FilterByDifficulty")] public async Task FilterByDifficulty(Difficulty? selectedDifficulty) @@ -218,11 +259,11 @@ // POST: /Recipe/{recipeId}/AddInstruction [HttpPost("{recipeId}/AddInstruction")] [ValidateAntiForgeryToken] - public async Task AddInstruction(Guid recipeId, string description, int number) + public async Task AddInstruction(Guid recipeId, string description) { try { - await _instructionRepository.CreateInstructionToRecipeAsync(recipeId, description, number); + await _instructionRepository.CreateInstructionToRecipeAsync(recipeId, description); return RedirectToAction("AddInstruction", new { recipeId }); } catch (Exception ex) From 2f879d987bf8f948c530512ce0389e89940b2c19 Mon Sep 17 00:00:00 2001 From: franc Date: Mon, 28 Apr 2025 13:11:28 +0200 Subject: [PATCH 19/27] Add more methods for improve sort logic --- .../Instruction/IInstructionRepository.cs | 4 +- .../Instruction/InstructionRepository.cs | 42 ++++++++++++++++--- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs index 2b17a6f..ef8094f 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/IInstructionRepository.cs @@ -6,12 +6,14 @@ { Task GetInstructionAsync(Guid instructionId); - Task CreateInstructionToRecipeAsync(Guid recipeId, string description, int number); + Task CreateInstructionToRecipeAsync(Guid recipeId, string description); Task RemoveInstructionFromRecipeAsync(Guid recipeId, Guid instructionId); Task SwapInstructionNumbersAsync(Instruction a, Instruction b); Task> GetInstructionsOfRecipeAsync(Guid recipeId); + + Task RenumberInstructionsAsync(Guid recipeId); } } diff --git a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs index e94fd34..6844c0a 100644 --- a/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs +++ b/Francesco.Recipes.World/Repositories/Instruction/InstructionRepository.cs @@ -22,25 +22,30 @@ return instruction ?? throw new InvalidDataException($"Instruction {instructionId} not found."); } - public async Task CreateInstructionToRecipeAsync(Guid recipeId, string description, int number) + public async Task CreateInstructionToRecipeAsync(Guid recipeId, string description) { - var recipe = await _recipeRepository.GetRecipeAsync(recipeId); - if (string.IsNullOrWhiteSpace(description)) { throw new ArgumentException("Description cannot be empty", nameof(description)); } - if (number <= 0) + var recipe = await _context.Recipes + .Include(r => r.Instructions) + .FirstOrDefaultAsync(r => r.Id == recipeId); + + if (recipe == null) { - throw new ArgumentOutOfRangeException(nameof(number), "Number must be greater than 0."); + throw new ArgumentException("Recipe not found.", nameof(recipeId)); } + var nextNumber = recipe.Instructions?.Max(i => i.Number) ?? 0; + nextNumber++; + var newInstruction = new Instruction { Id = Guid.NewGuid(), Description = description, - Number = number, + Number = nextNumber, Recipe = recipe, }; @@ -65,8 +70,18 @@ if (instructionToRemove != null) { + await _context.Entry(instructionToRemove) + .Collection(i => i.MediaFiles) + .LoadAsync(); + + if (instructionToRemove.MediaFiles != null && instructionToRemove.MediaFiles.Any()) + { + _context.MediaFiles.RemoveRange(instructionToRemove.MediaFiles); + } + recipe.Instructions?.Remove(instructionToRemove); await _context.SaveChangesAsync(); + await RenumberInstructionsAsync(recipeId); } } @@ -85,6 +100,21 @@ return instructions; } + public async Task RenumberInstructionsAsync(Guid recipeId) + { + var instructions = await _context.Instructions + .Where(i => i.Recipe.Id == recipeId) + .OrderBy(i => i.Number) + .ToListAsync(); + + for (var i = 0; i < instructions.Count; i++) + { + instructions[i].Number = i + 1; + } + + await _context.SaveChangesAsync(); + } + public async Task SwapInstructionNumbersAsync(Instruction a, Instruction b) { if (a == null) From 9c1584d621dc1c0ad00903933c4c4c1c23902c45 Mon Sep 17 00:00:00 2001 From: franc Date: Mon, 28 Apr 2025 13:13:24 +0200 Subject: [PATCH 20/27] Make two views for sort logic one for show the instructions and the other for add Instruction --- .../Views/Recipe/AddInstruction.cshtml | 50 ++++++++++--------- .../Views/Shared/_GetInstructions.cshtml | 28 ++++++++++- 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/Francesco.Recipes.World/Views/Recipe/AddInstruction.cshtml b/Francesco.Recipes.World/Views/Recipe/AddInstruction.cshtml index d6d5f79..e2ce85d 100644 --- a/Francesco.Recipes.World/Views/Recipe/AddInstruction.cshtml +++ b/Francesco.Recipes.World/Views/Recipe/AddInstruction.cshtml @@ -24,36 +24,38 @@ -
- - -
- + + @section Scripts { - if (response.ok) { - location.reload(); - } else { - alert('Failed to add instruction.'); - } - } - } diff --git a/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml b/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml index 251b4fc..695bda0 100644 --- a/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml +++ b/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml @@ -6,7 +6,7 @@
- +
@@ -68,6 +68,32 @@ } } + async function removeInstruction(instructionId) { + if (!confirm('Möchtest du diesen Schritt wirklich löschen?')) return; + + try { + const response = await fetch(`/${recipeId}/RemoveInstruction/${instructionId}`, { + method: 'POST', + headers: { + 'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value + } + }); + + if (response.ok) { + const element = document.getElementById(`instruction-${instructionId}`); + if (element) { + element.remove(); + } + } else { + const error = await response.json(); + alert(error.Error || 'Fehler beim Löschen der Anweisung.'); + } + } catch (error) { + console.error('Fehler beim Löschen:', error); + } + } + + function addInstruction() { const container = document.getElementById('instructions-container'); const newInstructionHtml = ` From aa5cc3d6835bec9c4c7b5ccda5c8942b5f506275 Mon Sep 17 00:00:00 2001 From: franc Date: Mon, 28 Apr 2025 15:00:50 +0200 Subject: [PATCH 21/27] Use InstructionViewModel --- .../Views/Shared/_GetInstructions.cshtml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml b/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml index 695bda0..5884c07 100644 --- a/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml +++ b/Francesco.Recipes.World/Views/Shared/_GetInstructions.cshtml @@ -1,16 +1,17 @@ -@Html.AntiForgeryToken() +@model Francesco.Recipes.World.Models.InstructionViewModel +@Html.AntiForgeryToken()
- @for (int i = 0; i < Model.Count; i++) + @for (int i = 0; i < Model.Instructions.Count; i++) { -
+
- - + +
- - + +
} @@ -18,6 +19,7 @@ + @section Scripts {