diff --git a/backend/API/BusinessLogic/RecipeLogic.cs b/backend/API/BusinessLogic/RecipeLogic.cs new file mode 100644 index 0000000..eb32f5f --- /dev/null +++ b/backend/API/BusinessLogic/RecipeLogic.cs @@ -0,0 +1,81 @@ +using API.DBAccess; +using API.Models.RecipeModels; +using Microsoft.AspNetCore.Mvc; + +namespace API.BusinessLogic +{ + public class RecipeLogic + { + private readonly RecipeDBaccess _dbAccess; + private readonly IConfiguration _configuration; + + public RecipeLogic(IConfiguration configuration, RecipeDBaccess dbAccess) + { + _dbAccess = dbAccess; + _configuration = configuration; + } + + public async Task GetPrefereredRecipes(int userId) + { + PrefereredRecipes recipes = await _dbAccess.ReadPrefereredRecipes(userId); + if (recipes == null) { recipes = await _dbAccess.CreateMissingLists(userId); } + if (recipes == null || recipes.Id == 0) { return new ConflictObjectResult(new { message = "Could not find any recipes" }); } + + return new OkObjectResult(recipes); + } + + public async Task GetRecipe(int recipeId) + { + var recipe = await _dbAccess.ReadRecipe(recipeId); + + if (recipe == null || recipe.Id == 0) { return new ConflictObjectResult(new { message = "Could not find any recipe" }); } + + return new OkObjectResult(recipe); + } + + public async Task CreateRecipe(Recipe recipe, int prefereredRecipesId) + { + var prefereredRecipes = await _dbAccess.ReadAllRecipe(prefereredRecipesId); + + foreach (var item in prefereredRecipes.Recipes) + { + if (item.Name == recipe.Name) + { + return new ConflictObjectResult(new { message = "Recipe name is already in use." }); + } + } + + return await _dbAccess.CreateRecipe(recipe, prefereredRecipesId); + } + + public async Task EditRecipe(Recipe recipe, int recipeId, int userId) + { + var prefereredRecipes = await _dbAccess.ReadPrefereredRecipes(userId); + var dish = await _dbAccess.ReadRecipe(recipeId); + + foreach (var item in prefereredRecipes.Recipes) + { + if (item.Name == recipe.Name) + { + return new ConflictObjectResult(new { message = "Recipe name is already in use." }); + } + } + + dish.Name = recipe.Name; + dish.Description = recipe.Description; + dish.Directions = recipe.Directions; + dish.Ingredients = recipe.Ingredients; + + return await _dbAccess.UpdateRecipe(dish); + } + + public async Task DeleteRecipe(int recipeId) + { + var recipe = await _dbAccess.ReadRecipe(recipeId); + + if (recipe != null) { return await _dbAccess.DeleteUser(recipe); } + + return new ConflictObjectResult(new { message = "Invalid user" }); + } + } +} diff --git a/backend/API/BusinessLogic/UserLogic.cs b/backend/API/BusinessLogic/UserLogic.cs index 07fb887..c835bf4 100644 --- a/backend/API/BusinessLogic/UserLogic.cs +++ b/backend/API/BusinessLogic/UserLogic.cs @@ -1,8 +1,8 @@ using API.DBAccess; using API.Models.UserModels; +using API.Models.RecipeModels; using Microsoft.AspNetCore.Mvc; using Microsoft.IdentityModel.Tokens; -using Org.BouncyCastle.Asn1.Ocsp; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; @@ -13,10 +13,10 @@ namespace API.BusinessLogic { public class UserLogic { - private readonly DbAccess _dbAccess; + private readonly UserDBAccess _dbAccess; private readonly IConfiguration _configuration; - public UserLogic(IConfiguration configuration, DbAccess dbAccess) + public UserLogic(IConfiguration configuration, UserDBAccess dbAccess) { _dbAccess = dbAccess; _configuration = configuration; @@ -60,12 +60,16 @@ namespace API.BusinessLogic string salt = Guid.NewGuid().ToString(); string hashedPassword = ComputeHash(userDTO.Password, SHA256.Create(), salt); + PrefereredRecipes recipes = new PrefereredRecipes(); + recipes.Recipes = new List(); + User user = new User { UserName = userDTO.UserName, Email = userDTO.Email, Password = hashedPassword, Salt = salt, + PrefereredRecipes = recipes, }; return await _dbAccess.CreateUser(user); diff --git a/backend/API/Controllers/RecipeController.cs b/backend/API/Controllers/RecipeController.cs new file mode 100644 index 0000000..113adac --- /dev/null +++ b/backend/API/Controllers/RecipeController.cs @@ -0,0 +1,61 @@ +using API.BusinessLogic; +using API.Models.RecipeModels; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System.Security.Claims; + +namespace API.Controllers +{ + [ApiController] + [Route("api/[controller]")] + public class RecipeController :Controller + { + private readonly RecipeLogic _recipeLogic; + + public RecipeController(RecipeLogic recipeLogic) + { + _recipeLogic = recipeLogic; + } + + [Authorize] + [HttpGet("getall")] + public async Task ReadPrefereredRecipes() + { + var claims = HttpContext.User.Claims; + string userIdString = claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value; + int userId = Convert.ToInt32(userIdString); + return await _recipeLogic.GetPrefereredRecipes(userId); + } + + [Authorize] + [HttpGet("get/{recipeId}")] + public async Task ReadRecipe(int recipeId) + { + return await _recipeLogic.GetRecipe(recipeId); + } + + [Authorize] + [HttpPost("create/{prefereredRecipesId}")] + public async Task CreateRecipe([FromBody] Recipe recipe, int prefereredRecipesId) + { + return await _recipeLogic.CreateRecipe(recipe, prefereredRecipesId); + } + + [Authorize] + [HttpPut("edit/{recipeId}")] + public async Task EditRecipe([FromBody] Recipe recipe, int recipeId) + { + var claims = HttpContext.User.Claims; + string userIdString = claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier).Value; + int userId = Convert.ToInt32(userIdString); + return await _recipeLogic.EditRecipe(recipe, recipeId, userId); + } + + [Authorize] + [HttpDelete("delete/{recipeId}")] + public async Task DeleteRecipe(int recipeId) + { + return await _recipeLogic.DeleteRecipe(recipeId); + } + } +} diff --git a/backend/API/DBAccess/RecipeDBaccess.cs b/backend/API/DBAccess/RecipeDBaccess.cs new file mode 100644 index 0000000..10b1091 --- /dev/null +++ b/backend/API/DBAccess/RecipeDBaccess.cs @@ -0,0 +1,79 @@ +using API.Models.RecipeModels; +using API.Models.UserModels; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace API.DBAccess +{ + public class RecipeDBaccess + { + private readonly DBContext _context; + + public RecipeDBaccess(DBContext context) + { + _context = context; + } + + public async Task ReadPrefereredRecipes(int userId) + { + var recipes = await _context.Users.Include(u => u.PrefereredRecipes).ThenInclude(p => p.Recipes).FirstOrDefaultAsync(u => u.Id == userId); + + return recipes.PrefereredRecipes; + } + + public async Task ReadAllRecipe(int prefereredRecipesId) + { + return await _context.PrefereredRecipes.Include(p => p.Recipes).FirstOrDefaultAsync(r => r.Id == prefereredRecipesId); + } + + public async Task ReadRecipe(int recipeId) + { + return await _context.Recipes.Include(r => r.Ingredients).FirstOrDefaultAsync(r => r.Id == recipeId); + } + + public async Task CreateMissingLists(int userId) + { + var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == userId); + user.PrefereredRecipes = new PrefereredRecipes(); + user.PrefereredRecipes.Recipes = new List(); + + _context.SaveChangesAsync(); + + return await ReadPrefereredRecipes(userId); + } + + public async Task CreateRecipe(Recipe recipe, int prefereredRecipeId) + { + var recipes = await _context.PrefereredRecipes.Include(p => p.Recipes).FirstOrDefaultAsync(p => p.Id == prefereredRecipeId); + + recipes.Recipes.Add(recipe); + + bool saved = await _context.SaveChangesAsync() > 1; + + if (saved) { return new OkObjectResult(saved); } + + return new ConflictObjectResult(new { message = "Could not save to database" }); + } + + public async Task UpdateRecipe(Recipe recipe) + { + _context.Entry(recipe).State = EntityState.Modified; + + bool saved = await _context.SaveChangesAsync() >= 1; + + if (saved) { return new OkObjectResult(recipe); } + + return new ConflictObjectResult(new { message = "Could not save to database" }); + } + + public async Task DeleteUser(Recipe recipe) + { + _context.Recipes.Remove(recipe); + bool saved = await _context.SaveChangesAsync() >= 0; + + if (saved) { return new OkObjectResult(saved); } + + return new ConflictObjectResult(new { message = "Could not save to database" }); + } + } +} diff --git a/backend/API/DBAccess/DbAccess.cs b/backend/API/DBAccess/UserDBAccess.cs similarity index 96% rename from backend/API/DBAccess/DbAccess.cs rename to backend/API/DBAccess/UserDBAccess.cs index f994c5a..2e3f07b 100644 --- a/backend/API/DBAccess/DbAccess.cs +++ b/backend/API/DBAccess/UserDBAccess.cs @@ -4,11 +4,11 @@ using Microsoft.EntityFrameworkCore; namespace API.DBAccess { - public class DbAccess + public class UserDBAccess { private readonly DBContext _context; - public DbAccess(DBContext context) + public UserDBAccess(DBContext context) { _context = context; } @@ -65,8 +65,7 @@ namespace API.DBAccess if (saved) { return new OkObjectResult(user); } - return new ConflictObjectResult(new { message = "Could not save to database" }); - + return new ConflictObjectResult(new { message = "Could not save to database" }) } public async Task UpdatePassword(User user) diff --git a/backend/API/Startup.cs b/backend/API/Startup.cs index c0d4f97..3969135 100644 --- a/backend/API/Startup.cs +++ b/backend/API/Startup.cs @@ -25,8 +25,10 @@ namespace API services.AddDbContext(options => options.UseMySQL(_configuration.GetConnectionString("Database"))); - services.AddScoped(); + services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddControllers();