From 199a08dd03fc4311c31d7f0a00e20bec00cff14c Mon Sep 17 00:00:00 2001 From: Ledana Date: Wed, 6 May 2026 12:35:43 +0200 Subject: [PATCH 1/3] Added my project --- DrinksInfo.Ledana/DrinksInfo.Ledana.slnx | 3 + .../Controllers/FavouriteDrinkController.cs | 44 ++++ .../Data/FavouritesDrinkContext.cs | 23 +++ .../DrinksInfo.Ledana.csproj | 35 ++++ .../20260506070842_InitialCreate.Designer.cs | 189 +++++++++++++++++ .../20260506070842_InitialCreate.cs | 82 ++++++++ .../20260506085503_AddViewCount.Designer.cs | 192 ++++++++++++++++++ .../Migrations/20260506085503_AddViewCount.cs | 29 +++ ...506085721_RemovedDeafaultValue.Designer.cs | 192 ++++++++++++++++++ .../20260506085721_RemovedDeafaultValue.cs | 22 ++ .../FavouritesDrinkContextModelSnapshot.cs | 189 +++++++++++++++++ .../DrinksInfo.Ledana/Models/Categories.cs | 10 + .../DrinksInfo.Ledana/Models/Category.cs | 7 + .../DrinksInfo.Ledana/Models/Drink.cs | 11 + .../DrinksInfo.Ledana/Models/DrinkDetail.cs | 67 ++++++ .../DrinksInfo.Ledana/Models/Drinks.cs | 10 + .../DrinksInfo.Ledana/Program.cs | 22 ++ .../Services/DrinkService.cs | 163 +++++++++++++++ .../TableVisualisationEngine.cs | 96 +++++++++ .../DrinksInfo.Ledana/UserInput.cs | 155 ++++++++++++++ .../DrinksInfo.Ledana/Validator.cs | 44 ++++ .../DrinksInfo.Ledana/appSettings.json | 5 + 22 files changed, 1590 insertions(+) create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana.slnx create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Data/FavouritesDrinkContext.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/DrinksInfo.Ledana.csproj create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506070842_InitialCreate.Designer.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506070842_InitialCreate.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085503_AddViewCount.Designer.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085503_AddViewCount.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085721_RemovedDeafaultValue.Designer.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085721_RemovedDeafaultValue.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/FavouritesDrinkContextModelSnapshot.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Categories.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Category.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Drink.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Models/DrinkDetail.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Drinks.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Program.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Services/DrinkService.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/TableVisualisationEngine.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/UserInput.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/Validator.cs create mode 100644 DrinksInfo.Ledana/DrinksInfo.Ledana/appSettings.json diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana.slnx b/DrinksInfo.Ledana/DrinksInfo.Ledana.slnx new file mode 100644 index 00000000..4f32197c --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana.slnx @@ -0,0 +1,3 @@ + + + diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs new file mode 100644 index 00000000..eaf42cf8 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs @@ -0,0 +1,44 @@ +using DrinksInfo.Ledana.Data; +using DrinksInfo.Ledana.Models; + +namespace DrinksInfo.Ledana.Controllers +{ + internal class FavouriteDrinkController + { + internal static void AddDrinkToFavourites(DrinkDetail favouriteDrink) + { + using var context = new FavouritesDrinkContext(); + + context.FavouriteDrinks.Add(favouriteDrink); + context.SaveChanges(); + } + + internal static async Task DeleteAllFavourites() + { + using var context = new FavouritesDrinkContext(); + context.FavouriteDrinks.RemoveRange(context.FavouriteDrinks); + await context.SaveChangesAsync(); + } + + internal static void DeleteFavourite(string? drink) + { + using var context = new FavouritesDrinkContext(); + var drinkToDelete = context.FavouriteDrinks.Where(d => d.idDrink == drink).First(); + context.FavouriteDrinks.Remove(drinkToDelete); + context.SaveChanges(); + } + + internal static List GetFavouriteDrinks() + { + using var context = new FavouritesDrinkContext(); + return context.FavouriteDrinks.ToList(); + } + + internal static bool HasDrink(string? drink) + { + using var context = new FavouritesDrinkContext(); + + return context.FavouriteDrinks.Any(d => d.idDrink == drink); + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Data/FavouritesDrinkContext.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Data/FavouritesDrinkContext.cs new file mode 100644 index 00000000..fda1c50d --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Data/FavouritesDrinkContext.cs @@ -0,0 +1,23 @@ +using DrinksInfo.Ledana.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; + +namespace DrinksInfo.Ledana.Data +{ + internal class FavouritesDrinkContext : DbContext + { + public DbSet FavouriteDrinks { get; set; } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + var config = new ConfigurationBuilder() + .SetBasePath(Directory.GetCurrentDirectory()) + .AddJsonFile("appSettings.json", optional: false, reloadOnChange: true) + .Build(); + + var connectionString = config.GetConnectionString("FavouriteDrinksDb"); + + optionsBuilder.UseSqlServer(connectionString); + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/DrinksInfo.Ledana.csproj b/DrinksInfo.Ledana/DrinksInfo.Ledana/DrinksInfo.Ledana.csproj new file mode 100644 index 00000000..0b3e9718 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/DrinksInfo.Ledana.csproj @@ -0,0 +1,35 @@ + + + + Exe + net10.0 + enable + enable + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + PreserveNewest + + + + diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506070842_InitialCreate.Designer.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506070842_InitialCreate.Designer.cs new file mode 100644 index 00000000..d5909805 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506070842_InitialCreate.Designer.cs @@ -0,0 +1,189 @@ +// +using DrinksInfo.Ledana.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DrinksInfo.Ledana.Migrations +{ + [DbContext(typeof(FavouritesDrinkContext))] + [Migration("20260506070842_InitialCreate")] + partial class InitialCreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("DrinksInfo.Ledana.Models.DrinkDetail", b => + { + b.Property("idDrink") + .HasColumnType("nvarchar(450)"); + + b.Property("dateModified") + .HasColumnType("nvarchar(max)"); + + b.Property("strAlcoholic") + .HasColumnType("nvarchar(max)"); + + b.Property("strCategory") + .HasColumnType("nvarchar(max)"); + + b.Property("strCreativeCommonsConfirmed") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrink") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrinkAlternate") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrinkThumb") + .HasColumnType("nvarchar(max)"); + + b.Property("strGlass") + .HasColumnType("nvarchar(max)"); + + b.Property("strIBA") + .HasColumnType("nvarchar(max)"); + + b.Property("strImageAttribution") + .HasColumnType("nvarchar(max)"); + + b.Property("strImageSource") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient1") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient10") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient11") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient12") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient13") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient14") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient15") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient2") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient3") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient4") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient5") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient6") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient7") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient8") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient9") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructions") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsDE") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsES") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsFR") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsIT") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsZHHANS") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsZHHANT") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure1") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure10") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure11") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure12") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure13") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure14") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure15") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure2") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure3") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure4") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure5") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure6") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure7") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure8") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure9") + .HasColumnType("nvarchar(max)"); + + b.Property("strTags") + .HasColumnType("nvarchar(max)"); + + b.Property("strVideo") + .HasColumnType("nvarchar(max)"); + + b.HasKey("idDrink"); + + b.ToTable("FavouriteDrinks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506070842_InitialCreate.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506070842_InitialCreate.cs new file mode 100644 index 00000000..c1f96f57 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506070842_InitialCreate.cs @@ -0,0 +1,82 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DrinksInfo.Ledana.Migrations +{ + /// + public partial class InitialCreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "FavouriteDrinks", + columns: table => new + { + idDrink = table.Column(type: "nvarchar(450)", nullable: false), + strDrink = table.Column(type: "nvarchar(max)", nullable: true), + strDrinkAlternate = table.Column(type: "nvarchar(max)", nullable: true), + strTags = table.Column(type: "nvarchar(max)", nullable: true), + strVideo = table.Column(type: "nvarchar(max)", nullable: true), + strCategory = table.Column(type: "nvarchar(max)", nullable: true), + strIBA = table.Column(type: "nvarchar(max)", nullable: true), + strAlcoholic = table.Column(type: "nvarchar(max)", nullable: true), + strGlass = table.Column(type: "nvarchar(max)", nullable: true), + strInstructions = table.Column(type: "nvarchar(max)", nullable: true), + strInstructionsES = table.Column(type: "nvarchar(max)", nullable: true), + strInstructionsDE = table.Column(type: "nvarchar(max)", nullable: true), + strInstructionsFR = table.Column(type: "nvarchar(max)", nullable: true), + strInstructionsIT = table.Column(type: "nvarchar(max)", nullable: true), + strInstructionsZHHANS = table.Column(type: "nvarchar(max)", nullable: true), + strInstructionsZHHANT = table.Column(type: "nvarchar(max)", nullable: true), + strDrinkThumb = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient1 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient2 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient3 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient4 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient5 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient6 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient7 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient8 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient9 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient10 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient11 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient12 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient13 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient14 = table.Column(type: "nvarchar(max)", nullable: true), + strIngredient15 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure1 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure2 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure3 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure4 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure5 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure6 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure7 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure8 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure9 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure10 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure11 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure12 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure13 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure14 = table.Column(type: "nvarchar(max)", nullable: true), + strMeasure15 = table.Column(type: "nvarchar(max)", nullable: true), + strImageSource = table.Column(type: "nvarchar(max)", nullable: true), + strImageAttribution = table.Column(type: "nvarchar(max)", nullable: true), + strCreativeCommonsConfirmed = table.Column(type: "nvarchar(max)", nullable: true), + dateModified = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_FavouriteDrinks", x => x.idDrink); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "FavouriteDrinks"); + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085503_AddViewCount.Designer.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085503_AddViewCount.Designer.cs new file mode 100644 index 00000000..5b84ad88 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085503_AddViewCount.Designer.cs @@ -0,0 +1,192 @@ +// +using DrinksInfo.Ledana.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DrinksInfo.Ledana.Migrations +{ + [DbContext(typeof(FavouritesDrinkContext))] + [Migration("20260506085503_AddViewCount")] + partial class AddViewCount + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("DrinksInfo.Ledana.Models.DrinkDetail", b => + { + b.Property("idDrink") + .HasColumnType("nvarchar(450)"); + + b.Property("dateModified") + .HasColumnType("nvarchar(max)"); + + b.Property("strAlcoholic") + .HasColumnType("nvarchar(max)"); + + b.Property("strCategory") + .HasColumnType("nvarchar(max)"); + + b.Property("strCreativeCommonsConfirmed") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrink") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrinkAlternate") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrinkThumb") + .HasColumnType("nvarchar(max)"); + + b.Property("strGlass") + .HasColumnType("nvarchar(max)"); + + b.Property("strIBA") + .HasColumnType("nvarchar(max)"); + + b.Property("strImageAttribution") + .HasColumnType("nvarchar(max)"); + + b.Property("strImageSource") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient1") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient10") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient11") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient12") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient13") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient14") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient15") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient2") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient3") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient4") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient5") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient6") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient7") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient8") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient9") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructions") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsDE") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsES") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsFR") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsIT") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsZHHANS") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsZHHANT") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure1") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure10") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure11") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure12") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure13") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure14") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure15") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure2") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure3") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure4") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure5") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure6") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure7") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure8") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure9") + .HasColumnType("nvarchar(max)"); + + b.Property("strTags") + .HasColumnType("nvarchar(max)"); + + b.Property("strVideo") + .HasColumnType("nvarchar(max)"); + + b.Property("viewCount") + .HasColumnType("int"); + + b.HasKey("idDrink"); + + b.ToTable("FavouriteDrinks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085503_AddViewCount.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085503_AddViewCount.cs new file mode 100644 index 00000000..3acbeb55 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085503_AddViewCount.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DrinksInfo.Ledana.Migrations +{ + /// + public partial class AddViewCount : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "viewCount", + table: "FavouriteDrinks", + type: "int", + nullable: false, + defaultValue: 0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "viewCount", + table: "FavouriteDrinks"); + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085721_RemovedDeafaultValue.Designer.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085721_RemovedDeafaultValue.Designer.cs new file mode 100644 index 00000000..a24823e4 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085721_RemovedDeafaultValue.Designer.cs @@ -0,0 +1,192 @@ +// +using DrinksInfo.Ledana.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DrinksInfo.Ledana.Migrations +{ + [DbContext(typeof(FavouritesDrinkContext))] + [Migration("20260506085721_RemovedDeafaultValue")] + partial class RemovedDeafaultValue + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("DrinksInfo.Ledana.Models.DrinkDetail", b => + { + b.Property("idDrink") + .HasColumnType("nvarchar(450)"); + + b.Property("dateModified") + .HasColumnType("nvarchar(max)"); + + b.Property("strAlcoholic") + .HasColumnType("nvarchar(max)"); + + b.Property("strCategory") + .HasColumnType("nvarchar(max)"); + + b.Property("strCreativeCommonsConfirmed") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrink") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrinkAlternate") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrinkThumb") + .HasColumnType("nvarchar(max)"); + + b.Property("strGlass") + .HasColumnType("nvarchar(max)"); + + b.Property("strIBA") + .HasColumnType("nvarchar(max)"); + + b.Property("strImageAttribution") + .HasColumnType("nvarchar(max)"); + + b.Property("strImageSource") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient1") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient10") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient11") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient12") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient13") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient14") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient15") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient2") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient3") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient4") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient5") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient6") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient7") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient8") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient9") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructions") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsDE") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsES") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsFR") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsIT") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsZHHANS") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsZHHANT") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure1") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure10") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure11") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure12") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure13") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure14") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure15") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure2") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure3") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure4") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure5") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure6") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure7") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure8") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure9") + .HasColumnType("nvarchar(max)"); + + b.Property("strTags") + .HasColumnType("nvarchar(max)"); + + b.Property("strVideo") + .HasColumnType("nvarchar(max)"); + + b.Property("viewCount") + .HasColumnType("int"); + + b.HasKey("idDrink"); + + b.ToTable("FavouriteDrinks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085721_RemovedDeafaultValue.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085721_RemovedDeafaultValue.cs new file mode 100644 index 00000000..09a24497 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/20260506085721_RemovedDeafaultValue.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DrinksInfo.Ledana.Migrations +{ + /// + public partial class RemovedDeafaultValue : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/FavouritesDrinkContextModelSnapshot.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/FavouritesDrinkContextModelSnapshot.cs new file mode 100644 index 00000000..9744d400 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Migrations/FavouritesDrinkContextModelSnapshot.cs @@ -0,0 +1,189 @@ +// +using DrinksInfo.Ledana.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace DrinksInfo.Ledana.Migrations +{ + [DbContext(typeof(FavouritesDrinkContext))] + partial class FavouritesDrinkContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("DrinksInfo.Ledana.Models.DrinkDetail", b => + { + b.Property("idDrink") + .HasColumnType("nvarchar(450)"); + + b.Property("dateModified") + .HasColumnType("nvarchar(max)"); + + b.Property("strAlcoholic") + .HasColumnType("nvarchar(max)"); + + b.Property("strCategory") + .HasColumnType("nvarchar(max)"); + + b.Property("strCreativeCommonsConfirmed") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrink") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrinkAlternate") + .HasColumnType("nvarchar(max)"); + + b.Property("strDrinkThumb") + .HasColumnType("nvarchar(max)"); + + b.Property("strGlass") + .HasColumnType("nvarchar(max)"); + + b.Property("strIBA") + .HasColumnType("nvarchar(max)"); + + b.Property("strImageAttribution") + .HasColumnType("nvarchar(max)"); + + b.Property("strImageSource") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient1") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient10") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient11") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient12") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient13") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient14") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient15") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient2") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient3") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient4") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient5") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient6") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient7") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient8") + .HasColumnType("nvarchar(max)"); + + b.Property("strIngredient9") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructions") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsDE") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsES") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsFR") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsIT") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsZHHANS") + .HasColumnType("nvarchar(max)"); + + b.Property("strInstructionsZHHANT") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure1") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure10") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure11") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure12") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure13") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure14") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure15") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure2") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure3") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure4") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure5") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure6") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure7") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure8") + .HasColumnType("nvarchar(max)"); + + b.Property("strMeasure9") + .HasColumnType("nvarchar(max)"); + + b.Property("strTags") + .HasColumnType("nvarchar(max)"); + + b.Property("strVideo") + .HasColumnType("nvarchar(max)"); + + b.Property("viewCount") + .HasColumnType("int"); + + b.HasKey("idDrink"); + + b.ToTable("FavouriteDrinks"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Categories.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Categories.cs new file mode 100644 index 00000000..84dcd78e --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Categories.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace DrinksInfo.Ledana.Models +{ + internal class Categories + { + [JsonPropertyName("drinks")] + public List CategoriesList { get; set; } = []; + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Category.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Category.cs new file mode 100644 index 00000000..f320574f --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Category.cs @@ -0,0 +1,7 @@ +namespace DrinksInfo.Ledana.Models +{ + internal class Category + { + public string? strCategory { get; set; } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Drink.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Drink.cs new file mode 100644 index 00000000..78e300a6 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Drink.cs @@ -0,0 +1,11 @@ +namespace DrinksInfo.Ledana.Models +{ + internal class Drink + { + public string? strDrink { get; set; } + public string? strDrinkThumb { get; set; } + public string? idDrink { get; set; } + public int viewCount { get; set; } + + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/DrinkDetail.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/DrinkDetail.cs new file mode 100644 index 00000000..e7d49067 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/DrinkDetail.cs @@ -0,0 +1,67 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace DrinksInfo.Ledana.Models +{ + internal class DrinkDetailObject + { + [JsonPropertyName("drinks")] + public List DrinkDetailList { get; set; } = []; + } + internal class DrinkDetail + { + [Key] + public string? idDrink { get; set; } + public int viewCount { get; set; } + public string? strDrink { get; set; } + public string? strDrinkAlternate { get; set; } + public string? strTags { get; set; } + public string? strVideo { get; set; } + public string? strCategory { get; set; } + public string? strIBA { get; set; } + public string? strAlcoholic { get; set; } + public string? strGlass { get; set; } + public string? strInstructions { get; set; } + public string? strInstructionsES { get; set; } + public string? strInstructionsDE { get; set; } + public string? strInstructionsFR { get; set; } + public string? strInstructionsIT { get; set; } + public string? strInstructionsZHHANS { get; set; } + public string? strInstructionsZHHANT { get; set; } + public string? strDrinkThumb { get; set; } + public string? strIngredient1 { get; set; } + public string? strIngredient2 { get; set; } + public string? strIngredient3 { get; set; } + public string? strIngredient4 { get; set; } + public string? strIngredient5 { get; set; } + public string? strIngredient6 { get; set; } + public string? strIngredient7 { get; set; } + public string? strIngredient8 { get; set; } + public string? strIngredient9 { get; set; } + public string? strIngredient10 { get; set; } + public string? strIngredient11 { get; set; } + public string? strIngredient12 { get; set; } + public string? strIngredient13 { get; set; } + public string? strIngredient14 { get; set; } + public string? strIngredient15 { get; set; } + public string? strMeasure1 { get; set; } + public string? strMeasure2 { get; set; } + public string? strMeasure3 { get; set; } + public string? strMeasure4 { get; set; } + public string? strMeasure5 { get; set; } + public string? strMeasure6 { get; set; } + public string? strMeasure7 { get; set; } + public string? strMeasure8 { get; set; } + public string? strMeasure9 { get; set; } + public string? strMeasure10 { get; set; } + public string? strMeasure11 { get; set; } + public string? strMeasure12 { get; set; } + public string? strMeasure13 { get; set; } + public string? strMeasure14 { get; set; } + public string? strMeasure15 { get; set; } + public string? strImageSource { get; set; } + public string? strImageAttribution { get; set; } + public string? strCreativeCommonsConfirmed { get; set; } + public string? dateModified { get; set; } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Drinks.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Drinks.cs new file mode 100644 index 00000000..bff55810 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Models/Drinks.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace DrinksInfo.Ledana.Models +{ + internal class Drinks + { + [JsonPropertyName("drinks")] + public List DrinksList { get; set; } = []; + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Program.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Program.cs new file mode 100644 index 00000000..48254739 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Program.cs @@ -0,0 +1,22 @@ +using DrinksInfo.Ledana; + +class Program +{ + static async Task Main() + { + UserInput userInput = new(); + while(true) + { + await userInput.GetCategoriesInput(); + Console.WriteLine("Press 'x' to exit or any other key to look into another drink"); + var input = Console.ReadLine(); + if (input is not null && input.ToLower() == "x") + { + Console.WriteLine("Good bye!"); + break; + } + } + + } +} + diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Services/DrinkService.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Services/DrinkService.cs new file mode 100644 index 00000000..42489d51 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Services/DrinkService.cs @@ -0,0 +1,163 @@ +using DrinksInfo.Ledana.Models; +using System.Net.Http.Headers; +using System.Reflection; +using System.Web; +using System.Text.Json; + + +namespace DrinksInfo.Ledana.Services +{ + internal class DrinkService + { + internal async Task?> GetCategoriesByHttpClient() + { + try + { + using HttpClient client = new(); + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/json")); + + string url = "https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list"; + var response = await client.GetAsync(url); + + if (response.IsSuccessStatusCode) + { + using var stream = await response.Content.ReadAsStreamAsync(); + + var serialize = await JsonSerializer.DeserializeAsync(stream, + new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + if (serialize is null) return null; + + return serialize.CategoriesList; + } + else return null; + } + catch (Exception e) + { + Console.WriteLine("Something is not working!" + e.Message); + return null; + } + } + + internal async Task?> GetDrinksByCategory(string? category) + { + try + { + using HttpClient client = new(); + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/json")); + + string url = $"https://www.thecocktaildb.com/api/json/v1/1/filter.php?c={HttpUtility.UrlEncode(category)}"; + var response = await client.GetAsync(url); + + if (response.IsSuccessStatusCode) + { + using var stream = await response.Content.ReadAsStreamAsync(); + + var serialize = await JsonSerializer.DeserializeAsync(stream, + new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + return serialize!.DrinksList; + } + else + return null; + } + catch (Exception e) + { + Console.WriteLine("Something is not working!" + e.Message); + return null; + } + } + + internal async Task?> GetDrink(string? drink) + { + try + { + using HttpClient client = new(); + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/json")); + + string url = $"https://www.thecocktaildb.com/api/json/v1/1/lookup.php?i={drink}"; + var response = await client.GetAsync(url); + + if (response.IsSuccessStatusCode) + { + using var stream = await response.Content.ReadAsStreamAsync(); + + var serializer = await JsonSerializer.DeserializeAsync(stream, + new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + + if (serializer is null) return null; + + List returnedList = serializer.DrinkDetailList; + if (returnedList is null || returnedList.Count == 0) + return null; + + DrinkDetail drinkDetail = returnedList[0]; + + List<(string Key, string Value)> prepList = []; + + foreach (PropertyInfo prop in drinkDetail.GetType().GetProperties()) + { + var value = prop.GetValue(drinkDetail)?.ToString(); + + if (!string.IsNullOrEmpty(value)) + { + string formattedName = prop.Name.StartsWith("str") + ? prop.Name.Substring(3) + : prop.Name; + + prepList.Add((formattedName, value)); + } + } + return prepList; + } + else + return null; + } + catch (Exception e) + { + Console.WriteLine("Something is not working!" + e.Message); + return null; + } + } + public async Task GetDrinkDetail(string? drink) + { + try + { + using HttpClient client = new(); + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add( + new MediaTypeWithQualityHeaderValue("application/json")); + + string url = $"https://www.thecocktaildb.com/api/json/v1/1/lookup.php?i={drink}"; + var response = await client.GetAsync(url); + + if (response.IsSuccessStatusCode) + { + using var stream = await response.Content.ReadAsStreamAsync(); + + var serializer = await JsonSerializer.DeserializeAsync(stream); + + if (serializer is null) return null; + + List returnedList = serializer.DrinkDetailList; + if (returnedList is null || returnedList.Count == 0) + return null; + + return returnedList[0]; + } + else + return null; + } + catch (Exception e) + { + Console.WriteLine("Something is not working!" + e.Message); + return null; + + } + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/TableVisualisationEngine.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/TableVisualisationEngine.cs new file mode 100644 index 00000000..06c1f641 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/TableVisualisationEngine.cs @@ -0,0 +1,96 @@ +using DrinksInfo.Ledana.Models; +using Microsoft.EntityFrameworkCore; +using Spectre.Console; + +namespace DrinksInfo.Ledana +{ + internal class TableVisualisationEngine + { + internal static void ShowCategoriesHttpTable(List? categories) + { + Console.Clear(); + + var table = new Table(); + table.AddColumn("Categories: "); + + if (categories is null) + { + Console.WriteLine("Table is empty or API is down!"); + return; + } + + foreach (var item in categories) + { + table.AddRow(item.strCategory); + } + table.AddRow("Favourites"); + + AnsiConsole.Write(table); + Console.Write("Type 'x' to exit or Choose category : "); + } + + internal static void ShowDrinkHttp(List<(string Key, string Value)> drinkTable) + { + var table = new Table() + .ShowRowSeparators(); + table.AddColumn("Property"); + table.AddColumn("Value"); + + foreach (var item in drinkTable) + { + table.AddRow(item.Key, item.Value); + } + AnsiConsole.Write(table); + } + + internal static void ShowDrinksHttpTable(List? drinks) + { + var table = new Table().Title("Drinks: "); + + table.AddColumn("Id"); + table.AddColumn("Name"); + + if (drinks is null) + { + Console.WriteLine("Table empty or API is down!"); + return; + } + + foreach (var item in drinks) + { + table.AddRow(item.idDrink.ToString(), item.strDrink); + } + AnsiConsole.Write(table); + Console.Write("Type 'x' to exit or Choose drink id: "); + } + + internal static void ShowFavouriteDrinksHttpTable(List favouriteDrinks) + { + var table = new Table(); + table.AddColumn("Property"); + table.AddColumn("Value"); + + List drinks = []; + foreach(var item in favouriteDrinks) + { + drinks.Add(DetailToDrink(item)); + } + + foreach (var item in drinks) + { + table.AddRow(item.idDrink.ToString(), item.strDrink); + } + + AnsiConsole.Write(table); + Console.Write("Type 'x' to exit or Choose drink id: "); + } + private static Drink DetailToDrink(DrinkDetail drink) + { + return new Drink() + { + idDrink = drink.idDrink, + strDrink = drink.strDrink + }; + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/UserInput.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/UserInput.cs new file mode 100644 index 00000000..c8a79dee --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/UserInput.cs @@ -0,0 +1,155 @@ +using DrinksInfo.Ledana.Controllers; +using DrinksInfo.Ledana.Models; +using DrinksInfo.Ledana.Services; + +namespace DrinksInfo.Ledana +{ + internal class UserInput + { + private readonly DrinkService drinksService = new(); + + internal async Task GetCategoriesInput() + { + var categories = await drinksService.GetCategoriesByHttpClient(); + + if (categories is null) return; + + TableVisualisationEngine.ShowCategoriesHttpTable(categories); + + string? category = Console.ReadLine(); + if (category is not null && category.ToLower() == "x") return; + + if (!string.IsNullOrEmpty(category) && category.ToLower() == "favourites") + { + FavouritesMenu(); + string? input = Console.ReadLine(); + if (input is null) return; + + switch (input) + { + case "1": + await SeeAllFavourites(); + break; + case "2": + await DeleteAllFavourites(); + break; + case "3": + DeleteOneFavourite(); + break; + default: + break; + } + + return; + } + + while (!Validator.IsCategoryValid(category, categories)) + { + Console.WriteLine("\nInvalid category. Type 'x' to exit or try again."); + category = Console.ReadLine(); + if (category == "x") return; + } + + await GetDrinksInput(category); + } + + private void DeleteOneFavourite() + { + List favouriteDrinks = FavouriteDrinkController.GetFavouriteDrinks(); + + TableVisualisationEngine.ShowFavouriteDrinksHttpTable(favouriteDrinks); + + string? drink = Console.ReadLine(); + + while (!Validator.IsIdValid(drink, favouriteDrinks)) + { + Console.WriteLine("\nInvalid drink. Type 'x' to exit or try again."); + drink = Console.ReadLine(); + if (drink == "x") return; + } + + FavouriteDrinkController.DeleteFavourite(drink); + Console.WriteLine($"Drink with id {drink} has been deleted!"); + } + + private async Task DeleteAllFavourites() + { + await FavouriteDrinkController.DeleteAllFavourites(); + Console.WriteLine("Successfully deleted all favourites!"); + } + + public async Task SeeAllFavourites() + { + List favouriteDrinks = FavouriteDrinkController.GetFavouriteDrinks(); + + TableVisualisationEngine.ShowFavouriteDrinksHttpTable(favouriteDrinks); + + string? drink = Console.ReadLine(); + if (drink is not null && drink.ToLower() == "x") return; + + while (!Validator.IsIdValid(drink, favouriteDrinks)) + { + Console.WriteLine("\nInvalid drink. Type 'x' to exit or try again."); + drink = Console.ReadLine(); + if (drink == "x") return; + } + + var drinkTable = await drinksService.GetDrink(drink); + + if (drinkTable is null) return; + + TableVisualisationEngine.ShowDrinkHttp(drinkTable); + return; + } + private void FavouritesMenu() + { + Console.WriteLine("1. See all favourites"); + Console.WriteLine("2. Delete all favourites"); + Console.WriteLine("3. Delete one favourite"); + } + + private async Task GetDrinksInput(string? category) + { + var drinks = await drinksService.GetDrinksByCategory(category); + + if (drinks is null) return; + + TableVisualisationEngine.ShowDrinksHttpTable(drinks); + + string? drink = Console.ReadLine(); + + if (drink is not null && drink.ToLower() == "x") return; + + while (!Validator.IsIdValid(drink, drinks)) + { + Console.WriteLine("\nInvalid drink. Type 'x' to exit or try again."); + drink = Console.ReadLine(); + if (drink == "x") return; + } + + var drinkTable = await drinksService.GetDrink(drink); + + if (drinkTable is null) return; + + TableVisualisationEngine.ShowDrinkHttp(drinkTable); + + if (!FavouriteDrinkController.HasDrink(drink)) + await AskForFavourite(drink); + } + + public async Task AskForFavourite(string? drink) + { + Console.WriteLine("Do you want to add this category to your favourites? (y/n): "); + var input = Console.ReadLine(); + if (input is not null && input.ToLower() == "y") + { + DrinkDetail? favouriteDrink = await drinksService.GetDrinkDetail(drink); + if (favouriteDrink is null) return; + + FavouriteDrinkController.AddDrinkToFavourites(favouriteDrink); + + Console.WriteLine("Drink added into favourites successfully!"); + } + } + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Validator.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Validator.cs new file mode 100644 index 00000000..e8df1a28 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Validator.cs @@ -0,0 +1,44 @@ +using DrinksInfo.Ledana.Models; + +namespace DrinksInfo.Ledana +{ + internal class Validator + { + internal static bool IsIdValid(string? drink, List drinks) + { + if (string.IsNullOrEmpty(drink) || !drinks.Any(d => d.idDrink == drink)) return false; + + foreach (char c in drink) + { + if (!char.IsDigit(c)) + return false; + } + return true; + } + internal static bool IsIdValid(string? drink, List drinks) + { + if (string.IsNullOrEmpty(drink) || !drinks.Any(d => d.idDrink == drink)) return false; + + foreach (char c in drink) + { + if (!char.IsDigit(c)) + return false; + } + return true; + } + + internal static bool IsCategoryValid(string? category, List categories) + { + if (string.IsNullOrEmpty(category)) return false; + + foreach (char c in category) + { + if ((!char.IsLetter(c) && c != '/' && c != ' ') || (!categories.Any(c => c.strCategory.ToLower() == category.ToLower()))) + return false; + } + + return true; + } + + } +} diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/appSettings.json b/DrinksInfo.Ledana/DrinksInfo.Ledana/appSettings.json new file mode 100644 index 00000000..e5448285 --- /dev/null +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/appSettings.json @@ -0,0 +1,5 @@ +{ + "ConnectionStrings": { + "FavouriteDrinksDb": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=FavouriteDrinksDb;Trust Server Certificate=True;" + } +} From de831cc963072636a1e11c868fd5a2d2e143143b Mon Sep 17 00:00:00 2001 From: Ledana Date: Wed, 6 May 2026 12:58:31 +0200 Subject: [PATCH 2/3] added try catch in every method of the controller --- .../Controllers/FavouriteDrinkController.cs | 61 ++++++++++++++----- 1 file changed, 47 insertions(+), 14 deletions(-) diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs index eaf42cf8..fe14a5e7 100644 --- a/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs @@ -7,38 +7,71 @@ internal class FavouriteDrinkController { internal static void AddDrinkToFavourites(DrinkDetail favouriteDrink) { - using var context = new FavouritesDrinkContext(); - - context.FavouriteDrinks.Add(favouriteDrink); - context.SaveChanges(); + try + { + using var context = new FavouritesDrinkContext(); + context.FavouriteDrinks.Add(favouriteDrink); + context.SaveChanges(); + } + catch(Exception e) + { + Console.WriteLine("Something went wrong! " + e.Message); + } } internal static async Task DeleteAllFavourites() { + try + { using var context = new FavouritesDrinkContext(); context.FavouriteDrinks.RemoveRange(context.FavouriteDrinks); await context.SaveChangesAsync(); + } + catch (Exception e) + { + Console.WriteLine("Something went wrong! " + e.Message); + } } internal static void DeleteFavourite(string? drink) { - using var context = new FavouritesDrinkContext(); - var drinkToDelete = context.FavouriteDrinks.Where(d => d.idDrink == drink).First(); - context.FavouriteDrinks.Remove(drinkToDelete); - context.SaveChanges(); - } + try + { + using var context = new FavouritesDrinkContext(); + var drinkToDelete = context.FavouriteDrinks.Where(d => d.idDrink == drink).First(); + context.FavouriteDrinks.Remove(drinkToDelete); + context.SaveChanges(); + } + catch(Exception e) + { + Console.WriteLine("Something went wrong! " + e.Message); + } +} internal static List GetFavouriteDrinks() { - using var context = new FavouritesDrinkContext(); - return context.FavouriteDrinks.ToList(); + try + { + using var context = new FavouritesDrinkContext(); + return context.FavouriteDrinks.ToList(); + } + catch (Exception e) + { + Console.WriteLine("Something went wrong! " + e.Message); + } } internal static bool HasDrink(string? drink) { - using var context = new FavouritesDrinkContext(); - - return context.FavouriteDrinks.Any(d => d.idDrink == drink); + try + { + using var context = new FavouritesDrinkContext(); + return context.FavouriteDrinks.Any(d => d.idDrink == drink); + } + catch (Exception e) + { + Console.WriteLine("Something went wrong! " + e.Message); + } } } } From 0dfb8d3547dea40f3732a849e597af5f1d3d92cb Mon Sep 17 00:00:00 2001 From: Ledana Date: Fri, 15 May 2026 08:14:32 +0200 Subject: [PATCH 3/3] fixed the catch return in controller and handled null in ui --- .../DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs | 2 ++ DrinksInfo.Ledana/DrinksInfo.Ledana/UserInput.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs index fe14a5e7..f10db243 100644 --- a/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/Controllers/FavouriteDrinkController.cs @@ -58,6 +58,7 @@ internal static List GetFavouriteDrinks() catch (Exception e) { Console.WriteLine("Something went wrong! " + e.Message); + return null; } } @@ -71,6 +72,7 @@ internal static bool HasDrink(string? drink) catch (Exception e) { Console.WriteLine("Something went wrong! " + e.Message); + return false; } } } diff --git a/DrinksInfo.Ledana/DrinksInfo.Ledana/UserInput.cs b/DrinksInfo.Ledana/DrinksInfo.Ledana/UserInput.cs index c8a79dee..a47259ef 100644 --- a/DrinksInfo.Ledana/DrinksInfo.Ledana/UserInput.cs +++ b/DrinksInfo.Ledana/DrinksInfo.Ledana/UserInput.cs @@ -56,6 +56,7 @@ internal async Task GetCategoriesInput() private void DeleteOneFavourite() { List favouriteDrinks = FavouriteDrinkController.GetFavouriteDrinks(); + if (favouriteDrinks is null) return; TableVisualisationEngine.ShowFavouriteDrinksHttpTable(favouriteDrinks); @@ -81,6 +82,7 @@ private async Task DeleteAllFavourites() public async Task SeeAllFavourites() { List favouriteDrinks = FavouriteDrinkController.GetFavouriteDrinks(); + if (favouriteDrinks is null) return; TableVisualisationEngine.ShowFavouriteDrinksHttpTable(favouriteDrinks);