From 2735c703839a7d75ff19c75d08982654c01ee75e Mon Sep 17 00:00:00 2001 From: Maxime BATISTA Date: Fri, 12 May 2023 15:25:57 +0200 Subject: [PATCH 1/6] add simple persistence system for recipes --- Endpoint/Services.csproj | 13 +++++++++ LocalEndpoint/LocalEndpoint.cs | 6 ++-- LocalEndpoint/LocalServices.csproj | 14 ++++++++++ LocalEndpoint/RecipesDatabase.cs | 40 ++++++++++++++++++++++++--- Models/Ingredient.cs | 19 +++++++++++-- Models/PreparationStep.cs | 18 ++++++++++-- Models/Recipe.cs | 26 +++++++++++++---- Models/RecipeInfo.cs | 37 +++++++++++++++++++------ Models/User.cs | 19 +++++++++++-- Platforms/Android/AndroidManifest.xml | 1 + Views/FavoritesPage.xaml.cs | 2 -- 11 files changed, 167 insertions(+), 28 deletions(-) create mode 100644 Endpoint/Services.csproj create mode 100644 LocalEndpoint/LocalServices.csproj diff --git a/Endpoint/Services.csproj b/Endpoint/Services.csproj new file mode 100644 index 0000000..d24baee --- /dev/null +++ b/Endpoint/Services.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/LocalEndpoint/LocalEndpoint.cs b/LocalEndpoint/LocalEndpoint.cs index 9b27f1e..ea7ad3e 100644 --- a/LocalEndpoint/LocalEndpoint.cs +++ b/LocalEndpoint/LocalEndpoint.cs @@ -17,15 +17,15 @@ namespace LocalEndpoint public LocalEndpoint() { - RecipesDatabase db = new RecipesDatabase(); + RecipesDatabase db = new RecipesDatabase(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "/recipes.xaml"); //miam - db.Insert(new Recipe(new RecipeInfo("Chicken Salad", 500, 20, new Uri("https://healthyfitnessmeals.com/wp-content/uploads/2021/04/Southwest-chicken-salad-7-500x500.jpg"), 4, Guid.NewGuid()), Constants.USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + /*db.Insert(new Recipe(new RecipeInfo("Chicken Salad", 500, 20, new Uri("https://healthyfitnessmeals.com/wp-content/uploads/2021/04/Southwest-chicken-salad-7-500x500.jpg"), 4, Guid.NewGuid()), Constants.USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); db.Insert(new Recipe(new RecipeInfo("Chocolate Cake", 2500, 10, new Uri("https://bakewithshivesh.com/wp-content/uploads/2022/08/IMG_0248-scaled.jpg"), 3, Guid.NewGuid()), Constants.USER2, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); db.Insert(new Recipe(new RecipeInfo("Salmon", 20, 10, new Uri("https://www.wholesomeyum.com/wp-content/uploads/2021/06/wholesomeyum-Pan-Seared-Salmon-Recipe-13.jpg"), 4, Guid.NewGuid()), Constants.MAIN_USER_ACCOUNT.User, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); db.Insert(new Recipe(new RecipeInfo("Fish", 50, 30, new Uri("https://www.ciaanet.org/wp-content/uploads/2022/07/Atlantic-and-Pacific-whole-salmon-1024x683.jpg"), 4.5F, Guid.NewGuid()), Constants.MAIN_USER_ACCOUNT.User, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); db.Insert(new Recipe(new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()), Constants.USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - + */ recipesService = new RecipesService(db); } diff --git a/LocalEndpoint/LocalServices.csproj b/LocalEndpoint/LocalServices.csproj new file mode 100644 index 0000000..29b3db6 --- /dev/null +++ b/LocalEndpoint/LocalServices.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + + + + + + + + diff --git a/LocalEndpoint/RecipesDatabase.cs b/LocalEndpoint/RecipesDatabase.cs index 511cd80..70aba26 100644 --- a/LocalEndpoint/RecipesDatabase.cs +++ b/LocalEndpoint/RecipesDatabase.cs @@ -1,15 +1,45 @@ using Models; using System.Collections.Generic; using System.Collections.Immutable; - +using System.Runtime.Serialization; + namespace LocalEndpoint { - //Simple class to simulate a recipe database internal class RecipesDatabase { - private Dictionary recipes = new Dictionary(); + private static readonly DataContractSerializer RECIPES_SERIALIZER = new DataContractSerializer(typeof(List)); + + private readonly Dictionary recipes = new Dictionary(); + private readonly string dbPath; + + public RecipesDatabase(string path) + { + dbPath = path; + + + if (!File.Exists(dbPath)) + { + File.Create(dbPath); + } + if (new FileInfo(dbPath).Length == 0) + return; //file is empty thus there is nothing to deserialize + Console.WriteLine(File.ReadAllText(dbPath)); + + using (var stream = File.OpenRead(dbPath)) { + var recipes = RECIPES_SERIALIZER.ReadObject(stream) as List; + recipes.ForEach(recipe => this.recipes.Add(recipe.Info.Id, recipe)); + } + } + + private void SaveAll() + { + using (var stream = File.OpenWrite(dbPath)) + { + RECIPES_SERIALIZER.WriteObject(stream, recipes.Values.ToList()); + } + } public Recipe? Lookup(Guid id) { @@ -26,12 +56,14 @@ namespace LocalEndpoint public void Insert(Recipe recipe) { - recipes[recipe.Info.Id] = recipe; + recipes[recipe.Info.Id] = recipe; + SaveAll(); } public void Remove(Guid id) { recipes.Remove(id); + SaveAll(); } public ImmutableList ListAll() diff --git a/Models/Ingredient.cs b/Models/Ingredient.cs index 3a40a75..7caaa9d 100644 --- a/Models/Ingredient.cs +++ b/Models/Ingredient.cs @@ -1,4 +1,19 @@ -namespace Models +using System.Runtime.Serialization; + +namespace Models { - public record Ingredient(string Name, float Amount); + [DataContract] + public class Ingredient + { + [DataMember] + public string Name { get; init; } + [DataMember] + public float Amount { get; init; } + + public Ingredient(string name, float amount) + { + Name = name; + Amount = amount; + } + } } diff --git a/Models/PreparationStep.cs b/Models/PreparationStep.cs index 40899a7..779f797 100644 --- a/Models/PreparationStep.cs +++ b/Models/PreparationStep.cs @@ -1,5 +1,19 @@ -namespace Models +using System.Runtime.Serialization; + +namespace Models { + [DataContract] + public record PreparationStep + { + [DataMember] + public string Name { get; init; } + [DataMember] + public string Description { get; init; } - public record PreparationStep(string Name, string Description); + public PreparationStep(string name, string description) + { + Name = name; + Description = description; + } + } } diff --git a/Models/Recipe.cs b/Models/Recipe.cs index e077c22..f6152bf 100644 --- a/Models/Recipe.cs +++ b/Models/Recipe.cs @@ -1,10 +1,26 @@ using System.Collections.Immutable; +using System.Runtime.Serialization; namespace Models { - public record Recipe( - RecipeInfo Info, - User Owner, - ImmutableList Ingredients, - ImmutableList Steps); + [DataContract] + public class Recipe + { + [DataMember] + public RecipeInfo Info { get; init; } + [DataMember] + public User Owner { get; init; } + [DataMember] + public ImmutableList Ingredients { get; init; } + [DataMember] + public ImmutableList Steps { get; init; } + + public Recipe(RecipeInfo info, User owner, ImmutableList ingredients, ImmutableList steps) + { + Info = info; + Owner = owner; + Ingredients = ingredients; + Steps = steps; + } + } } \ No newline at end of file diff --git a/Models/RecipeInfo.cs b/Models/RecipeInfo.cs index 1265c96..2dfbbcc 100644 --- a/Models/RecipeInfo.cs +++ b/Models/RecipeInfo.cs @@ -1,10 +1,31 @@ -namespace Models +using System.Runtime.Serialization; + +namespace Models { - public record RecipeInfo( - string Name, - uint CalPerPers, - uint CookTimeMins, - Uri? Image, - float AverageNote, - Guid Id); + [DataContract] + public class RecipeInfo + { + [DataMember] + public string Name { get; init; } + [DataMember] + public uint CalPerPers { get; init; } + [DataMember] + public uint CookTimeMins { get; init; } + [DataMember] + public Uri? Image { get; init; } + [DataMember] + public float AverageNote { get; init; } + [DataMember] + public Guid Id { get; init; } + + public RecipeInfo(string name, uint calPerPers, uint cookTimeMins, Uri? image, float averageNote, Guid id) + { + Name = name; + CalPerPers = calPerPers; + CookTimeMins = cookTimeMins; + Image = image; + AverageNote = averageNote; + Id = id; + } + } } diff --git a/Models/User.cs b/Models/User.cs index 981cef6..2273a93 100644 --- a/Models/User.cs +++ b/Models/User.cs @@ -1,4 +1,19 @@ -namespace Models +using System.Runtime.Serialization; + +namespace Models { - public record User(Uri ProfilePicture, string Name); + [DataContract] + public class User + { + [DataMember] + public Uri ProfilePicture { get; init; } + [DataMember] + public string Name { get; init; } + + public User(Uri profilePicture, string name) + { + ProfilePicture = profilePicture; + Name = name; + } + } } diff --git a/Platforms/Android/AndroidManifest.xml b/Platforms/Android/AndroidManifest.xml index 60c24e0..7871058 100644 --- a/Platforms/Android/AndroidManifest.xml +++ b/Platforms/Android/AndroidManifest.xml @@ -3,4 +3,5 @@ + \ No newline at end of file diff --git a/Views/FavoritesPage.xaml.cs b/Views/FavoritesPage.xaml.cs index 8282f86..20b9ef2 100644 --- a/Views/FavoritesPage.xaml.cs +++ b/Views/FavoritesPage.xaml.cs @@ -3,10 +3,8 @@ using Models; namespace ShoopNCook.Pages; using Endpoint; -using LocalEndpoint; using Models; using ShoopNCook.Views; -using System.Security.Principal; public partial class FavoritesPage : ContentPage { From 6c47bf5dc997817fd66391b74576cb265a03f26c Mon Sep 17 00:00:00 2001 From: Maxime BATISTA Date: Fri, 12 May 2023 15:28:01 +0200 Subject: [PATCH 2/6] additional fixes --- LocalEndpoint/LocalEndpoint.cs | 3 ++- LocalEndpoint/RecipesService.cs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LocalEndpoint/LocalEndpoint.cs b/LocalEndpoint/LocalEndpoint.cs index ea7ad3e..666a9de 100644 --- a/LocalEndpoint/LocalEndpoint.cs +++ b/LocalEndpoint/LocalEndpoint.cs @@ -25,7 +25,8 @@ namespace LocalEndpoint db.Insert(new Recipe(new RecipeInfo("Salmon", 20, 10, new Uri("https://www.wholesomeyum.com/wp-content/uploads/2021/06/wholesomeyum-Pan-Seared-Salmon-Recipe-13.jpg"), 4, Guid.NewGuid()), Constants.MAIN_USER_ACCOUNT.User, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); db.Insert(new Recipe(new RecipeInfo("Fish", 50, 30, new Uri("https://www.ciaanet.org/wp-content/uploads/2022/07/Atlantic-and-Pacific-whole-salmon-1024x683.jpg"), 4.5F, Guid.NewGuid()), Constants.MAIN_USER_ACCOUNT.User, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); db.Insert(new Recipe(new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()), Constants.USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - */ + db.Insert(new Recipe(new RecipeInfo("Cupcake", 500, 12, new Uri("https://www.mycake.fr/wp-content/uploads/2015/12/rs_cupcake_4x3.jpg"), 4.2F, Guid.NewGuid()), account.User, new List { new Ingredient("Chocolate", 4) }.ToImmutableList(), new List { new PreparationStep("Eat Chocolate", "Eat the chocolate") }.ToImmutableList())); + */ recipesService = new RecipesService(db); } diff --git a/LocalEndpoint/RecipesService.cs b/LocalEndpoint/RecipesService.cs index 9684e02..e8df0c7 100644 --- a/LocalEndpoint/RecipesService.cs +++ b/LocalEndpoint/RecipesService.cs @@ -43,7 +43,6 @@ namespace LocalEndpoint if (data == null) { AccountOwnedRecipes recipes = new AccountOwnedRecipes(account, db); - recipes.UploadRecipe(new Recipe(new RecipeInfo("Cupcake", 500, 12, new Uri("https://www.mycake.fr/wp-content/uploads/2015/12/rs_cupcake_4x3.jpg"), 4.2F, Guid.NewGuid()), account.User, new List { new Ingredient("Chocolate", 4) }.ToImmutableList(), new List { new PreparationStep("Eat Chocolate", "Eat the chocolate") }.ToImmutableList())); AccountRecipesPreferences preferences = new AccountRecipesPreferences(account, db); data = new AccountData(recipes, preferences); accountsData.Add(account, data); From eb4d0cf7cab8efb5861467737945e293d87bcc48 Mon Sep 17 00:00:00 2001 From: "maxime.BATISTA@etu.uca.fr" Date: Sat, 13 May 2023 18:10:05 +0200 Subject: [PATCH 3/6] add catastrophic performance persistance system for accounts, users, recipes and recipe rates --- ConnectAppShell.xaml.cs | 2 +- Controllers/ConnectionController.cs | 4 +- Endpoint/IAccountRecipesPreferences.cs | 2 +- .../{IAccountManager.cs => IAuthService.cs} | 2 +- Endpoint/IEndpoint.cs | 2 +- LocalEndpoint/AccountData.cs | 11 -- LocalEndpoint/AccountOwnedRecipes.cs | 14 +- LocalEndpoint/AccountRecipesPreferences.cs | 61 ++++---- LocalEndpoint/AccountServices.cs | 6 + .../{ConnectionManager.cs => AuthService.cs} | 23 +-- LocalEndpoint/Constants.cs | 11 -- LocalEndpoint/Data/AccountData.cs | 17 +++ .../Data/CatastrophicPerformancesDatabase.cs | 143 ++++++++++++++++++ LocalEndpoint/Data/Database.cs | 32 ++++ LocalEndpoint/Data/RecipeData.cs | 14 ++ LocalEndpoint/Data/UserData.cs | 13 ++ LocalEndpoint/LocalEndpoint.cs | 51 +++++-- LocalEndpoint/RecipesDatabase.cs | 75 --------- LocalEndpoint/RecipesService.cs | 17 ++- Models/AccountRecipeRate.cs | 5 - Models/Ingredient.cs | 16 +- Models/PreparationStep.cs | 14 +- Models/Recipe.cs | 24 +-- Models/RecipeInfo.cs | 33 +--- Models/RecipeRate.cs | 11 ++ Models/User.cs | 14 +- Views/Components/RecipeView.xaml | 1 + Views/RecipePage.xaml.cs | 13 +- 28 files changed, 383 insertions(+), 248 deletions(-) rename Endpoint/{IAccountManager.cs => IAuthService.cs} (84%) delete mode 100644 LocalEndpoint/AccountData.cs create mode 100644 LocalEndpoint/AccountServices.cs rename LocalEndpoint/{ConnectionManager.cs => AuthService.cs} (50%) create mode 100644 LocalEndpoint/Data/AccountData.cs create mode 100644 LocalEndpoint/Data/CatastrophicPerformancesDatabase.cs create mode 100644 LocalEndpoint/Data/Database.cs create mode 100644 LocalEndpoint/Data/RecipeData.cs create mode 100644 LocalEndpoint/Data/UserData.cs delete mode 100644 LocalEndpoint/RecipesDatabase.cs delete mode 100644 Models/AccountRecipeRate.cs create mode 100644 Models/RecipeRate.cs diff --git a/ConnectAppShell.xaml.cs b/ConnectAppShell.xaml.cs index 29f3275..dd44352 100644 --- a/ConnectAppShell.xaml.cs +++ b/ConnectAppShell.xaml.cs @@ -7,7 +7,7 @@ using ShoopNCook.Pages; public partial class ConnectAppShell : Shell { - public ConnectAppShell(ConnectionObserver observer, IAccountManager accounts, IUserNotifier notifier) + public ConnectAppShell(ConnectionObserver observer, IAuthService accounts, IUserNotifier notifier) { ConnectionController controller = new ConnectionController(observer, accounts, notifier); InitializeComponent(); diff --git a/Controllers/ConnectionController.cs b/Controllers/ConnectionController.cs index 6ecfd51..0e59bb7 100644 --- a/Controllers/ConnectionController.cs +++ b/Controllers/ConnectionController.cs @@ -6,9 +6,9 @@ namespace ShoopNCook.Controllers public class ConnectionController : LoginController, RegisterController { private readonly ConnectionObserver observer; - private readonly IAccountManager accounts; + private readonly IAuthService accounts; private readonly IUserNotifier notifier; - public ConnectionController(ConnectionObserver observer, IAccountManager accounts, IUserNotifier notifier) { + public ConnectionController(ConnectionObserver observer, IAuthService accounts, IUserNotifier notifier) { this.observer = observer; this.accounts = accounts; this.notifier = notifier; diff --git a/Endpoint/IAccountRecipesPreferences.cs b/Endpoint/IAccountRecipesPreferences.cs index 1a40745..64d4f35 100644 --- a/Endpoint/IAccountRecipesPreferences.cs +++ b/Endpoint/IAccountRecipesPreferences.cs @@ -13,7 +13,7 @@ namespace Endpoint public void SetReviewScore(RecipeInfo info, uint score); public bool AddToWeeklyList(RecipeInfo info, uint persAmount); - public AccountRecipeRate GetRate(RecipeInfo info); + public RecipeRate GetRate(RecipeInfo info); public ImmutableList GetFavorites(); diff --git a/Endpoint/IAccountManager.cs b/Endpoint/IAuthService.cs similarity index 84% rename from Endpoint/IAccountManager.cs rename to Endpoint/IAuthService.cs index c61b79e..2b4fa73 100644 --- a/Endpoint/IAccountManager.cs +++ b/Endpoint/IAuthService.cs @@ -1,7 +1,7 @@ using Models; namespace Endpoint { - public interface IAccountManager + public interface IAuthService { public Account? Login(string email, string password); diff --git a/Endpoint/IEndpoint.cs b/Endpoint/IEndpoint.cs index 10906ee..bd75452 100644 --- a/Endpoint/IEndpoint.cs +++ b/Endpoint/IEndpoint.cs @@ -4,7 +4,7 @@ namespace Endpoint { public interface IEndpoint { - public IAccountManager AccountManager { get; } + public IAuthService AccountManager { get; } public IRecipesService RecipesService { get; } diff --git a/LocalEndpoint/AccountData.cs b/LocalEndpoint/AccountData.cs deleted file mode 100644 index cf84b07..0000000 --- a/LocalEndpoint/AccountData.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Endpoint; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LocalEndpoint -{ - internal record AccountData(IAccountOwnedRecipes Recipes, IAccountRecipesPreferences Preferences); -} diff --git a/LocalEndpoint/AccountOwnedRecipes.cs b/LocalEndpoint/AccountOwnedRecipes.cs index e3d8059..633d96e 100644 --- a/LocalEndpoint/AccountOwnedRecipes.cs +++ b/LocalEndpoint/AccountOwnedRecipes.cs @@ -1,4 +1,5 @@ using LocalEndpoint; +using LocalEndpoint.Data; using Models; using System.Collections.Immutable; @@ -10,17 +11,18 @@ namespace Endpoint public Account Account { get; init; } private readonly Dictionary ownedRecipes = new Dictionary(); - private readonly RecipesDatabase db; + private readonly Database db; - public AccountOwnedRecipes(Account account, RecipesDatabase db) + public AccountOwnedRecipes(Account account, Database db) { Account = account; this.db = db; //Retrieve all owned recipes from database. - db.ListAll().ForEach(recipe => + db.ListAllRecipes().ForEach(recipe => { - if (recipe.Owner == account.User) ownedRecipes[recipe.Info.Id] = recipe; + if (recipe.Owner.Equals(account.User)) + ownedRecipes.Add(recipe.Info.Id, recipe); }); } @@ -31,14 +33,14 @@ namespace Endpoint { return false; } - db.Insert(recipe); + db.InsertRecipe(recipe); ownedRecipes.Add(id, recipe); return true; } public bool RemoveRecipe(RecipeInfo info) { - db.Remove(info.Id); + db.RemoveRecipe(info.Id); return ownedRecipes.Remove(info.Id); } diff --git a/LocalEndpoint/AccountRecipesPreferences.cs b/LocalEndpoint/AccountRecipesPreferences.cs index ce8f296..d260838 100644 --- a/LocalEndpoint/AccountRecipesPreferences.cs +++ b/LocalEndpoint/AccountRecipesPreferences.cs @@ -1,24 +1,18 @@ using Endpoint; +using LocalEndpoint.Data; using Models; -using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace LocalEndpoint { internal class AccountRecipesPreferences : IAccountRecipesPreferences { - //Binds a recipe's id to it's account review ratings. - private readonly Dictionary ratings = new Dictionary(); //Binds a recipe's id to its amount of person stored in the account's weekly list private readonly Dictionary weekly = new Dictionary(); - private readonly RecipesDatabase db; - public AccountRecipesPreferences(Account account, RecipesDatabase db) + private readonly Database db; + public AccountRecipesPreferences(Account account, Database db) { Account = account; this.db = db; @@ -28,15 +22,17 @@ namespace LocalEndpoint public ImmutableList GetRecommendedRecipes() { - return db.ListAll().ConvertAll(recipe => recipe.Info); + return db.ListAllRecipes().ConvertAll(recipe => recipe.Info); } public ImmutableList GetFavorites() { List favorites = new List(); - foreach (Recipe recipe in db.ListAll()) + var ratings = db.ListRatesOf(Account.User.Id); + + foreach (Recipe recipe in db.ListAllRecipes()) { - if (ratings.TryGetValue(recipe.Info.Id, out AccountRecipeRate? rate)) + if (ratings.TryGetValue(recipe.Info.Id, out RecipeRate? rate)) { if (rate.IsFavorite) favorites.Add(recipe.Info); @@ -48,7 +44,7 @@ namespace LocalEndpoint public ImmutableList<(RecipeInfo, uint)> GetWeeklyList() { List<(RecipeInfo, uint)> weekly = new List<(RecipeInfo, uint)>(); - foreach (Recipe recipe in db.ListAll()) + foreach (Recipe recipe in db.ListAllRecipes()) { if (this.weekly.TryGetValue(recipe.Info.Id, out uint personAmmount)) { @@ -59,24 +55,19 @@ namespace LocalEndpoint } - public AccountRecipeRate GetRate(RecipeInfo info) + public RecipeRate GetRate(RecipeInfo info) { - AccountRecipeRate rate = null; + RecipeRate rate = null; + var ratings = db.ListRatesOf(Account.User.Id); + if (!ratings.TryGetValue(info.Id, out rate)) { - rate = new AccountRecipeRate(); + rate = new RecipeRate(); ratings.Add(info.Id, rate); } return rate; } - public void AddToFavorites(RecipeInfo info) - { - AccountRecipeRate rate = GetRate(info); - ratings[info.Id] = new AccountRecipeRate(true, rate.Rate); - } - - public bool AddToWeeklyList(RecipeInfo info, uint persAmount) { if (weekly.ContainsKey(info.Id)) @@ -87,16 +78,32 @@ namespace LocalEndpoint return true; } + + public void AddToFavorites(RecipeInfo info) + { + Guid userId = Account.User.Id; + var ratings = db.ListRatesOf(userId); + RecipeRate rate = GetRate(info); + + db.InsertRate(userId, info.Id, new RecipeRate(true, rate.Rate)); + } + public void RemoveFromFavorites(RecipeInfo info) { - AccountRecipeRate rate = GetRate(info); - ratings[info.Id] = new AccountRecipeRate(false, rate.Rate); + Guid userId = Account.User.Id; + var ratings = db.ListRatesOf(userId); + RecipeRate rate = GetRate(info); + + db.InsertRate(userId, info.Id, new RecipeRate(false, rate.Rate)); } public void SetReviewScore(RecipeInfo info, uint score) { - AccountRecipeRate rate = GetRate(info); - ratings[info.Id] = new AccountRecipeRate(rate.IsFavorite, score); + Guid userId = Account.User.Id; + var ratings = db.ListRatesOf(userId); + RecipeRate rate = GetRate(info); + + db.InsertRate(userId, info.Id, new RecipeRate(rate.IsFavorite, score)); } } } diff --git a/LocalEndpoint/AccountServices.cs b/LocalEndpoint/AccountServices.cs new file mode 100644 index 0000000..02d4d6a --- /dev/null +++ b/LocalEndpoint/AccountServices.cs @@ -0,0 +1,6 @@ +using Endpoint; + +namespace LocalEndpoint +{ + internal record AccountServices(IAccountOwnedRecipes Recipes, IAccountRecipesPreferences Preferences); +} diff --git a/LocalEndpoint/ConnectionManager.cs b/LocalEndpoint/AuthService.cs similarity index 50% rename from LocalEndpoint/ConnectionManager.cs rename to LocalEndpoint/AuthService.cs index 427814e..47ca4fb 100644 --- a/LocalEndpoint/ConnectionManager.cs +++ b/LocalEndpoint/AuthService.cs @@ -5,28 +5,33 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using LocalEndpoint.Data; +using System.Security.Cryptography; namespace LocalEndpoint { - internal class ConnectionManager : IAccountManager + internal class AuthService : IAuthService { - private Account userAccount = Constants.MAIN_USER_ACCOUNT; - private string userPassword = Constants.MAIN_USER_PASSWORD; - public Account? Login(string email, string password) + private readonly Database db; + + + public AuthService(Database db) { - if (Constants.MAIN_USER_ACCOUNT.Email == email && Constants.MAIN_USER_PASSWORD == password) - return Constants.MAIN_USER_ACCOUNT; - return null; + this.db = db; } + public Account? Login(string email, string password) + { + return db.GetAccount(email, password); + } public Account? Register(string email, string username, string password) { if (email == null || username == null || password == null) return null; - userAccount = new Account(new User(Constants.DEFAULT_ACCOUNT_IMAGE, username), email); - userPassword = password; + var userAccount = new Account(new User(Constants.DEFAULT_ACCOUNT_IMAGE, username, Guid.NewGuid()), email); + db.InsertAccount(userAccount, password); return userAccount; } } diff --git a/LocalEndpoint/Constants.cs b/LocalEndpoint/Constants.cs index 249a016..75f80d1 100644 --- a/LocalEndpoint/Constants.cs +++ b/LocalEndpoint/Constants.cs @@ -4,17 +4,6 @@ namespace LocalEndpoint { internal class Constants { - public static readonly Uri DEFAULT_ACCOUNT_IMAGE = new Uri("https://www.pngkey.com/png/full/115-1150152_default-profile-picture-avatar-png-green.png"); - - // User account for tests - public static readonly Account MAIN_USER_ACCOUNT = new Account(new User(DEFAULT_ACCOUNT_IMAGE, "Example Account"), "test@example.com"); - public static readonly string MAIN_USER_PASSWORD = "123456"; - - // other user samples - public static readonly User USER1 = new User(new Uri("https://i.ibb.co/L6t6bGR/DALL-E-2023-05-10-20-27-31-cook-looking-at-the-camera-with-a-chef-s-hat-laughing-in-an-exaggerated-w.png"), "The Funny Chief"); - public static readonly User USER2 = new User(DEFAULT_ACCOUNT_IMAGE, "Yanis"); - public static readonly User USER3 = new User(DEFAULT_ACCOUNT_IMAGE, "Leo"); - } } diff --git a/LocalEndpoint/Data/AccountData.cs b/LocalEndpoint/Data/AccountData.cs new file mode 100644 index 0000000..332c7e9 --- /dev/null +++ b/LocalEndpoint/Data/AccountData.cs @@ -0,0 +1,17 @@ +using Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace LocalEndpoint.Data +{ + [DataContract] + internal record AccountData( + [property: DataMember] Guid UserId, + [property: DataMember] string Email, + [property: DataMember] string PasswordHash + ); +} diff --git a/LocalEndpoint/Data/CatastrophicPerformancesDatabase.cs b/LocalEndpoint/Data/CatastrophicPerformancesDatabase.cs new file mode 100644 index 0000000..136b2ab --- /dev/null +++ b/LocalEndpoint/Data/CatastrophicPerformancesDatabase.cs @@ -0,0 +1,143 @@ +using Models; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; + +namespace LocalEndpoint.Data +{ + /// + /// Database implementation with catastrophic performances. + /// This database implementation persists data in xml and will save all the data in their files on each mutable requests. + /// + internal class CatastrophicPerformancesDatabase : Database + { + + private static readonly DataContractSerializer RECIPES_SERIALIZER = new DataContractSerializer(typeof(Dictionary)); + private static readonly DataContractSerializer USERS_SERIALIZER = new DataContractSerializer(typeof(Dictionary)); + private static readonly DataContractSerializer ACCOUNTS_SERIALIZER = new DataContractSerializer(typeof(Dictionary)); + + private static readonly string RECIPES_FILENAME = "recipes_data.xml"; + private static readonly string USERS_FILENAME = "users_data.xml"; + private static readonly string ACCOUNTS_FILENAME = "accounts_data.xml"; + + private readonly Dictionary recipesData; + private readonly Dictionary usersData; + private readonly Dictionary accountsData; + + private readonly string dbPath; + + + public CatastrophicPerformancesDatabase(string folderPath) + { + dbPath = folderPath; + if (!Directory.Exists(folderPath)) + Directory.CreateDirectory(folderPath); + + usersData = Load(USERS_FILENAME, USERS_SERIALIZER); + recipesData = Load(RECIPES_FILENAME, RECIPES_SERIALIZER); + accountsData = Load(ACCOUNTS_FILENAME, ACCOUNTS_SERIALIZER); + } + + public bool IsEmpty() + { + return recipesData.Count == 0 && usersData.Count == 0 && accountsData.Count == 0; + } + + public Account? GetAccount(string email, string passwordHash) + { + if (!accountsData.TryGetValue(email, out AccountData? data)) + return null; + + if (data.PasswordHash != passwordHash) return null; + return new Account(usersData[data.UserId].User, data.Email); + } + + public void InsertAccount(Account account, string passwordHash) + { + accountsData[account.Email] = new AccountData(account.User.Id, account.Email, passwordHash); + Save(ACCOUNTS_FILENAME, ACCOUNTS_SERIALIZER, accountsData); + } + + public Recipe GetRecipe(Guid id) + { + return ConvertRecipeDataToRecipe(recipesData[id]); + } + + public RecipeRate GetRecipeRate(Guid user, Guid recipe) + { + return usersData[user].Rates[recipe]; + } + + + public void InsertRecipe(Recipe recipe) + { + recipesData[recipe.Info.Id] = new RecipeData(recipe.Info, recipe.Owner.Id, recipe.Ingredients, recipe.Steps); + Save(RECIPES_FILENAME, RECIPES_SERIALIZER, recipesData); + } + + public void InsertUser(User user) + { + usersData[user.Id] = new UserData(user, new Dictionary()); + Save(USERS_FILENAME, USERS_SERIALIZER, usersData); + } + + public void InsertRate(Guid userId, Guid recipeId, RecipeRate rate) + { + usersData[userId].Rates[recipeId] = rate; + Save(USERS_FILENAME, USERS_SERIALIZER, usersData); + } + + public void RemoveRecipe(Guid id) + { + recipesData.Remove(id); + Save(RECIPES_FILENAME, RECIPES_SERIALIZER, recipesData); + } + + public ImmutableList ListAllRecipes() + { + return recipesData.Values.ToImmutableList().ConvertAll(ConvertRecipeDataToRecipe); + } + + + public ImmutableDictionary ListRatesOf(Guid user) + { + return usersData[user].Rates.ToImmutableDictionary(); + } + + private Recipe ConvertRecipeDataToRecipe(RecipeData rd) + { + var owner = usersData[rd.OwnerID].User; + return new Recipe(rd.Info, owner, rd.Ingredients, rd.Steps); + } + + private Dictionary Load(string fileName, DataContractSerializer deserializer) + { + var file = dbPath + "/" + fileName; + var fileInfo = new FileInfo(file); + + if (!fileInfo.Exists) + fileInfo.Create(); + + if (fileInfo.Length == 0) + return new Dictionary(); //file is empty thus there is nothing to deserialize + Console.WriteLine(File.ReadAllText(file)); + + using (var stream = File.OpenRead(file)) + return deserializer.ReadObject(stream) as Dictionary ?? throw new Exception("object read from " + file + " is not a dictionnary"); + } + + private void Save(string fileName, DataContractSerializer serializer, Dictionary dict) + { + using (var stream = File.OpenWrite(dbPath + "/" + fileName)) + { + serializer.WriteObject(stream, dict); + stream.Flush(); + } + } + + } +} diff --git a/LocalEndpoint/Data/Database.cs b/LocalEndpoint/Data/Database.cs new file mode 100644 index 0000000..b27004a --- /dev/null +++ b/LocalEndpoint/Data/Database.cs @@ -0,0 +1,32 @@ + +using Models; +using System.Collections.Immutable; + +namespace LocalEndpoint.Data +{ + + // The database interface defines all the different kinds of requests the LocalEndpoint needs to store and retrieve data. + public interface Database + { + + public Recipe GetRecipe(Guid id); + + public RecipeRate GetRecipeRate(Guid user, Guid recipe); + + public Account? GetAccount(string email, string passwordHash); + + public void InsertAccount(Account account, string passwordHash); + + public void InsertRecipe(Recipe recipe); + + public void InsertUser(User user); + + public void InsertRate(Guid userId, Guid recipeId, RecipeRate rate); + + public void RemoveRecipe(Guid id); + + public ImmutableList ListAllRecipes(); + + public ImmutableDictionary ListRatesOf(Guid user); + } +} diff --git a/LocalEndpoint/Data/RecipeData.cs b/LocalEndpoint/Data/RecipeData.cs new file mode 100644 index 0000000..431f9b6 --- /dev/null +++ b/LocalEndpoint/Data/RecipeData.cs @@ -0,0 +1,14 @@ +using Models; +using System.Collections.Immutable; +using System.Runtime.Serialization; + +namespace LocalEndpoint.Data +{ + [DataContract] + internal record RecipeData( + [property: DataMember] RecipeInfo Info, + [property: DataMember] Guid OwnerID, + [property: DataMember] ImmutableList Ingredients, + [property: DataMember] ImmutableList Steps + ); +} \ No newline at end of file diff --git a/LocalEndpoint/Data/UserData.cs b/LocalEndpoint/Data/UserData.cs new file mode 100644 index 0000000..bad1f5e --- /dev/null +++ b/LocalEndpoint/Data/UserData.cs @@ -0,0 +1,13 @@ + + +using Models; +using System.Runtime.Serialization; + +namespace LocalEndpoint.Data +{ + [DataContract] + internal record UserData( + [property: DataMember] User User, + [property: DataMember] Dictionary Rates + ); +} diff --git a/LocalEndpoint/LocalEndpoint.cs b/LocalEndpoint/LocalEndpoint.cs index 666a9de..ca4875b 100644 --- a/LocalEndpoint/LocalEndpoint.cs +++ b/LocalEndpoint/LocalEndpoint.cs @@ -1,4 +1,5 @@ using Endpoint; +using LocalEndpoint.Data; using Models; using System.Collections.Immutable; @@ -11,28 +12,54 @@ namespace LocalEndpoint /// public class LocalEndpoint : IEndpoint { - private readonly IAccountManager accountManager = new ConnectionManager(); + private readonly IAuthService authService; private readonly IRecipesService recipesService; public LocalEndpoint() { - RecipesDatabase db = new RecipesDatabase(Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "/recipes.xaml"); - - //miam - /*db.Insert(new Recipe(new RecipeInfo("Chicken Salad", 500, 20, new Uri("https://healthyfitnessmeals.com/wp-content/uploads/2021/04/Southwest-chicken-salad-7-500x500.jpg"), 4, Guid.NewGuid()), Constants.USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.Insert(new Recipe(new RecipeInfo("Chocolate Cake", 2500, 10, new Uri("https://bakewithshivesh.com/wp-content/uploads/2022/08/IMG_0248-scaled.jpg"), 3, Guid.NewGuid()), Constants.USER2, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.Insert(new Recipe(new RecipeInfo("Salmon", 20, 10, new Uri("https://www.wholesomeyum.com/wp-content/uploads/2021/06/wholesomeyum-Pan-Seared-Salmon-Recipe-13.jpg"), 4, Guid.NewGuid()), Constants.MAIN_USER_ACCOUNT.User, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.Insert(new Recipe(new RecipeInfo("Fish", 50, 30, new Uri("https://www.ciaanet.org/wp-content/uploads/2022/07/Atlantic-and-Pacific-whole-salmon-1024x683.jpg"), 4.5F, Guid.NewGuid()), Constants.MAIN_USER_ACCOUNT.User, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.Insert(new Recipe(new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()), Constants.USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.Insert(new Recipe(new RecipeInfo("Cupcake", 500, 12, new Uri("https://www.mycake.fr/wp-content/uploads/2015/12/rs_cupcake_4x3.jpg"), 4.2F, Guid.NewGuid()), account.User, new List { new Ingredient("Chocolate", 4) }.ToImmutableList(), new List { new PreparationStep("Eat Chocolate", "Eat the chocolate") }.ToImmutableList())); - */ + var db = new CatastrophicPerformancesDatabase(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); + + if (db.IsEmpty()) + PrepareDatabase(db); + recipesService = new RecipesService(db); + authService = new AuthService(db); } - public IAccountManager AccountManager => accountManager; + public IAuthService AccountManager => authService; public IRecipesService RecipesService => recipesService; + private static void PrepareDatabase(Database db) + { + User USER1 = new User(new Uri("https://i.ibb.co/L6t6bGR/DALL-E-2023-05-10-20-27-31-cook-looking-at-the-camera-with-a-chef-s-hat-laughing-in-an-exaggerated-w.png"), "The Funny Chief", MakeGuid(1)); + User USER2 = new User(Constants.DEFAULT_ACCOUNT_IMAGE, "Yanis", MakeGuid(2)); + User USER3 = new User(Constants.DEFAULT_ACCOUNT_IMAGE, "Leo", MakeGuid(3)); + + db.InsertUser(USER1); + db.InsertUser(USER2); + db.InsertUser(USER3); + + db.InsertAccount(new Account(USER1, "chief@cook.com"), "123456"); + db.InsertAccount(new Account(USER2, "yanis@google.com"), "123456"); + db.InsertAccount(new Account(USER3, "leo@google.com"), "123456"); + + db.InsertRecipe(new Recipe(new RecipeInfo("Chicken Salad", 500, 20, new Uri("https://healthyfitnessmeals.com/wp-content/uploads/2021/04/Southwest-chicken-salad-7-500x500.jpg"), 4, Guid.NewGuid()), USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Chocolate Cake", 2500, 10, new Uri("https://bakewithshivesh.com/wp-content/uploads/2022/08/IMG_0248-scaled.jpg"), 3, Guid.NewGuid()), USER2, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Salmon", 20, 10, new Uri("https://www.wholesomeyum.com/wp-content/uploads/2021/06/wholesomeyum-Pan-Seared-Salmon-Recipe-13.jpg"), 4, Guid.NewGuid()), USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Fish", 50, 30, new Uri("https://www.ciaanet.org/wp-content/uploads/2022/07/Atlantic-and-Pacific-whole-salmon-1024x683.jpg"), 4.5F, Guid.NewGuid()), USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()), USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Cupcake", 500, 12, new Uri("https://www.mycake.fr/wp-content/uploads/2015/12/rs_cupcake_4x3.jpg"), 4.2F, Guid.NewGuid()), USER1, new List { new Ingredient("Chocolate", 4) }.ToImmutableList(), new List { new PreparationStep("Eat Chocolate", "Eat the chocolate") }.ToImmutableList())); + } + + private static Guid MakeGuid(int seed) + { + var r = new Random(seed); + var guid = new byte[16]; + r.NextBytes(guid); + + return new Guid(guid); + } } } \ No newline at end of file diff --git a/LocalEndpoint/RecipesDatabase.cs b/LocalEndpoint/RecipesDatabase.cs deleted file mode 100644 index 70aba26..0000000 --- a/LocalEndpoint/RecipesDatabase.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Models; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Runtime.Serialization; - -namespace LocalEndpoint -{ - - internal class RecipesDatabase - { - - private static readonly DataContractSerializer RECIPES_SERIALIZER = new DataContractSerializer(typeof(List)); - - private readonly Dictionary recipes = new Dictionary(); - private readonly string dbPath; - - public RecipesDatabase(string path) - { - dbPath = path; - - - if (!File.Exists(dbPath)) - { - File.Create(dbPath); - } - if (new FileInfo(dbPath).Length == 0) - return; //file is empty thus there is nothing to deserialize - Console.WriteLine(File.ReadAllText(dbPath)); - - using (var stream = File.OpenRead(dbPath)) { - var recipes = RECIPES_SERIALIZER.ReadObject(stream) as List; - recipes.ForEach(recipe => this.recipes.Add(recipe.Info.Id, recipe)); - } - } - - private void SaveAll() - { - using (var stream = File.OpenWrite(dbPath)) - { - RECIPES_SERIALIZER.WriteObject(stream, recipes.Values.ToList()); - } - } - - public Recipe? Lookup(Guid id) - { - Recipe? recipe; - recipes.TryGetValue(id, out recipe); - return recipe; - } - - - public Recipe Get(Guid id) - { - return recipes[id]; - } - - public void Insert(Recipe recipe) - { - recipes[recipe.Info.Id] = recipe; - SaveAll(); - } - - public void Remove(Guid id) - { - recipes.Remove(id); - SaveAll(); - } - - public ImmutableList ListAll() - { - return recipes.Values.ToImmutableList(); - } - - } -} diff --git a/LocalEndpoint/RecipesService.cs b/LocalEndpoint/RecipesService.cs index e8df0c7..8969e9e 100644 --- a/LocalEndpoint/RecipesService.cs +++ b/LocalEndpoint/RecipesService.cs @@ -1,4 +1,5 @@ using Endpoint; +using LocalEndpoint.Data; using Models; using System.Collections.Immutable; @@ -7,22 +8,22 @@ namespace LocalEndpoint internal class RecipesService : IRecipesService { - private readonly RecipesDatabase db; - private readonly Dictionary accountsData = new Dictionary(); + private readonly Database db; + private readonly Dictionary accountsData = new Dictionary(); - public RecipesService(RecipesDatabase db) + public RecipesService(Database db) { this.db = db; } public ImmutableList PopularRecipes() { - return db.ListAll().Take(4).ToImmutableList().ConvertAll(v => v.Info); + return db.ListAllRecipes().Take(4).ToImmutableList().ConvertAll(v => v.Info); } public Recipe GetRecipe(RecipeInfo info) { - return db.Get(info.Id); + return db.GetRecipe(info.Id); } @@ -35,16 +36,16 @@ namespace LocalEndpoint return GetOrInitData(account).Preferences; } - private AccountData GetOrInitData(Account account) + private AccountServices GetOrInitData(Account account) { - AccountData? data; + AccountServices? data; accountsData.TryGetValue(account, out data); if (data == null) { AccountOwnedRecipes recipes = new AccountOwnedRecipes(account, db); AccountRecipesPreferences preferences = new AccountRecipesPreferences(account, db); - data = new AccountData(recipes, preferences); + data = new AccountServices(recipes, preferences); accountsData.Add(account, data); } return data; diff --git a/Models/AccountRecipeRate.cs b/Models/AccountRecipeRate.cs deleted file mode 100644 index caf7658..0000000 --- a/Models/AccountRecipeRate.cs +++ /dev/null @@ -1,5 +0,0 @@ - -namespace Models -{ - public record AccountRecipeRate(bool IsFavorite = false, uint Rate = 0); -} diff --git a/Models/Ingredient.cs b/Models/Ingredient.cs index 7caaa9d..10e7655 100644 --- a/Models/Ingredient.cs +++ b/Models/Ingredient.cs @@ -2,18 +2,8 @@ namespace Models { - [DataContract] - public class Ingredient - { - [DataMember] - public string Name { get; init; } - [DataMember] - public float Amount { get; init; } - public Ingredient(string name, float amount) - { - Name = name; - Amount = amount; - } - } + + [DataContract] + public record Ingredient([property: DataMember] string Name, [property: DataMember] float Amount); } diff --git a/Models/PreparationStep.cs b/Models/PreparationStep.cs index 779f797..35e4734 100644 --- a/Models/PreparationStep.cs +++ b/Models/PreparationStep.cs @@ -3,17 +3,5 @@ namespace Models { [DataContract] - public record PreparationStep - { - [DataMember] - public string Name { get; init; } - [DataMember] - public string Description { get; init; } - - public PreparationStep(string name, string description) - { - Name = name; - Description = description; - } - } + public record PreparationStep([property: DataMember] string Name, [property: DataMember] string Description); } diff --git a/Models/Recipe.cs b/Models/Recipe.cs index f6152bf..021d99a 100644 --- a/Models/Recipe.cs +++ b/Models/Recipe.cs @@ -4,23 +4,11 @@ using System.Runtime.Serialization; namespace Models { [DataContract] - public class Recipe - { - [DataMember] - public RecipeInfo Info { get; init; } - [DataMember] - public User Owner { get; init; } - [DataMember] - public ImmutableList Ingredients { get; init; } - [DataMember] - public ImmutableList Steps { get; init; } + public record Recipe( + [property: DataMember] RecipeInfo Info, + [property: DataMember] User Owner, + [property: DataMember] ImmutableList Ingredients, + [property: DataMember] ImmutableList Steps + ); - public Recipe(RecipeInfo info, User owner, ImmutableList ingredients, ImmutableList steps) - { - Info = info; - Owner = owner; - Ingredients = ingredients; - Steps = steps; - } - } } \ No newline at end of file diff --git a/Models/RecipeInfo.cs b/Models/RecipeInfo.cs index 2dfbbcc..fec0ebb 100644 --- a/Models/RecipeInfo.cs +++ b/Models/RecipeInfo.cs @@ -3,29 +3,12 @@ namespace Models { [DataContract] - public class RecipeInfo - { - [DataMember] - public string Name { get; init; } - [DataMember] - public uint CalPerPers { get; init; } - [DataMember] - public uint CookTimeMins { get; init; } - [DataMember] - public Uri? Image { get; init; } - [DataMember] - public float AverageNote { get; init; } - [DataMember] - public Guid Id { get; init; } - - public RecipeInfo(string name, uint calPerPers, uint cookTimeMins, Uri? image, float averageNote, Guid id) - { - Name = name; - CalPerPers = calPerPers; - CookTimeMins = cookTimeMins; - Image = image; - AverageNote = averageNote; - Id = id; - } - } + public record RecipeInfo( + [property: DataMember] string Name, + [property: DataMember] uint CalPerPers, + [property: DataMember] uint CookTimeMins, + [property: DataMember] Uri? Image, + [property: DataMember] float AverageNote, + [property: DataMember] Guid Id + ); } diff --git a/Models/RecipeRate.cs b/Models/RecipeRate.cs new file mode 100644 index 0000000..b4dc3a3 --- /dev/null +++ b/Models/RecipeRate.cs @@ -0,0 +1,11 @@ + +using System.Runtime.Serialization; + +namespace Models +{ + [DataContract] + public record RecipeRate( + [property: DataMember] bool IsFavorite = false, + [property: DataMember] uint Rate = 0 + ); +} diff --git a/Models/User.cs b/Models/User.cs index 2273a93..21cd678 100644 --- a/Models/User.cs +++ b/Models/User.cs @@ -9,11 +9,23 @@ namespace Models public Uri ProfilePicture { get; init; } [DataMember] public string Name { get; init; } + [DataMember] + public Guid Id { get; init; } - public User(Uri profilePicture, string name) + public User(Uri profilePicture, string name, Guid id) { ProfilePicture = profilePicture; Name = name; + Id = id; + } + + public override bool Equals(object? other) + { + if (this == other) + return true; + + User? otherUser = other as User; + return otherUser != null && Id.Equals(otherUser.Id); } } } diff --git a/Views/Components/RecipeView.xaml b/Views/Components/RecipeView.xaml index 8e794da..7409572 100644 --- a/Views/Components/RecipeView.xaml +++ b/Views/Components/RecipeView.xaml @@ -14,6 +14,7 @@ MinimumHeightRequest="175" MinimumWidthRequest="150" RowDefinitions="*, Auto"> + diff --git a/Views/RecipePage.xaml.cs b/Views/RecipePage.xaml.cs index d40478d..33531f3 100644 --- a/Views/RecipePage.xaml.cs +++ b/Views/RecipePage.xaml.cs @@ -27,7 +27,7 @@ public partial class RecipePage : ContentPage this.notifier = notifier; this.info = recipe.Info; - AccountRecipeRate rate = preferences.GetRate(recipe.Info); + RecipeRate rate = preferences.GetRate(recipe.Info); note = rate.Rate; isFavorite = rate.IsFavorite; @@ -80,6 +80,10 @@ public partial class RecipePage : ContentPage private void OnFavorite(object o, EventArgs e) { SetFavorite(!isFavorite); + if (isFavorite) + preferences.AddToFavorites(info); + else + preferences.RemoveFromFavorites(info); } private void OnSubmitReviewClicked(object o, EventArgs e) @@ -100,19 +104,12 @@ public partial class RecipePage : ContentPage { this.isFavorite = isFavorite; if (isFavorite) - { Favorite.Source = ImageSource.FromFile("hearth_on.svg"); - preferences.AddToFavorites(info); - } else - { Favorite.Source = ImageSource.FromFile("hearth_off.svg"); - preferences.RemoveFromFavorites(info); - } } private void OnBackButtonClicked(object sender, EventArgs e) { - Navigation.PopAsync(); } From a64673ce0ccdf9fea205b619d07adf58c6bfff99 Mon Sep 17 00:00:00 2001 From: "maxime.BATISTA@etu.uca.fr" Date: Sat, 13 May 2023 18:28:54 +0200 Subject: [PATCH 4/6] refactor Endpoint and LocalEndpoint assemblies to Services and LocalServices --- Endpoint/Endpoint.csproj | 13 -- LocalEndpoint/LocalEndpoint.csproj | 14 -- .../AccountOwnedRecipes.cs | 0 .../AccountRecipesPreferences.cs | 0 .../AccountServices.cs | 0 .../AuthService.cs | 0 {LocalEndpoint => LocalServices}/Constants.cs | 0 .../Data/AccountData.cs | 0 .../Data/CatastrophicPerformancesDatabase.cs | 0 .../Data/Database.cs | 0 .../Data/RecipeData.cs | 0 .../Data/UserData.cs | 0 .../LocalEndpoint.cs | 128 +++++++++--------- .../LocalServices.csproj | 2 +- .../RecipesService.cs | 0 Models/User.cs | 5 + .../IAccountOwnedRecipes.cs | 0 .../IAccountRecipesPreferences.cs | 0 {Endpoint => Services}/IAuthService.cs | 0 {Endpoint => Services}/IEndpoint.cs | 0 {Endpoint => Services}/IRecipesService.cs | 0 {Endpoint => Services}/Services.csproj | 26 ++-- ShoopNCook.csproj | 24 ++-- ShoopNCook.sln | 4 +- 24 files changed, 97 insertions(+), 119 deletions(-) delete mode 100644 Endpoint/Endpoint.csproj delete mode 100644 LocalEndpoint/LocalEndpoint.csproj rename {LocalEndpoint => LocalServices}/AccountOwnedRecipes.cs (100%) rename {LocalEndpoint => LocalServices}/AccountRecipesPreferences.cs (100%) rename {LocalEndpoint => LocalServices}/AccountServices.cs (100%) rename {LocalEndpoint => LocalServices}/AuthService.cs (100%) rename {LocalEndpoint => LocalServices}/Constants.cs (100%) rename {LocalEndpoint => LocalServices}/Data/AccountData.cs (100%) rename {LocalEndpoint => LocalServices}/Data/CatastrophicPerformancesDatabase.cs (100%) rename {LocalEndpoint => LocalServices}/Data/Database.cs (100%) rename {LocalEndpoint => LocalServices}/Data/RecipeData.cs (100%) rename {LocalEndpoint => LocalServices}/Data/UserData.cs (100%) rename {LocalEndpoint => LocalServices}/LocalEndpoint.cs (98%) rename {LocalEndpoint => LocalServices}/LocalServices.csproj (82%) rename {LocalEndpoint => LocalServices}/RecipesService.cs (100%) rename {Endpoint => Services}/IAccountOwnedRecipes.cs (100%) rename {Endpoint => Services}/IAccountRecipesPreferences.cs (100%) rename {Endpoint => Services}/IAuthService.cs (100%) rename {Endpoint => Services}/IEndpoint.cs (100%) rename {Endpoint => Services}/IRecipesService.cs (100%) rename {Endpoint => Services}/Services.csproj (95%) diff --git a/Endpoint/Endpoint.csproj b/Endpoint/Endpoint.csproj deleted file mode 100644 index d24baee..0000000 --- a/Endpoint/Endpoint.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - net7.0 - enable - enable - - - - - - - diff --git a/LocalEndpoint/LocalEndpoint.csproj b/LocalEndpoint/LocalEndpoint.csproj deleted file mode 100644 index b84a3cb..0000000 --- a/LocalEndpoint/LocalEndpoint.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - net7.0 - enable - enable - - - - - - - - diff --git a/LocalEndpoint/AccountOwnedRecipes.cs b/LocalServices/AccountOwnedRecipes.cs similarity index 100% rename from LocalEndpoint/AccountOwnedRecipes.cs rename to LocalServices/AccountOwnedRecipes.cs diff --git a/LocalEndpoint/AccountRecipesPreferences.cs b/LocalServices/AccountRecipesPreferences.cs similarity index 100% rename from LocalEndpoint/AccountRecipesPreferences.cs rename to LocalServices/AccountRecipesPreferences.cs diff --git a/LocalEndpoint/AccountServices.cs b/LocalServices/AccountServices.cs similarity index 100% rename from LocalEndpoint/AccountServices.cs rename to LocalServices/AccountServices.cs diff --git a/LocalEndpoint/AuthService.cs b/LocalServices/AuthService.cs similarity index 100% rename from LocalEndpoint/AuthService.cs rename to LocalServices/AuthService.cs diff --git a/LocalEndpoint/Constants.cs b/LocalServices/Constants.cs similarity index 100% rename from LocalEndpoint/Constants.cs rename to LocalServices/Constants.cs diff --git a/LocalEndpoint/Data/AccountData.cs b/LocalServices/Data/AccountData.cs similarity index 100% rename from LocalEndpoint/Data/AccountData.cs rename to LocalServices/Data/AccountData.cs diff --git a/LocalEndpoint/Data/CatastrophicPerformancesDatabase.cs b/LocalServices/Data/CatastrophicPerformancesDatabase.cs similarity index 100% rename from LocalEndpoint/Data/CatastrophicPerformancesDatabase.cs rename to LocalServices/Data/CatastrophicPerformancesDatabase.cs diff --git a/LocalEndpoint/Data/Database.cs b/LocalServices/Data/Database.cs similarity index 100% rename from LocalEndpoint/Data/Database.cs rename to LocalServices/Data/Database.cs diff --git a/LocalEndpoint/Data/RecipeData.cs b/LocalServices/Data/RecipeData.cs similarity index 100% rename from LocalEndpoint/Data/RecipeData.cs rename to LocalServices/Data/RecipeData.cs diff --git a/LocalEndpoint/Data/UserData.cs b/LocalServices/Data/UserData.cs similarity index 100% rename from LocalEndpoint/Data/UserData.cs rename to LocalServices/Data/UserData.cs diff --git a/LocalEndpoint/LocalEndpoint.cs b/LocalServices/LocalEndpoint.cs similarity index 98% rename from LocalEndpoint/LocalEndpoint.cs rename to LocalServices/LocalEndpoint.cs index ca4875b..d2d71d3 100644 --- a/LocalEndpoint/LocalEndpoint.cs +++ b/LocalServices/LocalEndpoint.cs @@ -1,65 +1,65 @@ -using Endpoint; -using LocalEndpoint.Data; -using Models; -using System.Collections.Immutable; - -namespace LocalEndpoint -{ - - /// - /// The local endpoint is an implementation of the Endpoint API definition. - /// - /// - public class LocalEndpoint : IEndpoint - { - private readonly IAuthService authService; - private readonly IRecipesService recipesService; - - - public LocalEndpoint() - { - var db = new CatastrophicPerformancesDatabase(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); - - if (db.IsEmpty()) - PrepareDatabase(db); - - recipesService = new RecipesService(db); - authService = new AuthService(db); - } - - public IAuthService AccountManager => authService; - - public IRecipesService RecipesService => recipesService; - - private static void PrepareDatabase(Database db) - { - User USER1 = new User(new Uri("https://i.ibb.co/L6t6bGR/DALL-E-2023-05-10-20-27-31-cook-looking-at-the-camera-with-a-chef-s-hat-laughing-in-an-exaggerated-w.png"), "The Funny Chief", MakeGuid(1)); - User USER2 = new User(Constants.DEFAULT_ACCOUNT_IMAGE, "Yanis", MakeGuid(2)); - User USER3 = new User(Constants.DEFAULT_ACCOUNT_IMAGE, "Leo", MakeGuid(3)); - - db.InsertUser(USER1); - db.InsertUser(USER2); - db.InsertUser(USER3); - - db.InsertAccount(new Account(USER1, "chief@cook.com"), "123456"); - db.InsertAccount(new Account(USER2, "yanis@google.com"), "123456"); - db.InsertAccount(new Account(USER3, "leo@google.com"), "123456"); - - db.InsertRecipe(new Recipe(new RecipeInfo("Chicken Salad", 500, 20, new Uri("https://healthyfitnessmeals.com/wp-content/uploads/2021/04/Southwest-chicken-salad-7-500x500.jpg"), 4, Guid.NewGuid()), USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.InsertRecipe(new Recipe(new RecipeInfo("Chocolate Cake", 2500, 10, new Uri("https://bakewithshivesh.com/wp-content/uploads/2022/08/IMG_0248-scaled.jpg"), 3, Guid.NewGuid()), USER2, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.InsertRecipe(new Recipe(new RecipeInfo("Salmon", 20, 10, new Uri("https://www.wholesomeyum.com/wp-content/uploads/2021/06/wholesomeyum-Pan-Seared-Salmon-Recipe-13.jpg"), 4, Guid.NewGuid()), USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.InsertRecipe(new Recipe(new RecipeInfo("Fish", 50, 30, new Uri("https://www.ciaanet.org/wp-content/uploads/2022/07/Atlantic-and-Pacific-whole-salmon-1024x683.jpg"), 4.5F, Guid.NewGuid()), USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.InsertRecipe(new Recipe(new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()), USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); - db.InsertRecipe(new Recipe(new RecipeInfo("Cupcake", 500, 12, new Uri("https://www.mycake.fr/wp-content/uploads/2015/12/rs_cupcake_4x3.jpg"), 4.2F, Guid.NewGuid()), USER1, new List { new Ingredient("Chocolate", 4) }.ToImmutableList(), new List { new PreparationStep("Eat Chocolate", "Eat the chocolate") }.ToImmutableList())); - } - - private static Guid MakeGuid(int seed) - { - var r = new Random(seed); - var guid = new byte[16]; - r.NextBytes(guid); - - return new Guid(guid); - } - } +using Endpoint; +using LocalEndpoint.Data; +using Models; +using System.Collections.Immutable; + +namespace LocalEndpoint +{ + + /// + /// The local endpoint is an implementation of the Endpoint API definition. + /// + /// + public class LocalEndpoint : IEndpoint + { + private readonly IAuthService authService; + private readonly IRecipesService recipesService; + + + public LocalEndpoint() + { + var db = new CatastrophicPerformancesDatabase(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); + + if (db.IsEmpty()) + PrepareDatabase(db); + + recipesService = new RecipesService(db); + authService = new AuthService(db); + } + + public IAuthService AccountManager => authService; + + public IRecipesService RecipesService => recipesService; + + private static void PrepareDatabase(Database db) + { + User USER1 = new User(new Uri("https://i.ibb.co/L6t6bGR/DALL-E-2023-05-10-20-27-31-cook-looking-at-the-camera-with-a-chef-s-hat-laughing-in-an-exaggerated-w.png"), "The Funny Chief", MakeGuid(1)); + User USER2 = new User(Constants.DEFAULT_ACCOUNT_IMAGE, "Yanis", MakeGuid(2)); + User USER3 = new User(Constants.DEFAULT_ACCOUNT_IMAGE, "Leo", MakeGuid(3)); + + db.InsertUser(USER1); + db.InsertUser(USER2); + db.InsertUser(USER3); + + db.InsertAccount(new Account(USER1, "chief@cook.com"), "123456"); + db.InsertAccount(new Account(USER2, "yanis@google.com"), "123456"); + db.InsertAccount(new Account(USER3, "leo@google.com"), "123456"); + + db.InsertRecipe(new Recipe(new RecipeInfo("Chicken Salad", 500, 20, new Uri("https://healthyfitnessmeals.com/wp-content/uploads/2021/04/Southwest-chicken-salad-7-500x500.jpg"), 4, Guid.NewGuid()), USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Chocolate Cake", 2500, 10, new Uri("https://bakewithshivesh.com/wp-content/uploads/2022/08/IMG_0248-scaled.jpg"), 3, Guid.NewGuid()), USER2, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Salmon", 20, 10, new Uri("https://www.wholesomeyum.com/wp-content/uploads/2021/06/wholesomeyum-Pan-Seared-Salmon-Recipe-13.jpg"), 4, Guid.NewGuid()), USER1, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Fish", 50, 30, new Uri("https://www.ciaanet.org/wp-content/uploads/2022/07/Atlantic-and-Pacific-whole-salmon-1024x683.jpg"), 4.5F, Guid.NewGuid()), USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Space Cake", 800, 5, new Uri("https://static.youmiam.com/images/recipe/1500x1000/space-cake-22706?placeholder=web_recipe&sig=f14a7a86da837c6b8cc678cde424d6d5902f99ec&v3"), 5, Guid.NewGuid()), USER3, new List { new Ingredient("Ingredient 1", 6) }.ToImmutableList(), new List { new PreparationStep("Step 1", "Bake the eggs") }.ToImmutableList())); + db.InsertRecipe(new Recipe(new RecipeInfo("Cupcake", 500, 12, new Uri("https://www.mycake.fr/wp-content/uploads/2015/12/rs_cupcake_4x3.jpg"), 4.2F, Guid.NewGuid()), USER1, new List { new Ingredient("Chocolate", 4) }.ToImmutableList(), new List { new PreparationStep("Eat Chocolate", "Eat the chocolate") }.ToImmutableList())); + } + + private static Guid MakeGuid(int seed) + { + var r = new Random(seed); + var guid = new byte[16]; + r.NextBytes(guid); + + return new Guid(guid); + } + } } \ No newline at end of file diff --git a/LocalEndpoint/LocalServices.csproj b/LocalServices/LocalServices.csproj similarity index 82% rename from LocalEndpoint/LocalServices.csproj rename to LocalServices/LocalServices.csproj index 29b3db6..62f7504 100644 --- a/LocalEndpoint/LocalServices.csproj +++ b/LocalServices/LocalServices.csproj @@ -7,7 +7,7 @@ - + diff --git a/LocalEndpoint/RecipesService.cs b/LocalServices/RecipesService.cs similarity index 100% rename from LocalEndpoint/RecipesService.cs rename to LocalServices/RecipesService.cs diff --git a/Models/User.cs b/Models/User.cs index 21cd678..b70f7b1 100644 --- a/Models/User.cs +++ b/Models/User.cs @@ -27,5 +27,10 @@ namespace Models User? otherUser = other as User; return otherUser != null && Id.Equals(otherUser.Id); } + + override public int GetHashCode() + { + return Id.GetHashCode(); + } } } diff --git a/Endpoint/IAccountOwnedRecipes.cs b/Services/IAccountOwnedRecipes.cs similarity index 100% rename from Endpoint/IAccountOwnedRecipes.cs rename to Services/IAccountOwnedRecipes.cs diff --git a/Endpoint/IAccountRecipesPreferences.cs b/Services/IAccountRecipesPreferences.cs similarity index 100% rename from Endpoint/IAccountRecipesPreferences.cs rename to Services/IAccountRecipesPreferences.cs diff --git a/Endpoint/IAuthService.cs b/Services/IAuthService.cs similarity index 100% rename from Endpoint/IAuthService.cs rename to Services/IAuthService.cs diff --git a/Endpoint/IEndpoint.cs b/Services/IEndpoint.cs similarity index 100% rename from Endpoint/IEndpoint.cs rename to Services/IEndpoint.cs diff --git a/Endpoint/IRecipesService.cs b/Services/IRecipesService.cs similarity index 100% rename from Endpoint/IRecipesService.cs rename to Services/IRecipesService.cs diff --git a/Endpoint/Services.csproj b/Services/Services.csproj similarity index 95% rename from Endpoint/Services.csproj rename to Services/Services.csproj index d24baee..e45d1d7 100644 --- a/Endpoint/Services.csproj +++ b/Services/Services.csproj @@ -1,13 +1,13 @@ - - - - net7.0 - enable - enable - - - - - - - + + + + net7.0 + enable + enable + + + + + + + diff --git a/ShoopNCook.csproj b/ShoopNCook.csproj index 063bc5b..8a80861 100644 --- a/ShoopNCook.csproj +++ b/ShoopNCook.csproj @@ -48,28 +48,28 @@ - - + + - - + + - - + + - - + + - - + + @@ -118,8 +118,8 @@ - - + + diff --git a/ShoopNCook.sln b/ShoopNCook.sln index 6ca3619..3b6c720 100644 --- a/ShoopNCook.sln +++ b/ShoopNCook.sln @@ -8,9 +8,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Models", "Models\Models.csproj", "{A9D43E07-345D-4DD4-B4F9-CE69ED569B5F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LocalEndpoint", "LocalEndpoint\LocalEndpoint.csproj", "{57732316-93B9-4DA0-A212-F8892D3D968B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LocalServices", "LocalServices\LocalServices.csproj", "{57732316-93B9-4DA0-A212-F8892D3D968B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Endpoint", "Endpoint\Endpoint.csproj", "{C976BDD8-710D-4162-8A42-973B634491F9}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Services\Services.csproj", "{C976BDD8-710D-4162-8A42-973B634491F9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From d2023616f45f0a091de60d3efdd6bafcc6030edd Mon Sep 17 00:00:00 2001 From: "maxime.BATISTA@etu.uca.fr" Date: Sun, 14 May 2023 09:42:31 +0200 Subject: [PATCH 5/6] fix recipes page --- Views/RecipePage.xaml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Views/RecipePage.xaml b/Views/RecipePage.xaml index bca49c4..020dd04 100644 --- a/Views/RecipePage.xaml +++ b/Views/RecipePage.xaml @@ -14,21 +14,20 @@ + RowDefinitions="Auto, Auto, *, Auto"> + AlignItems="Center" + HeightRequest="60"> - @@ -110,7 +108,8 @@ + Grid.Row="3" + MaximumHeightRequest="45"> Date: Sun, 14 May 2023 10:14:58 +0200 Subject: [PATCH 6/6] persist 'MyList' of users --- App.xaml.cs | 2 +- LocalServices/AccountRecipesPreferences.cs | 12 ++++++------ .../Data/CatastrophicPerformancesDatabase.cs | 19 ++++++++++++++++++- LocalServices/Data/Database.cs | 4 ++++ LocalServices/Data/UserData.cs | 3 ++- LocalServices/LocalEndpoint.cs | 2 +- Services/IEndpoint.cs | 2 +- Services/IRecipesService.cs | 5 ----- 8 files changed, 33 insertions(+), 16 deletions(-) diff --git a/App.xaml.cs b/App.xaml.cs index 9c150df..c873ce2 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -25,7 +25,7 @@ public partial class App : Application, ConnectionObserver, IApp public void ForceLogin() { - Shell shell = new ConnectAppShell(this, Endpoint.AccountManager, Notifier); + Shell shell = new ConnectAppShell(this, Endpoint.AuthService, Notifier); shell.GoToAsync("//Splash"); MainPage = shell; } diff --git a/LocalServices/AccountRecipesPreferences.cs b/LocalServices/AccountRecipesPreferences.cs index d260838..a7d848a 100644 --- a/LocalServices/AccountRecipesPreferences.cs +++ b/LocalServices/AccountRecipesPreferences.cs @@ -8,9 +8,6 @@ namespace LocalEndpoint internal class AccountRecipesPreferences : IAccountRecipesPreferences { - //Binds a recipe's id to its amount of person stored in the account's weekly list - private readonly Dictionary weekly = new Dictionary(); - private readonly Database db; public AccountRecipesPreferences(Account account, Database db) { @@ -43,10 +40,12 @@ namespace LocalEndpoint public ImmutableList<(RecipeInfo, uint)> GetWeeklyList() { + var weeklyDict = db.GetRecipeListOf(Account.User.Id); List<(RecipeInfo, uint)> weekly = new List<(RecipeInfo, uint)>(); + foreach (Recipe recipe in db.ListAllRecipes()) { - if (this.weekly.TryGetValue(recipe.Info.Id, out uint personAmmount)) + if (weeklyDict.TryGetValue(recipe.Info.Id, out uint personAmmount)) { weekly.Add((recipe.Info, personAmmount)); } @@ -70,10 +69,11 @@ namespace LocalEndpoint public bool AddToWeeklyList(RecipeInfo info, uint persAmount) { - if (weekly.ContainsKey(info.Id)) + var weeklyDict = db.GetRecipeListOf(Account.User.Id); + if (weeklyDict.ContainsKey(info.Id)) return false; - weekly[info.Id] = persAmount; + db.InsertInUserList(Account.User.Id, info.Id, persAmount); return true; } diff --git a/LocalServices/Data/CatastrophicPerformancesDatabase.cs b/LocalServices/Data/CatastrophicPerformancesDatabase.cs index 136b2ab..32c48c1 100644 --- a/LocalServices/Data/CatastrophicPerformancesDatabase.cs +++ b/LocalServices/Data/CatastrophicPerformancesDatabase.cs @@ -72,6 +72,18 @@ namespace LocalEndpoint.Data return usersData[user].Rates[recipe]; } + public void InsertInUserList(Guid userId, Guid recipeId, uint persAmount) + { + usersData[userId].RecipesList[recipeId] = persAmount; + Save(USERS_FILENAME, USERS_SERIALIZER, usersData); + } + + public void RemoveFromUserList(Guid userId, Guid recipeId) + { + usersData[userId].RecipesList.Remove(recipeId); + Save(USERS_FILENAME, USERS_SERIALIZER, usersData); + } + public void InsertRecipe(Recipe recipe) { @@ -81,7 +93,7 @@ namespace LocalEndpoint.Data public void InsertUser(User user) { - usersData[user.Id] = new UserData(user, new Dictionary()); + usersData[user.Id] = new UserData(user, new Dictionary(), new Dictionary()); Save(USERS_FILENAME, USERS_SERIALIZER, usersData); } @@ -108,6 +120,11 @@ namespace LocalEndpoint.Data return usersData[user].Rates.ToImmutableDictionary(); } + public ImmutableDictionary GetRecipeListOf(Guid user) + { + return usersData[user].RecipesList.ToImmutableDictionary(); + } + private Recipe ConvertRecipeDataToRecipe(RecipeData rd) { var owner = usersData[rd.OwnerID].User; diff --git a/LocalServices/Data/Database.cs b/LocalServices/Data/Database.cs index b27004a..130093a 100644 --- a/LocalServices/Data/Database.cs +++ b/LocalServices/Data/Database.cs @@ -15,6 +15,8 @@ namespace LocalEndpoint.Data public Account? GetAccount(string email, string passwordHash); + public void InsertInUserList(Guid userId, Guid recipeId, uint persAmount); + public void RemoveFromUserList(Guid userId, Guid recipeId); public void InsertAccount(Account account, string passwordHash); public void InsertRecipe(Recipe recipe); @@ -28,5 +30,7 @@ namespace LocalEndpoint.Data public ImmutableList ListAllRecipes(); public ImmutableDictionary ListRatesOf(Guid user); + + public ImmutableDictionary GetRecipeListOf(Guid user); } } diff --git a/LocalServices/Data/UserData.cs b/LocalServices/Data/UserData.cs index bad1f5e..847d659 100644 --- a/LocalServices/Data/UserData.cs +++ b/LocalServices/Data/UserData.cs @@ -8,6 +8,7 @@ namespace LocalEndpoint.Data [DataContract] internal record UserData( [property: DataMember] User User, - [property: DataMember] Dictionary Rates + [property: DataMember] Dictionary Rates, + [property: DataMember] Dictionary RecipesList ); } diff --git a/LocalServices/LocalEndpoint.cs b/LocalServices/LocalEndpoint.cs index d2d71d3..c8f4533 100644 --- a/LocalServices/LocalEndpoint.cs +++ b/LocalServices/LocalEndpoint.cs @@ -27,7 +27,7 @@ namespace LocalEndpoint authService = new AuthService(db); } - public IAuthService AccountManager => authService; + public IAuthService AuthService => authService; public IRecipesService RecipesService => recipesService; diff --git a/Services/IEndpoint.cs b/Services/IEndpoint.cs index bd75452..b928557 100644 --- a/Services/IEndpoint.cs +++ b/Services/IEndpoint.cs @@ -4,7 +4,7 @@ namespace Endpoint { public interface IEndpoint { - public IAuthService AccountManager { get; } + public IAuthService AuthService { get; } public IRecipesService RecipesService { get; } diff --git a/Services/IRecipesService.cs b/Services/IRecipesService.cs index f9159c2..88e8b65 100644 --- a/Services/IRecipesService.cs +++ b/Services/IRecipesService.cs @@ -1,11 +1,6 @@ using LocalEndpoint; using Models; -using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Endpoint {