From 45f27d341dca3be3ad74c63d663324e245c6a65b Mon Sep 17 00:00:00 2001 From: "includingivansmirnov@gmail.com" Date: Mon, 2 May 2022 22:35:48 +0500 Subject: [PATCH 01/15] Add: Part of Implement functionality for Deck CRUD #2 and continue buid class DeckService BusinessLogic #4 --- Tyche/Tyche.API/Controllers/DeckController.cs | 39 ++++----- Tyche/Tyche.API/Models/DeckRespose.cs | 13 +++ Tyche/Tyche.API/Startup.cs | 18 ++--- Tyche/Tyche.API/Tyche.API.csproj | 10 +-- Tyche/Tyche.API/appsettings.json | 6 +- .../Services/DeckService.cs | 74 ++++++++++++++++- .../Context/DeckContext.cs | 17 ++++ .../Entities/CardEntity.cs | 16 ++++ .../Entities/DeckEntity.cs | 14 ++++ .../Infrastructure/Automapper.cs | 53 +++++++++++++ .../20220502170054_First.Designer.cs | 79 +++++++++++++++++++ .../Migrations/20220502170054_First.cs | 58 ++++++++++++++ .../Migrations/DeckContextModelSnapshot.cs | 77 ++++++++++++++++++ .../Repository/DeckRepository.cs | 75 ++++++++++++++++++ .../Tyche.DataAccess.MsSql.csproj | 13 +++ .../Interfaces/IDeckRepository.cs | 20 +++++ Tyche/Tyche.Domain/Interfaces/IDeckService.cs | 12 ++- Tyche/Tyche.Domain/Models/Card.cs | 15 +++- Tyche/Tyche.Domain/Models/Deck.cs | 8 +- Tyche/Tyche.sln | 12 +-- 20 files changed, 579 insertions(+), 50 deletions(-) create mode 100644 Tyche/Tyche.API/Models/DeckRespose.cs create mode 100644 Tyche/Tyche.DataAccess.MsSql/Context/DeckContext.cs create mode 100644 Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs create mode 100644 Tyche/Tyche.DataAccess.MsSql/Entities/DeckEntity.cs create mode 100644 Tyche/Tyche.DataAccess.MsSql/Infrastructure/Automapper.cs create mode 100644 Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.Designer.cs create mode 100644 Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.cs create mode 100644 Tyche/Tyche.DataAccess.MsSql/Migrations/DeckContextModelSnapshot.cs create mode 100644 Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs create mode 100644 Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs diff --git a/Tyche/Tyche.API/Controllers/DeckController.cs b/Tyche/Tyche.API/Controllers/DeckController.cs index 1079b7f..0d4af1c 100644 --- a/Tyche/Tyche.API/Controllers/DeckController.cs +++ b/Tyche/Tyche.API/Controllers/DeckController.cs @@ -18,30 +18,33 @@ public DeckController(IDeckService deckService) } [HttpPost] - [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] - [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)] - public ActionResult Create(Suit suit) + public IActionResult Create(string suitRequest) { - if (ModelState.IsValid == false) - return BadRequest(); - - try - { - var response = _deckService.CreateNamedDeck(suit); - return Ok(response); - } - catch (Exception ex) + if (Enum.TryParse(suitRequest, out var suit)) { - return BadRequest(ex.Message); + try + { + var response = _deckService.CreateNamedDeck(suit); + return Ok(response); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } } + + return BadRequest($"Suit can be only \"Spades\", \"Clubs\", \"Hearts\", \"Diamonds\"; But you try enter suit - \"{suitRequest}\""); } - [HttpGet("{DeckSuit:int}")] - public IActionResult Get(int suit) + [HttpGet("{suitRequest}")] + public ActionResult Get(string suitRequest) { - var response = _deckService.GetNamedDeck(suit); - return Ok(response); + if (Enum.TryParse(suitRequest, out var suit)) + { + var response = _deckService.GetDeckBySuit(suit); + return Ok(response); + } + return BadRequest($"Suit can be only \"Spades\", \"Clubs\", \"Hearts\", \"Diamonds\"; But you try enter suit - \"{suitRequest}\""); } } } diff --git a/Tyche/Tyche.API/Models/DeckRespose.cs b/Tyche/Tyche.API/Models/DeckRespose.cs new file mode 100644 index 0000000..e55ebaf --- /dev/null +++ b/Tyche/Tyche.API/Models/DeckRespose.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tyche.API.Models +{ + public class DeckRespose + { + + } +} diff --git a/Tyche/Tyche.API/Startup.cs b/Tyche/Tyche.API/Startup.cs index b428a82..e2f340c 100644 --- a/Tyche/Tyche.API/Startup.cs +++ b/Tyche/Tyche.API/Startup.cs @@ -1,19 +1,16 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Tyche.BusinessLogic.Services; +using Tyche.DataAccess.MsSql.Context; +using Tyche.DataAccess.MsSql.Repository; using Tyche.Domain.Interfaces; + namespace Tyche.API { public class Startup @@ -25,13 +22,15 @@ public Startup(IConfiguration configuration) public IConfiguration Configuration { get; } - // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddControllers(); services.AddScoped(); + services.AddScoped(); + + services.AddDbContext(x => + x.UseSqlServer(Configuration.GetConnectionString("DeckContext"))); services.AddSwaggerGen(c => { @@ -39,7 +38,6 @@ public void ConfigureServices(IServiceCollection services) }); } - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) diff --git a/Tyche/Tyche.API/Tyche.API.csproj b/Tyche/Tyche.API/Tyche.API.csproj index b49eb3e..7c3b5a5 100644 --- a/Tyche/Tyche.API/Tyche.API.csproj +++ b/Tyche/Tyche.API/Tyche.API.csproj @@ -5,16 +5,16 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - - - - - + diff --git a/Tyche/Tyche.API/appsettings.json b/Tyche/Tyche.API/appsettings.json index d9d9a9b..fe25ec2 100644 --- a/Tyche/Tyche.API/appsettings.json +++ b/Tyche/Tyche.API/appsettings.json @@ -6,5 +6,9 @@ "Microsoft.Hosting.Lifetime": "Information" } }, - "AllowedHosts": "*" + "AllowedHosts": "*", + "ConnectionStrings": { + //"DeckContext": "Data Source=(LocalDb)\\MSSQLLocalDB;Database=DeckDB;Trusted_Connection=True;MultipleActiveResultSets=true" + "DeckContext": "Data Source=DESKTOP-KJ6048R;Database=DeckDB;Trusted_Connection=True;MultipleActiveResultSets=true" + } } diff --git a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs index e45629c..6b44032 100644 --- a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs +++ b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Tyche.Domain.Interfaces; using Tyche.Domain.Models; @@ -7,14 +8,81 @@ namespace Tyche.BusinessLogic.Services { public class DeckService : IDeckService { + private readonly IDeckRepository _deckRepository; + + public DeckService(IDeckRepository deckRepository) + { + _deckRepository = deckRepository; + } + public string CreateNamedDeck(Suit suit) { - throw new NotImplementedException(); + try + { + var existingDecks = GetCreatedDecksSuits(); + + if (existingDecks.Length != 0) + { + foreach (var existingSuit in existingDecks) + { + if (existingSuit == suit.ToString()) + return "Deck already exists"; + } + } + + var cards = GetCardsArray(suit); + var deck = new Deck(cards); + + _deckRepository.Add(deck); + return "Success created"; + } + catch (Exception ex) + { + return ex.Message; + } + } + + public Deck GetDeckBySuit(Suit suit) + { + var deck = _deckRepository.GetDeck(suit); + return deck; } - public Deck GetNamedDeck(int suit) + public Deck[] GetDecks() { - throw new NotImplementedException(); + return new Deck[] { }; + } + + public string[] GetCreatedDecksSuits() + { + return _deckRepository.GetDecksSuit(); + } + + public string DeleteDeckBySuit(Suit suit) + { + return "Success deleted"; + } + + public string ShuffleDeckBySuit(Suit suit, int sortOption) + { + return "Successfully shuffled"; + } + + private void Update() + { + + } + + private Card[] GetCardsArray(Suit suit) + { + List listCards = new List(); + + foreach (Rank rank in Enum.GetValues(typeof(Rank))) + { + listCards.Add(new Card(rank, suit)); + } + + return listCards.ToArray(); } } } diff --git a/Tyche/Tyche.DataAccess.MsSql/Context/DeckContext.cs b/Tyche/Tyche.DataAccess.MsSql/Context/DeckContext.cs new file mode 100644 index 0000000..e125202 --- /dev/null +++ b/Tyche/Tyche.DataAccess.MsSql/Context/DeckContext.cs @@ -0,0 +1,17 @@ +using Microsoft.EntityFrameworkCore; +using Tyche.DataAccess.MsSql.Entities; + +namespace Tyche.DataAccess.MsSql.Context +{ + public class DeckContext : DbContext + { + public DbSet Decks { get; set; } + public DbSet Cards { get; set; } + + public DeckContext(DbContextOptions options) : base(options) + { + + } + + } +} diff --git a/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs b/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs new file mode 100644 index 0000000..053b684 --- /dev/null +++ b/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs @@ -0,0 +1,16 @@ + +namespace Tyche.DataAccess.MsSql.Entities +{ + public class CardEntity + { + public int Id { get; set; } + + public string Rank { get; set; } + + public string Suit { get; set; } + + public int DeckId { get; set; } + + public DeckEntity Deck { get; set; } + } +} diff --git a/Tyche/Tyche.DataAccess.MsSql/Entities/DeckEntity.cs b/Tyche/Tyche.DataAccess.MsSql/Entities/DeckEntity.cs new file mode 100644 index 0000000..b537743 --- /dev/null +++ b/Tyche/Tyche.DataAccess.MsSql/Entities/DeckEntity.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + + +namespace Tyche.DataAccess.MsSql.Entities +{ + public class DeckEntity + { + public int Id { get; set; } + + public string Suit { get; set; } + + public ICollection Deck { get; set; } + } +} diff --git a/Tyche/Tyche.DataAccess.MsSql/Infrastructure/Automapper.cs b/Tyche/Tyche.DataAccess.MsSql/Infrastructure/Automapper.cs new file mode 100644 index 0000000..67a0bbe --- /dev/null +++ b/Tyche/Tyche.DataAccess.MsSql/Infrastructure/Automapper.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Tyche.DataAccess.MsSql.Entities; +using Tyche.Domain.Models; + + +namespace Tyche.DataAccess.MsSql.Infrastructure +{ + public class Automapper + { + public DeckEntity MappingToDeckEntity(Deck deck) + { + var cards = new List(); + + while (deck.Count > 0) + { + var card = deck.Pull(); + var cardEntity = new CardEntity + { + Rank = card.Rank.ToString(), + Suit = card.Suit.ToString() + }; + cards.Add(cardEntity); + } + + var suit = deck.Suit.ToString(); + + return new DeckEntity + { + Suit = suit, + Deck = cards.ToArray() + }; + } + + public Deck MappingToDeck(DeckEntity deckEntity) + { + var cards = new List(); + var decks = deckEntity.Deck; + + foreach (var item in decks) + { + var rank = (Rank)Enum.Parse(typeof(Rank), item.Rank); + var suit = (Suit)Enum.Parse(typeof(Suit), item.Suit); + + var card = new Card(rank, suit); + + cards.Add(card); + } + + return new Deck(cards.ToArray()); + } + } +} diff --git a/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.Designer.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.Designer.cs new file mode 100644 index 0000000..02026b2 --- /dev/null +++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.Designer.cs @@ -0,0 +1,79 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Tyche.DataAccess.MsSql.Context; + +namespace Tyche.DataAccess.MsSql.Migrations +{ + [DbContext(typeof(DeckContext))] + [Migration("20220502170054_First")] + partial class First + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.16") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Tyche.DataAccess.MsSql.Entities.CardEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("DeckId") + .HasColumnType("int"); + + b.Property("Rank") + .HasColumnType("nvarchar(max)"); + + b.Property("Suit") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("DeckId"); + + b.ToTable("Cards"); + }); + + modelBuilder.Entity("Tyche.DataAccess.MsSql.Entities.DeckEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Suit") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Decks"); + }); + + modelBuilder.Entity("Tyche.DataAccess.MsSql.Entities.CardEntity", b => + { + b.HasOne("Tyche.DataAccess.MsSql.Entities.DeckEntity", "Deck") + .WithMany("Deck") + .HasForeignKey("DeckId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Deck"); + }); + + modelBuilder.Entity("Tyche.DataAccess.MsSql.Entities.DeckEntity", b => + { + b.Navigation("Deck"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.cs new file mode 100644 index 0000000..2dc9e0f --- /dev/null +++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.cs @@ -0,0 +1,58 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Tyche.DataAccess.MsSql.Migrations +{ + public partial class First : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Decks", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Suit = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Decks", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Cards", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + Rank = table.Column(type: "nvarchar(max)", nullable: true), + Suit = table.Column(type: "nvarchar(max)", nullable: true), + DeckId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Cards", x => x.Id); + table.ForeignKey( + name: "FK_Cards_Decks_DeckId", + column: x => x.DeckId, + principalTable: "Decks", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_Cards_DeckId", + table: "Cards", + column: "DeckId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Cards"); + + migrationBuilder.DropTable( + name: "Decks"); + } + } +} diff --git a/Tyche/Tyche.DataAccess.MsSql/Migrations/DeckContextModelSnapshot.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/DeckContextModelSnapshot.cs new file mode 100644 index 0000000..822a630 --- /dev/null +++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/DeckContextModelSnapshot.cs @@ -0,0 +1,77 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Tyche.DataAccess.MsSql.Context; + +namespace Tyche.DataAccess.MsSql.Migrations +{ + [DbContext(typeof(DeckContext))] + partial class DeckContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("Relational:MaxIdentifierLength", 128) + .HasAnnotation("ProductVersion", "5.0.16") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + modelBuilder.Entity("Tyche.DataAccess.MsSql.Entities.CardEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("DeckId") + .HasColumnType("int"); + + b.Property("Rank") + .HasColumnType("nvarchar(max)"); + + b.Property("Suit") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("DeckId"); + + b.ToTable("Cards"); + }); + + modelBuilder.Entity("Tyche.DataAccess.MsSql.Entities.DeckEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); + + b.Property("Suit") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Decks"); + }); + + modelBuilder.Entity("Tyche.DataAccess.MsSql.Entities.CardEntity", b => + { + b.HasOne("Tyche.DataAccess.MsSql.Entities.DeckEntity", "Deck") + .WithMany("Deck") + .HasForeignKey("DeckId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Deck"); + }); + + modelBuilder.Entity("Tyche.DataAccess.MsSql.Entities.DeckEntity", b => + { + b.Navigation("Deck"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs b/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs new file mode 100644 index 0000000..2b46b0c --- /dev/null +++ b/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Linq; +using Tyche.DataAccess.MsSql.Context; +using Tyche.DataAccess.MsSql.Entities; +using Tyche.DataAccess.MsSql.Infrastructure; +using Tyche.Domain.Interfaces; +using Tyche.Domain.Models; + + +namespace Tyche.DataAccess.MsSql.Repository +{ + public class DeckRepository : IDeckRepository + { + private readonly DeckContext _context; + private readonly Automapper _automapper = new Automapper(); + + public DeckRepository(DeckContext context) + { + _context = context; + } + + public void Add(Deck deck) + { + if (deck == null) return; + + var deckEntity = _automapper.MappingToDeckEntity(deck); + + _context.Add(deckEntity); + _context.SaveChanges(); + } + + public void Delete(Suit suit) + { + throw new System.NotImplementedException(); + } + + public Deck[] Get() + { + var decksEntity = _context.Decks.ToList(); + return new Deck[] { }; + } + + public Deck GetDeck(Suit suit) + { + var cardsEntity = _context.Cards.Where(x => x.Suit == suit.ToString()).ToArray(); + if (cardsEntity.Length == 0) return null; + + var deckEntity = new DeckEntity + { + Deck = cardsEntity, + Suit = suit.ToString() + }; + + var deck = _automapper.MappingToDeck(deckEntity); + return deck; + } + + public string[] GetDecksSuit() + { + var decksEntity = _context.Decks.ToList(); + var decks = new List(); + + foreach (var deck in decksEntity) + { + decks.Add(deck.Suit); + } + return decks.ToArray(); + } + + public void Update(Deck deck) + { + throw new System.NotImplementedException(); + } + } +} diff --git a/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj b/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj index aefaff0..d066449 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj +++ b/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj @@ -4,6 +4,19 @@ net5.0 + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs b/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs new file mode 100644 index 0000000..7dae2aa --- /dev/null +++ b/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs @@ -0,0 +1,20 @@ + +using Tyche.Domain.Models; + +namespace Tyche.Domain.Interfaces +{ + public interface IDeckRepository + { + void Add(Deck deck); + + void Update(Deck deck); + + void Delete(Suit suit); + + Deck GetDeck(Suit suit); + + Deck[] Get(); + + string[] GetDecksSuit(); + } +} diff --git a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs index da74af5..8fd484f 100644 --- a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs +++ b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs @@ -5,8 +5,16 @@ namespace Tyche.Domain.Interfaces { public interface IDeckService { - Deck GetNamedDeck(int suit); + public string CreateNamedDeck(Suit suit); - string CreateNamedDeck(Suit suit); + public Deck GetDeckBySuit(Suit suit); + + public Deck[] GetDecks(); + + public string[] GetCreatedDecksSuits(); + + public string DeleteDeckBySuit(Suit suit); + + public string ShuffleDeckBySuit(Suit suit, int sortOption); } } diff --git a/Tyche/Tyche.Domain/Models/Card.cs b/Tyche/Tyche.Domain/Models/Card.cs index 999c669..cef7d09 100644 --- a/Tyche/Tyche.Domain/Models/Card.cs +++ b/Tyche/Tyche.Domain/Models/Card.cs @@ -3,10 +3,19 @@ namespace Tyche.Domain.Models { public class Card { - public int Id { get; set; } + public Rank Rank { get; } - public Rank Rank { get; set; } + public Suit Suit { get; } - public Suit Suit { get; set; } + public Card(Rank rank, Suit suit) + { + Rank = rank; + Suit = suit; + } + + public override string ToString() + { + return $"{Rank.ToString()};{Suit.ToString()}"; + } } } diff --git a/Tyche/Tyche.Domain/Models/Deck.cs b/Tyche/Tyche.Domain/Models/Deck.cs index c7a5d89..e4ca074 100644 --- a/Tyche/Tyche.Domain/Models/Deck.cs +++ b/Tyche/Tyche.Domain/Models/Deck.cs @@ -8,20 +8,24 @@ public class Deck { private Stack _cards; - public int Id { get; set; } + public Stack Cards { get { return _cards; } } - public Suit Name { get; set; } + public int Count { get; private set; } + + public Suit Suit { get; set; } public Deck(Card[] cards) { if (cards == null || cards.Length == 0) throw new ArgumentException(nameof(cards)); + Count = cards.Length; _cards = new Stack(cards); } public Card Pull() { + Count = _cards.Count - 1; return _cards.Pop(); } } diff --git a/Tyche/Tyche.sln b/Tyche/Tyche.sln index 178f6df..dd8ca80 100644 --- a/Tyche/Tyche.sln +++ b/Tyche/Tyche.sln @@ -9,12 +9,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.Domain", "Tyche.Domai EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.BusinessLogic", "Tyche.BusinessLogic\Tyche.BusinessLogic.csproj", "{5FC62F53-A220-4483-A965-12B214712FF8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.DataAccess.MsSql", "Tyche.DataAccess.Postgres\Tyche.DataAccess.MsSql.csproj", "{67AB4D45-4003-42C5-99DA-CD7361ECCB58}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.UnitTests", "Tyche.UnitTests\Tyche.UnitTests.csproj", "{80151682-6D95-4A4F-8D30-C370E9FEC971}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.IntegrationTests", "Tyche.IntegrationTests\Tyche.IntegrationTests.csproj", "{45CEE789-234D-4ED9-A11C-8876D4C5DDB5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tyche.DataAccess.MsSql", "Tyche.DataAccess.MsSql\Tyche.DataAccess.MsSql.csproj", "{DF99F54A-0C13-47AC-BF39-06183CD40417}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,10 +33,6 @@ Global {5FC62F53-A220-4483-A965-12B214712FF8}.Debug|Any CPU.Build.0 = Debug|Any CPU {5FC62F53-A220-4483-A965-12B214712FF8}.Release|Any CPU.ActiveCfg = Release|Any CPU {5FC62F53-A220-4483-A965-12B214712FF8}.Release|Any CPU.Build.0 = Release|Any CPU - {67AB4D45-4003-42C5-99DA-CD7361ECCB58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {67AB4D45-4003-42C5-99DA-CD7361ECCB58}.Debug|Any CPU.Build.0 = Debug|Any CPU - {67AB4D45-4003-42C5-99DA-CD7361ECCB58}.Release|Any CPU.ActiveCfg = Release|Any CPU - {67AB4D45-4003-42C5-99DA-CD7361ECCB58}.Release|Any CPU.Build.0 = Release|Any CPU {80151682-6D95-4A4F-8D30-C370E9FEC971}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80151682-6D95-4A4F-8D30-C370E9FEC971}.Debug|Any CPU.Build.0 = Debug|Any CPU {80151682-6D95-4A4F-8D30-C370E9FEC971}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -45,6 +41,10 @@ Global {45CEE789-234D-4ED9-A11C-8876D4C5DDB5}.Debug|Any CPU.Build.0 = Debug|Any CPU {45CEE789-234D-4ED9-A11C-8876D4C5DDB5}.Release|Any CPU.ActiveCfg = Release|Any CPU {45CEE789-234D-4ED9-A11C-8876D4C5DDB5}.Release|Any CPU.Build.0 = Release|Any CPU + {DF99F54A-0C13-47AC-BF39-06183CD40417}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF99F54A-0C13-47AC-BF39-06183CD40417}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF99F54A-0C13-47AC-BF39-06183CD40417}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF99F54A-0C13-47AC-BF39-06183CD40417}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 3460307d40fa6e8ee0ed00f6088ed0b1693ab93a Mon Sep 17 00:00:00 2001 From: "includingivansmirnov@gmail.com" Date: Tue, 3 May 2022 20:23:00 +0500 Subject: [PATCH 02/15] Implement functionality for Deck CRUD #2 + Implement functionality for Service --- Tyche/Tyche.API/Controllers/DeckController.cs | 129 +++++++++++++++--- Tyche/Tyche.API/Infrastructure/Automapper.cs | 27 ++++ Tyche/Tyche.API/Models/DeckRequest.cs | 15 ++ Tyche/Tyche.API/Models/DeckResponse.cs | 10 ++ Tyche/Tyche.API/Models/DeckRespose.cs | 13 -- Tyche/Tyche.API/Models/ShuffleRequest.cs | 11 ++ Tyche/Tyche.API/Startup.cs | 5 +- Tyche/Tyche.API/Tyche.API.csproj | 10 ++ Tyche/Tyche.API/Tyche.API.xml | 53 +++++++ .../Infrasturcure/CardShuffler.cs | 39 ++++++ .../Services/DeckService.cs | 103 ++++++++++---- .../Entities/CardEntity.cs | 6 + .../Entities/DeckEntity.cs | 5 +- .../Infrastructure/Automapper.cs | 31 ++--- ...er.cs => 20220503144457_First.Designer.cs} | 16 ++- ...70054_First.cs => 20220503144457_First.cs} | 7 +- .../Migrations/DeckContextModelSnapshot.cs | 14 +- .../Repository/DeckRepository.cs | 78 +++++++---- .../Interfaces/IDeckRepository.cs | 14 +- Tyche/Tyche.Domain/Interfaces/IDeckService.cs | 14 +- Tyche/Tyche.Domain/Models/Card.cs | 10 +- Tyche/Tyche.Domain/Models/Deck.cs | 5 +- Tyche/Tyche.Domain/Models/DeckType.cs | 9 ++ Tyche/Tyche.Domain/Models/Rank.cs | 21 +-- Tyche/Tyche.sln | 2 +- Tyche/Tyche/Tyche.API/Tyche.API.xml | 52 +++++++ 26 files changed, 538 insertions(+), 161 deletions(-) create mode 100644 Tyche/Tyche.API/Infrastructure/Automapper.cs create mode 100644 Tyche/Tyche.API/Models/DeckRequest.cs create mode 100644 Tyche/Tyche.API/Models/DeckResponse.cs delete mode 100644 Tyche/Tyche.API/Models/DeckRespose.cs create mode 100644 Tyche/Tyche.API/Models/ShuffleRequest.cs create mode 100644 Tyche/Tyche.API/Tyche.API.xml create mode 100644 Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs rename Tyche/Tyche.DataAccess.MsSql/Migrations/{20220502170054_First.Designer.cs => 20220503144457_First.Designer.cs} (84%) rename Tyche/Tyche.DataAccess.MsSql/Migrations/{20220502170054_First.cs => 20220503144457_First.cs} (88%) create mode 100644 Tyche/Tyche.Domain/Models/DeckType.cs create mode 100644 Tyche/Tyche/Tyche.API/Tyche.API.xml diff --git a/Tyche/Tyche.API/Controllers/DeckController.cs b/Tyche/Tyche.API/Controllers/DeckController.cs index 0d4af1c..949ed35 100644 --- a/Tyche/Tyche.API/Controllers/DeckController.cs +++ b/Tyche/Tyche.API/Controllers/DeckController.cs @@ -1,50 +1,137 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; using System; +using System.Collections.Generic; +using Tyche.API.Infrastructure; +using Tyche.API.Models; using Tyche.Domain.Interfaces; -using Tyche.Domain.Models; + namespace Tyche.API.Controllers { + /// + /// Controller for creating, receiving, working with a deck of cards + /// [ApiController] [Route("[controller]")] public class DeckController : ControllerBase { private readonly IDeckService _deckService; + private readonly Automapper _automapper = new Automapper(); public DeckController(IDeckService deckService) { _deckService = deckService; } + /// + /// Create a named deck of cards + /// + /// + /// [HttpPost] - public IActionResult Create(string suitRequest) + public IActionResult Create(DeckRequest request) { - if (Enum.TryParse(suitRequest, out var suit)) + try { - try - { - var response = _deckService.CreateNamedDeck(suit); - return Ok(response); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } + var response = _deckService.CreateNamedDeck(request.Name, request.DeckType); + return Ok(response); + } + catch (Exception ex) + { + return BadRequest(ex.Message); } - - return BadRequest($"Suit can be only \"Spades\", \"Clubs\", \"Hearts\", \"Diamonds\"; But you try enter suit - \"{suitRequest}\""); } - [HttpGet("{suitRequest}")] - public ActionResult Get(string suitRequest) + /// + /// Getting a deck of cards by name + /// + /// + /// + [HttpGet("{name}")] + public ActionResult GetDeckByName(string name) { - if (Enum.TryParse(suitRequest, out var suit)) + + var deck = _deckService.GetDeckByName(name); + if (deck != null) { - var response = _deckService.GetDeckBySuit(suit); + var response = _automapper.MappingToDeckResponse(deck); return Ok(response); } - return BadRequest($"Suit can be only \"Spades\", \"Clubs\", \"Hearts\", \"Diamonds\"; But you try enter suit - \"{suitRequest}\""); + else + { + return Ok($"Have no decks of cards {name}"); + } + } + + /// + /// Get a list of deck names + /// + /// + [HttpGet("Names/")] + public IActionResult GetNames() + { + var names = _deckService.GetCreatedDecksNames(); + if (names.Length != 0) + return Ok(names); + else + return Ok("No decks of cards"); + } + + /// + /// Getting a all decks of cards + /// + /// + [HttpGet("Decks/")] + public ActionResult GetDecks() + { + var decks = _deckService.GetDecks(); + if (decks != null) + { + var response = new List(); + + foreach (var deck in decks) + { + response.Add(_automapper.MappingToDeckResponse(deck)); + } + return Ok(response.ToArray()); + } + else + return Ok("No decks of cards"); } + + /// + /// Deleting a deck of cards by name + /// + /// + [HttpDelete("ByNames/")] + public IActionResult Delete(string name) + { + var response = _deckService.DeleteDeckByName(name); + return Ok(response); + } + + /// + /// Deleting all deck of cards + /// + /// + /// + [HttpDelete("Decks/")] + public IActionResult Delete() + { + var response = _deckService.DeleteDecks(); + return Ok(response); + } + + /// + /// Shuffle dekcs of cards in the selected way + /// + /// + /// + //[HttpPut("Shuffle/")] + //public IActionResult Update(ShuffleRequest request) + //{ + // var response = _deckService.ShuffleDeckBySuit(request.SortOption); + // return Ok(response); + //} } } diff --git a/Tyche/Tyche.API/Infrastructure/Automapper.cs b/Tyche/Tyche.API/Infrastructure/Automapper.cs new file mode 100644 index 0000000..a4735d5 --- /dev/null +++ b/Tyche/Tyche.API/Infrastructure/Automapper.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Tyche.API.Models; +using Tyche.Domain.Models; + +namespace Tyche.API.Infrastructure +{ + internal class Automapper + { + public DeckResponse MappingToDeckResponse(Deck deck) + { + var cards = deck.Cards; + var cardsResponse = new List(); + + foreach (var card in cards) + { + var cardResponse = $"{card.SequenceNumber};{card.Rank.ToString()};{card.Suit.ToString()}"; + cardsResponse.Add(cardResponse); + } + + return new DeckResponse + { + Cards = cardsResponse.ToArray(), + Name = deck.Name + }; + } + } +} diff --git a/Tyche/Tyche.API/Models/DeckRequest.cs b/Tyche/Tyche.API/Models/DeckRequest.cs new file mode 100644 index 0000000..b5590c2 --- /dev/null +++ b/Tyche/Tyche.API/Models/DeckRequest.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; +using Tyche.Domain.Models; + +namespace Tyche.API.Models +{ + public class DeckRequest + { + [Required] + [StringLength(50, MinimumLength = 3, ErrorMessage = "Name length must be in the family from {2}-{1} characters")] + public string Name { get; set; } + + [Required] + public DeckType DeckType { get; set; } + } +} diff --git a/Tyche/Tyche.API/Models/DeckResponse.cs b/Tyche/Tyche.API/Models/DeckResponse.cs new file mode 100644 index 0000000..eccdf6f --- /dev/null +++ b/Tyche/Tyche.API/Models/DeckResponse.cs @@ -0,0 +1,10 @@ + +namespace Tyche.API.Models +{ + public class DeckResponse + { + public string[] Cards { get; set; } + + public string Name { get; set; } + } +} diff --git a/Tyche/Tyche.API/Models/DeckRespose.cs b/Tyche/Tyche.API/Models/DeckRespose.cs deleted file mode 100644 index e55ebaf..0000000 --- a/Tyche/Tyche.API/Models/DeckRespose.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Tyche.API.Models -{ - public class DeckRespose - { - - } -} diff --git a/Tyche/Tyche.API/Models/ShuffleRequest.cs b/Tyche/Tyche.API/Models/ShuffleRequest.cs new file mode 100644 index 0000000..e6f0845 --- /dev/null +++ b/Tyche/Tyche.API/Models/ShuffleRequest.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; + + +namespace Tyche.API.Models +{ + public class ShuffleRequest + { + [Range(1, 2)] + public int SortOption { get; set; } + } +} diff --git a/Tyche/Tyche.API/Startup.cs b/Tyche/Tyche.API/Startup.cs index e2f340c..3aa2d79 100644 --- a/Tyche/Tyche.API/Startup.cs +++ b/Tyche/Tyche.API/Startup.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; +using System.IO; using Tyche.BusinessLogic.Services; using Tyche.DataAccess.MsSql.Context; using Tyche.DataAccess.MsSql.Repository; @@ -35,7 +36,9 @@ public void ConfigureServices(IServiceCollection services) services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Tyche.API", Version = "v1" }); - }); + var filePath = Path.Combine(System.AppContext.BaseDirectory, "Tyche.API.xml"); + c.IncludeXmlComments(filePath); + }); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) diff --git a/Tyche/Tyche.API/Tyche.API.csproj b/Tyche/Tyche.API/Tyche.API.csproj index 7c3b5a5..47713c4 100644 --- a/Tyche/Tyche.API/Tyche.API.csproj +++ b/Tyche/Tyche.API/Tyche.API.csproj @@ -2,6 +2,16 @@ net5.0 + True + ..\\Tyche\Tyche.API\Tyche.API.xml + + + + 1701;1702;1591; + + + + 1701;1702;1591; diff --git a/Tyche/Tyche.API/Tyche.API.xml b/Tyche/Tyche.API/Tyche.API.xml new file mode 100644 index 0000000..d2eadbb --- /dev/null +++ b/Tyche/Tyche.API/Tyche.API.xml @@ -0,0 +1,53 @@ + + + + Tyche.API + + + + + Controller for creating, receiving, working with a deck of cards + + + + + Create a named deck of cards + + + + + + + Getting a deck of cards by suit + + + + + + + Get a list of deck names + + + + + + Getting a all decks of cards + + + + + + Deleting a deck of cards by suit + + + + + + + Shuffle a named deck of cards in the selected way + + + + + + diff --git a/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs b/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs new file mode 100644 index 0000000..9114735 --- /dev/null +++ b/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Tyche.Domain.Models; + + +namespace Tyche.BusinessLogic.Infrasturcure +{ + internal class CardShuffler + { + protected static Random _random = new Random(); + + //public Deck SimpleShuffle(Deck[] decks) + //{ + // var count = 0; + + // foreach (var deck in decks) + // { + // count+=deck.Count; + // } + + // int[] randomRanks = Enumerable.Range(0, count) + // .OrderBy(n => _random.Next(0, count)) + // .ToArray(); + + // List cards = new List(); + + // foreach (var rank in randomRanks) + // { + // if (Enum.IsDefined(typeof(Rank), rank)) + // { + // cards.Add(new Card((Rank)rank, suit)); + // } + // } + + // return new Deck(cards.ToArray()); + //} + } +} diff --git a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs index 6b44032..e9c9885 100644 --- a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs +++ b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Tyche.BusinessLogic.Infrasturcure; using Tyche.Domain.Interfaces; using Tyche.Domain.Models; @@ -8,32 +9,28 @@ namespace Tyche.BusinessLogic.Services { public class DeckService : IDeckService { + private const int SIMPLE_SHUFFLING = 1; + private const int ASCENDING_ORDER = 2; + private readonly IDeckRepository _deckRepository; + private readonly CardShuffler _cardShuffler = new CardShuffler(); public DeckService(IDeckRepository deckRepository) { _deckRepository = deckRepository; } - public string CreateNamedDeck(Suit suit) + public string CreateNamedDeck(string name, DeckType deckType) { try { - var existingDecks = GetCreatedDecksSuits(); - - if (existingDecks.Length != 0) - { - foreach (var existingSuit in existingDecks) - { - if (existingSuit == suit.ToString()) - return "Deck already exists"; - } - } + var existingDeck = GetDeckByName(name); + if (existingDeck != null) return $"Deck this name {name} already exists"; - var cards = GetCardsArray(suit); - var deck = new Deck(cards); + var cards = GetCardsArray(deckType); + var deck = new Deck(cards, name); - _deckRepository.Add(deck); + _deckRepository.Add(deck, name); return "Success created"; } catch (Exception ex) @@ -42,47 +39,95 @@ public string CreateNamedDeck(Suit suit) } } - public Deck GetDeckBySuit(Suit suit) + public Deck GetDeckByName(string name) { - var deck = _deckRepository.GetDeck(suit); + var deck = _deckRepository.GetDeck(name); return deck; } + public string[] GetCreatedDecksNames() + { + return _deckRepository.GetDecksNames(); + } + public Deck[] GetDecks() { - return new Deck[] { }; + return _deckRepository.GetDecks(); } - public string[] GetCreatedDecksSuits() + public string DeleteDeckByName(string name) { - return _deckRepository.GetDecksSuit(); + try + { + var existingDeck = GetDeckByName(name); + if (existingDeck != null) + { + _deckRepository.Delete(name); + return "Success deleted"; + } + else + return "This deck was not created"; + } + catch (Exception ex) + { + return ex.Message; + } } - public string DeleteDeckBySuit(Suit suit) + public string DeleteDecks() { + var decks = _deckRepository.GetDecks(); + if (decks == null) return "Decks was not created"; + + _deckRepository.DeleteDecks(); return "Success deleted"; } - public string ShuffleDeckBySuit(Suit suit, int sortOption) + public string ShuffleDeckBySuit(int sortOption) { - return "Successfully shuffled"; + var existingDecks = GetDecks(); + if (existingDecks != null) + { + switch (sortOption) + { + case SIMPLE_SHUFFLING: + break; + case ASCENDING_ORDER: + break; + default: + break; + } + return "Successfully shuffled"; + } + else + return "This decks was not created"; } - private void Update() + private void UpdateDeck(Suit suit, Deck deck) { } - private Card[] GetCardsArray(Suit suit) + private Card[] GetCardsArray(DeckType deckType) { - List listCards = new List(); + var cards = new List(); + var sequenceNumber = 1; - foreach (Rank rank in Enum.GetValues(typeof(Rank))) + foreach (Suit suit in Enum.GetValues(typeof(Suit))) { - listCards.Add(new Card(rank, suit)); - } + foreach (Rank rank in Enum.GetValues(typeof(Rank))) + { + if (deckType == DeckType.SmalDeck) + { + if (rank < Rank.Six) + continue; + } - return listCards.ToArray(); + cards.Add(new Card(rank, suit, sequenceNumber)); + sequenceNumber++; + } + } + return cards.ToArray(); } } } diff --git a/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs b/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs index 053b684..5d27e56 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs @@ -1,12 +1,18 @@  +using System.ComponentModel.DataAnnotations; + namespace Tyche.DataAccess.MsSql.Entities { public class CardEntity { public int Id { get; set; } + public int SequenceNumber { get; set; } + + [StringLength(20)] public string Rank { get; set; } + [StringLength(20)] public string Suit { get; set; } public int DeckId { get; set; } diff --git a/Tyche/Tyche.DataAccess.MsSql/Entities/DeckEntity.cs b/Tyche/Tyche.DataAccess.MsSql/Entities/DeckEntity.cs index b537743..2c8d189 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Entities/DeckEntity.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Entities/DeckEntity.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; - +using System.ComponentModel.DataAnnotations; namespace Tyche.DataAccess.MsSql.Entities { @@ -7,7 +7,8 @@ public class DeckEntity { public int Id { get; set; } - public string Suit { get; set; } + [StringLength(50, MinimumLength = 3)] + public string Name { get; set; } public ICollection Deck { get; set; } } diff --git a/Tyche/Tyche.DataAccess.MsSql/Infrastructure/Automapper.cs b/Tyche/Tyche.DataAccess.MsSql/Infrastructure/Automapper.cs index 67a0bbe..e4a7d74 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Infrastructure/Automapper.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Infrastructure/Automapper.cs @@ -6,48 +6,47 @@ namespace Tyche.DataAccess.MsSql.Infrastructure { - public class Automapper + internal class Automapper { - public DeckEntity MappingToDeckEntity(Deck deck) + public DeckEntity MappingToDeckEntity(Deck deck, string name) { var cards = new List(); - while (deck.Count > 0) + foreach (var card in deck.Cards) { - var card = deck.Pull(); var cardEntity = new CardEntity { Rank = card.Rank.ToString(), - Suit = card.Suit.ToString() + Suit = card.Suit.ToString(), + SequenceNumber = card.SequenceNumber }; cards.Add(cardEntity); } - var suit = deck.Suit.ToString(); - return new DeckEntity { - Suit = suit, + Name = name, Deck = cards.ToArray() }; } - public Deck MappingToDeck(DeckEntity deckEntity) + public Deck MappingToDeck(DeckEntity deckEntity, string name) { var cards = new List(); var decks = deckEntity.Deck; + var sequenceNumber = 1; - foreach (var item in decks) + foreach (var deck in decks) { - var rank = (Rank)Enum.Parse(typeof(Rank), item.Rank); - var suit = (Suit)Enum.Parse(typeof(Suit), item.Suit); - - var card = new Card(rank, suit); - + var rank = (Rank)Enum.Parse(typeof(Rank), deck.Rank); + var suit = (Suit)Enum.Parse(typeof(Suit), deck.Suit); + + var card = new Card(rank, suit, deck.SequenceNumber); + sequenceNumber++; cards.Add(card); } - return new Deck(cards.ToArray()); + return new Deck(cards.ToArray(), name); } } } diff --git a/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.Designer.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.Designer.cs similarity index 84% rename from Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.Designer.cs rename to Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.Designer.cs index 02026b2..e04d7ae 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.Designer.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.Designer.cs @@ -9,7 +9,7 @@ namespace Tyche.DataAccess.MsSql.Migrations { [DbContext(typeof(DeckContext))] - [Migration("20220502170054_First")] + [Migration("20220503144457_First")] partial class First { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -31,10 +31,15 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("int"); b.Property("Rank") - .HasColumnType("nvarchar(max)"); + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("SequenceNumber") + .HasColumnType("int"); b.Property("Suit") - .HasColumnType("nvarchar(max)"); + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); b.HasKey("Id"); @@ -50,8 +55,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("int") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("Suit") - .HasColumnType("nvarchar(max)"); + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); b.HasKey("Id"); diff --git a/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.cs similarity index 88% rename from Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.cs rename to Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.cs index 2dc9e0f..be7e41c 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Migrations/20220502170054_First.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.cs @@ -12,7 +12,7 @@ protected override void Up(MigrationBuilder migrationBuilder) { Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - Suit = table.Column(type: "nvarchar(max)", nullable: true) + Name = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: true) }, constraints: table => { @@ -25,8 +25,9 @@ protected override void Up(MigrationBuilder migrationBuilder) { Id = table.Column(type: "int", nullable: false) .Annotation("SqlServer:Identity", "1, 1"), - Rank = table.Column(type: "nvarchar(max)", nullable: true), - Suit = table.Column(type: "nvarchar(max)", nullable: true), + SequenceNumber = table.Column(type: "int", nullable: false), + Rank = table.Column(type: "nvarchar(20)", maxLength: 20, nullable: true), + Suit = table.Column(type: "nvarchar(20)", maxLength: 20, nullable: true), DeckId = table.Column(type: "int", nullable: false) }, constraints: table => diff --git a/Tyche/Tyche.DataAccess.MsSql/Migrations/DeckContextModelSnapshot.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/DeckContextModelSnapshot.cs index 822a630..339f470 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Migrations/DeckContextModelSnapshot.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/DeckContextModelSnapshot.cs @@ -29,10 +29,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("int"); b.Property("Rank") - .HasColumnType("nvarchar(max)"); + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("SequenceNumber") + .HasColumnType("int"); b.Property("Suit") - .HasColumnType("nvarchar(max)"); + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); b.HasKey("Id"); @@ -48,8 +53,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("int") .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); - b.Property("Suit") - .HasColumnType("nvarchar(max)"); + b.Property("Name") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); b.HasKey("Id"); diff --git a/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs b/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs index 2b46b0c..10d28bd 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Tyche.DataAccess.MsSql.Context; -using Tyche.DataAccess.MsSql.Entities; using Tyche.DataAccess.MsSql.Infrastructure; using Tyche.Domain.Interfaces; using Tyche.Domain.Models; @@ -19,57 +19,81 @@ public DeckRepository(DeckContext context) _context = context; } - public void Add(Deck deck) + public void Add(Deck deck, string name) { if (deck == null) return; - var deckEntity = _automapper.MappingToDeckEntity(deck); + if (String.IsNullOrWhiteSpace(name)) return; + + var deckEntity = _automapper.MappingToDeckEntity(deck, name); _context.Add(deckEntity); _context.SaveChanges(); } - public void Delete(Suit suit) + public Deck GetDeck(string name) { - throw new System.NotImplementedException(); - } + var deckEntity = _context.Decks.FirstOrDefault(deck => deck.Name == name); + if (deckEntity == null) return null; - public Deck[] Get() - { - var decksEntity = _context.Decks.ToList(); - return new Deck[] { }; + deckEntity.Deck = _context.Cards.Where(card => card.DeckId == deckEntity.Id).OrderByDescending(card => card.SequenceNumber).ToArray(); + + var deck = _automapper.MappingToDeck(deckEntity, name); + return deck; } - public Deck GetDeck(Suit suit) + public string[] GetDecksNames() { - var cardsEntity = _context.Cards.Where(x => x.Suit == suit.ToString()).ToArray(); - if (cardsEntity.Length == 0) return null; + var decksEntity = _context.Decks.ToList(); + var decks = new List(); - var deckEntity = new DeckEntity + foreach (var deck in decksEntity) { - Deck = cardsEntity, - Suit = suit.ToString() - }; - - var deck = _automapper.MappingToDeck(deckEntity); - return deck; + decks.Add(deck.Name); + } + return decks.ToArray(); } - public string[] GetDecksSuit() + public Deck[] GetDecks() { var decksEntity = _context.Decks.ToList(); - var decks = new List(); + if (decksEntity.Count == 0) return null; + + foreach (var deckEntity in decksEntity) + { + deckEntity.Deck = _context.Cards.Where(card => card.DeckId == deckEntity.Id).OrderByDescending(card => card.SequenceNumber).ToArray(); + } + + var decksResponse = new List(); foreach (var deck in decksEntity) { - decks.Add(deck.Suit); + decksResponse.Add(_automapper.MappingToDeck(deck, deck.Name)); } - return decks.ToArray(); + + return decksResponse.ToArray(); } - public void Update(Deck deck) + public void Delete(string name) { - throw new System.NotImplementedException(); + var deck = _context.Decks.FirstOrDefault(deck => deck.Name == name); + _context.Decks.Remove(deck); + + var cardsEntity = _context.Cards.Where(card => card.DeckId == deck.Id).ToArray(); + _context.Cards.RemoveRange(cardsEntity); + + _context.SaveChanges(); + } + + public void DeleteDecks() + { + var decksEntity = _context.Decks.ToList(); + if (decksEntity.Count == 0) return; + + foreach (var deckEntity in decksEntity) + { + Delete(deckEntity.Name); + } } } } diff --git a/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs b/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs index 7dae2aa..24538e6 100644 --- a/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs +++ b/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs @@ -5,16 +5,16 @@ namespace Tyche.Domain.Interfaces { public interface IDeckRepository { - void Add(Deck deck); + void Add(Deck deck, string name); - void Update(Deck deck); + void Delete(string name); - void Delete(Suit suit); + Deck GetDeck(string name); - Deck GetDeck(Suit suit); + Deck[] GetDecks(); - Deck[] Get(); - - string[] GetDecksSuit(); + string[] GetDecksNames(); + + void DeleteDecks(); } } diff --git a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs index 8fd484f..0e64ef6 100644 --- a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs +++ b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs @@ -5,16 +5,18 @@ namespace Tyche.Domain.Interfaces { public interface IDeckService { - public string CreateNamedDeck(Suit suit); + string CreateNamedDeck(string name, DeckType deckType); - public Deck GetDeckBySuit(Suit suit); + Deck GetDeckByName(string name); - public Deck[] GetDecks(); + Deck[] GetDecks(); - public string[] GetCreatedDecksSuits(); + string[] GetCreatedDecksNames(); - public string DeleteDeckBySuit(Suit suit); + string DeleteDeckByName(string name); - public string ShuffleDeckBySuit(Suit suit, int sortOption); + string ShuffleDeckBySuit(int sortOption); + + string DeleteDecks(); } } diff --git a/Tyche/Tyche.Domain/Models/Card.cs b/Tyche/Tyche.Domain/Models/Card.cs index cef7d09..9a8d0b0 100644 --- a/Tyche/Tyche.Domain/Models/Card.cs +++ b/Tyche/Tyche.Domain/Models/Card.cs @@ -3,19 +3,17 @@ namespace Tyche.Domain.Models { public class Card { + public int SequenceNumber { get; } + public Rank Rank { get; } public Suit Suit { get; } - public Card(Rank rank, Suit suit) + public Card(Rank rank, Suit suit, int sequenceNumber) { Rank = rank; Suit = suit; - } - - public override string ToString() - { - return $"{Rank.ToString()};{Suit.ToString()}"; + SequenceNumber = sequenceNumber; } } } diff --git a/Tyche/Tyche.Domain/Models/Deck.cs b/Tyche/Tyche.Domain/Models/Deck.cs index e4ca074..87a0cd1 100644 --- a/Tyche/Tyche.Domain/Models/Deck.cs +++ b/Tyche/Tyche.Domain/Models/Deck.cs @@ -12,15 +12,16 @@ public class Deck public int Count { get; private set; } - public Suit Suit { get; set; } + public string Name { get; private set; } - public Deck(Card[] cards) + public Deck(Card[] cards, string name) { if (cards == null || cards.Length == 0) throw new ArgumentException(nameof(cards)); Count = cards.Length; _cards = new Stack(cards); + Name = name; } public Card Pull() diff --git a/Tyche/Tyche.Domain/Models/DeckType.cs b/Tyche/Tyche.Domain/Models/DeckType.cs new file mode 100644 index 0000000..c36bbf4 --- /dev/null +++ b/Tyche/Tyche.Domain/Models/DeckType.cs @@ -0,0 +1,9 @@ + +namespace Tyche.Domain.Models +{ + public enum DeckType + { + StandartDeck = 52, + SmalDeck = 36 + } +} diff --git a/Tyche/Tyche.Domain/Models/Rank.cs b/Tyche/Tyche.Domain/Models/Rank.cs index d97fffb..8f0ab6b 100644 --- a/Tyche/Tyche.Domain/Models/Rank.cs +++ b/Tyche/Tyche.Domain/Models/Rank.cs @@ -1,35 +1,20 @@ -using System.ComponentModel.DataAnnotations; - - + namespace Tyche.Domain.Models { public enum Rank { - [Display(Name = "Ace")] - Ace, - [Display(Name = "2")] Two, - [Display(Name = "3")] Three, - [Display(Name = "4")] Four, - [Display(Name = "5")] Five, - [Display(Name = "6")] Six, - [Display(Name = "7")] Seven, - [Display(Name = "8")] Eight, - [Display(Name = "9")] Nine, - [Display(Name = "10")] Ten, - [Display(Name = "Jack")] Jack, - [Display(Name = "Queen")] Queen, - [Display(Name = "King")] - King + King, + Ace } } diff --git a/Tyche/Tyche.sln b/Tyche/Tyche.sln index dd8ca80..8ea74b7 100644 --- a/Tyche/Tyche.sln +++ b/Tyche/Tyche.sln @@ -13,7 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.UnitTests", "Tyche.Un EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.IntegrationTests", "Tyche.IntegrationTests\Tyche.IntegrationTests.csproj", "{45CEE789-234D-4ED9-A11C-8876D4C5DDB5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tyche.DataAccess.MsSql", "Tyche.DataAccess.MsSql\Tyche.DataAccess.MsSql.csproj", "{DF99F54A-0C13-47AC-BF39-06183CD40417}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.DataAccess.MsSql", "Tyche.DataAccess.MsSql\Tyche.DataAccess.MsSql.csproj", "{DF99F54A-0C13-47AC-BF39-06183CD40417}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Tyche/Tyche/Tyche.API/Tyche.API.xml b/Tyche/Tyche/Tyche.API/Tyche.API.xml new file mode 100644 index 0000000..63823fe --- /dev/null +++ b/Tyche/Tyche/Tyche.API/Tyche.API.xml @@ -0,0 +1,52 @@ + + + + Tyche.API + + + + + Controller for creating, receiving, working with a deck of cards + + + + + Create a named deck of cards + + + + + + + Getting a deck of cards by name + + + + + + + Get a list of deck names + + + + + + Getting a all decks of cards + + + + + + Deleting a deck of cards by name + + + + + + Deleting all deck of cards + + + + + + From cfd13c10fc9bcd96130f2cebf93e0434a19819d8 Mon Sep 17 00:00:00 2001 From: "includingivansmirnov@gmail.com" Date: Tue, 3 May 2022 21:08:54 +0500 Subject: [PATCH 03/15] Create a deck shuffling method #5 --- Tyche/Tyche.API/Controllers/DeckController.cs | 12 +++--- Tyche/Tyche.API/Models/ShuffleRequest.cs | 3 ++ .../Infrasturcure/CardShuffler.cs | 41 ++++++++----------- .../Services/DeckService.cs | 16 +++++--- Tyche/Tyche.Domain/Interfaces/IDeckService.cs | 2 +- Tyche/Tyche/Tyche.API/Tyche.API.xml | 7 ++++ 6 files changed, 44 insertions(+), 37 deletions(-) diff --git a/Tyche/Tyche.API/Controllers/DeckController.cs b/Tyche/Tyche.API/Controllers/DeckController.cs index 949ed35..366091b 100644 --- a/Tyche/Tyche.API/Controllers/DeckController.cs +++ b/Tyche/Tyche.API/Controllers/DeckController.cs @@ -127,11 +127,11 @@ public IActionResult Delete() /// /// /// - //[HttpPut("Shuffle/")] - //public IActionResult Update(ShuffleRequest request) - //{ - // var response = _deckService.ShuffleDeckBySuit(request.SortOption); - // return Ok(response); - //} + [HttpPut("Shuffle/")] + public IActionResult Update(ShuffleRequest request) + { + var response = _deckService.ShuffleDeckBySuit(request.SortOption, request.Name); + return Ok(response); + } } } diff --git a/Tyche/Tyche.API/Models/ShuffleRequest.cs b/Tyche/Tyche.API/Models/ShuffleRequest.cs index e6f0845..c61e6b0 100644 --- a/Tyche/Tyche.API/Models/ShuffleRequest.cs +++ b/Tyche/Tyche.API/Models/ShuffleRequest.cs @@ -7,5 +7,8 @@ public class ShuffleRequest { [Range(1, 2)] public int SortOption { get; set; } + + [StringLength(50, MinimumLength = 3, ErrorMessage = "Name length must be in the family from {2}-{1} characters")] + public string Name { get; set; } } } diff --git a/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs b/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs index 9114735..3f1abc1 100644 --- a/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs +++ b/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs @@ -10,30 +10,21 @@ internal class CardShuffler { protected static Random _random = new Random(); - //public Deck SimpleShuffle(Deck[] decks) - //{ - // var count = 0; - - // foreach (var deck in decks) - // { - // count+=deck.Count; - // } - - // int[] randomRanks = Enumerable.Range(0, count) - // .OrderBy(n => _random.Next(0, count)) - // .ToArray(); - - // List cards = new List(); - - // foreach (var rank in randomRanks) - // { - // if (Enum.IsDefined(typeof(Rank), rank)) - // { - // cards.Add(new Card((Rank)rank, suit)); - // } - // } - - // return new Deck(cards.ToArray()); - //} + public Deck SimpleShuffle(Deck deck) + { + var sequenceNumbersRandom = Enumerable.Range(1, deck.Count + 1) + .OrderBy(n => _random.Next(1, deck.Count + 1)) + .ToArray(); + + List cards = new List(); + var count = 0; + foreach (var card in deck.Cards) + { + cards.Add(new Card(card.Rank, card.Suit, sequenceNumbersRandom[count])); + count++; + } + + return new Deck(cards.ToArray(), deck.Name); + } } } diff --git a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs index e9c9885..74b8c39 100644 --- a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs +++ b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs @@ -83,18 +83,23 @@ public string DeleteDecks() return "Success deleted"; } - public string ShuffleDeckBySuit(int sortOption) + public string ShuffleDeckBySuit(int sortOption, string name) { - var existingDecks = GetDecks(); - if (existingDecks != null) + var existingDeck = GetDeckByName(name); + + if (existingDeck != null) { switch (sortOption) { case SIMPLE_SHUFFLING: + UpdateDeck(name, _cardShuffler.SimpleShuffle(existingDeck)); break; case ASCENDING_ORDER: + DeleteDeckByName(name); + CreateNamedDeck(name, (DeckType)existingDeck.Count); break; default: + UpdateDeck(name, _cardShuffler.SimpleShuffle(existingDeck)); break; } return "Successfully shuffled"; @@ -103,9 +108,10 @@ public string ShuffleDeckBySuit(int sortOption) return "This decks was not created"; } - private void UpdateDeck(Suit suit, Deck deck) + private void UpdateDeck(string name, Deck deck) { - + DeleteDeckByName(name); + _deckRepository.Add(deck, name); } private Card[] GetCardsArray(DeckType deckType) diff --git a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs index 0e64ef6..bedd020 100644 --- a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs +++ b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs @@ -15,7 +15,7 @@ public interface IDeckService string DeleteDeckByName(string name); - string ShuffleDeckBySuit(int sortOption); + string ShuffleDeckBySuit(int sortOption, string name); string DeleteDecks(); } diff --git a/Tyche/Tyche/Tyche.API/Tyche.API.xml b/Tyche/Tyche/Tyche.API/Tyche.API.xml index 63823fe..a033792 100644 --- a/Tyche/Tyche/Tyche.API/Tyche.API.xml +++ b/Tyche/Tyche/Tyche.API/Tyche.API.xml @@ -48,5 +48,12 @@ + + + Shuffle dekcs of cards in the selected way + + + + From 3bde66647e6adc1559652d38c6d84f8240b46572 Mon Sep 17 00:00:00 2001 From: "includingivansmirnov@gmail.com" Date: Tue, 3 May 2022 21:59:13 +0500 Subject: [PATCH 04/15] Make methods async #6 --- Tyche/Tyche.API/Controllers/DeckController.cs | 29 +++++----- .../Services/DeckService.cs | 58 ++++++++++--------- .../Repository/DeckRepository.cs | 52 ++++++++++------- .../Interfaces/IDeckRepository.cs | 15 ++--- Tyche/Tyche.Domain/Interfaces/IDeckService.cs | 17 +++--- 5 files changed, 94 insertions(+), 77 deletions(-) diff --git a/Tyche/Tyche.API/Controllers/DeckController.cs b/Tyche/Tyche.API/Controllers/DeckController.cs index 366091b..bc52993 100644 --- a/Tyche/Tyche.API/Controllers/DeckController.cs +++ b/Tyche/Tyche.API/Controllers/DeckController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; +using System.Threading.Tasks; using Tyche.API.Infrastructure; using Tyche.API.Models; using Tyche.Domain.Interfaces; @@ -29,11 +30,11 @@ public DeckController(IDeckService deckService) /// /// [HttpPost] - public IActionResult Create(DeckRequest request) + public async Task Create(DeckRequest request) { try { - var response = _deckService.CreateNamedDeck(request.Name, request.DeckType); + var response = await _deckService.CreateNamedDeckAsync(request.Name, request.DeckType); return Ok(response); } catch (Exception ex) @@ -48,10 +49,10 @@ public IActionResult Create(DeckRequest request) /// /// [HttpGet("{name}")] - public ActionResult GetDeckByName(string name) + public async Task> GetDeckByName(string name) { - var deck = _deckService.GetDeckByName(name); + var deck = await _deckService.GetDeckByNameAsync(name); if (deck != null) { var response = _automapper.MappingToDeckResponse(deck); @@ -68,9 +69,9 @@ public ActionResult GetDeckByName(string name) /// /// [HttpGet("Names/")] - public IActionResult GetNames() + public async Task GetNames() { - var names = _deckService.GetCreatedDecksNames(); + var names = await _deckService.GetCreatedDecksNamesAsync(); if (names.Length != 0) return Ok(names); else @@ -82,9 +83,9 @@ public IActionResult GetNames() /// /// [HttpGet("Decks/")] - public ActionResult GetDecks() + public async Task> GetDecks() { - var decks = _deckService.GetDecks(); + var decks = await _deckService.GetDecksAsync(); if (decks != null) { var response = new List(); @@ -104,9 +105,9 @@ public ActionResult GetDecks() /// /// [HttpDelete("ByNames/")] - public IActionResult Delete(string name) + public async Task Delete(string name) { - var response = _deckService.DeleteDeckByName(name); + var response = await _deckService.DeleteDeckByNameAsync(name); return Ok(response); } @@ -116,9 +117,9 @@ public IActionResult Delete(string name) /// /// [HttpDelete("Decks/")] - public IActionResult Delete() + public async Task Delete() { - var response = _deckService.DeleteDecks(); + var response = await _deckService.DeleteDecksAsync(); return Ok(response); } @@ -128,9 +129,9 @@ public IActionResult Delete() /// /// [HttpPut("Shuffle/")] - public IActionResult Update(ShuffleRequest request) + public async Task Update(ShuffleRequest request) { - var response = _deckService.ShuffleDeckBySuit(request.SortOption, request.Name); + var response = await _deckService.ShuffleDeckByNameAsync(request.SortOption, request.Name); return Ok(response); } } diff --git a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs index 74b8c39..85d5c72 100644 --- a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs +++ b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Tyche.BusinessLogic.Infrasturcure; using Tyche.Domain.Interfaces; using Tyche.Domain.Models; @@ -13,25 +14,28 @@ public class DeckService : IDeckService private const int ASCENDING_ORDER = 2; private readonly IDeckRepository _deckRepository; - private readonly CardShuffler _cardShuffler = new CardShuffler(); + private readonly CardShuffler _cardShuffler = new(); public DeckService(IDeckRepository deckRepository) { _deckRepository = deckRepository; } - public string CreateNamedDeck(string name, DeckType deckType) + public async Task CreateNamedDeckAsync(string name, DeckType deckType) { try { - var existingDeck = GetDeckByName(name); + var existingDeck = await GetDeckByNameAsync(name); if (existingDeck != null) return $"Deck this name {name} already exists"; var cards = GetCardsArray(deckType); var deck = new Deck(cards, name); - _deckRepository.Add(deck, name); - return "Success created"; + var isCreate = await _deckRepository.AddAsync(deck, name); + if (isCreate) + return "Success created"; + else + return "Deck not created"; } catch (Exception ex) { @@ -39,30 +43,30 @@ public string CreateNamedDeck(string name, DeckType deckType) } } - public Deck GetDeckByName(string name) + public async Task GetDeckByNameAsync(string name) { - var deck = _deckRepository.GetDeck(name); + var deck = await _deckRepository.GetDeckAsync(name); return deck; } - public string[] GetCreatedDecksNames() + public async Task GetCreatedDecksNamesAsync() { - return _deckRepository.GetDecksNames(); + return await _deckRepository.GetDecksNamesAsync(); } - public Deck[] GetDecks() + public async Task GetDecksAsync() { - return _deckRepository.GetDecks(); + return await _deckRepository.GetDecksAsync(); } - public string DeleteDeckByName(string name) + public async Task DeleteDeckByNameAsync(string name) { try { - var existingDeck = GetDeckByName(name); + var existingDeck = await GetDeckByNameAsync(name); if (existingDeck != null) { - _deckRepository.Delete(name); + await _deckRepository.DeleteAsync(name); return "Success deleted"; } else @@ -74,32 +78,32 @@ public string DeleteDeckByName(string name) } } - public string DeleteDecks() + public async Task DeleteDecksAsync() { - var decks = _deckRepository.GetDecks(); + var decks = await _deckRepository.GetDecksAsync(); if (decks == null) return "Decks was not created"; - _deckRepository.DeleteDecks(); + await _deckRepository.DeleteDecksAsync(); return "Success deleted"; } - public string ShuffleDeckBySuit(int sortOption, string name) + public async Task ShuffleDeckByNameAsync(int sortOption, string name) { - var existingDeck = GetDeckByName(name); + var existingDeck = await GetDeckByNameAsync(name); if (existingDeck != null) { switch (sortOption) { case SIMPLE_SHUFFLING: - UpdateDeck(name, _cardShuffler.SimpleShuffle(existingDeck)); + await UpdateDeckAsync(name, _cardShuffler.SimpleShuffle(existingDeck)); break; case ASCENDING_ORDER: - DeleteDeckByName(name); - CreateNamedDeck(name, (DeckType)existingDeck.Count); + await DeleteDeckByNameAsync(name); + await CreateNamedDeckAsync(name, (DeckType)existingDeck.Count); break; default: - UpdateDeck(name, _cardShuffler.SimpleShuffle(existingDeck)); + await UpdateDeckAsync(name, _cardShuffler.SimpleShuffle(existingDeck)); break; } return "Successfully shuffled"; @@ -108,13 +112,13 @@ public string ShuffleDeckBySuit(int sortOption, string name) return "This decks was not created"; } - private void UpdateDeck(string name, Deck deck) + private async Task UpdateDeckAsync(string name, Deck deck) { - DeleteDeckByName(name); - _deckRepository.Add(deck, name); + await DeleteDeckByNameAsync(name); + await _deckRepository.AddAsync(deck, name); } - private Card[] GetCardsArray(DeckType deckType) + private static Card[] GetCardsArray(DeckType deckType) { var cards = new List(); var sequenceNumber = 1; diff --git a/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs b/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs index 10d28bd..c77c572 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs @@ -1,6 +1,8 @@ -using System; +using Microsoft.EntityFrameworkCore; +using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Tyche.DataAccess.MsSql.Context; using Tyche.DataAccess.MsSql.Infrastructure; using Tyche.Domain.Interfaces; @@ -19,32 +21,34 @@ public DeckRepository(DeckContext context) _context = context; } - public void Add(Deck deck, string name) + public async Task AddAsync(Deck deck, string name) { - if (deck == null) return; + if (deck == null) return false; - if (String.IsNullOrWhiteSpace(name)) return; + if (String.IsNullOrWhiteSpace(name)) return false; var deckEntity = _automapper.MappingToDeckEntity(deck, name); - _context.Add(deckEntity); - _context.SaveChanges(); + await _context.AddAsync(deckEntity); + await _context.SaveChangesAsync(); + + return true; } - public Deck GetDeck(string name) + public async Task GetDeckAsync(string name) { - var deckEntity = _context.Decks.FirstOrDefault(deck => deck.Name == name); + var deckEntity = await _context.Decks.FirstOrDefaultAsync(deck => deck.Name == name); if (deckEntity == null) return null; - deckEntity.Deck = _context.Cards.Where(card => card.DeckId == deckEntity.Id).OrderByDescending(card => card.SequenceNumber).ToArray(); + deckEntity.Deck = await _context.Cards.Where(card => card.DeckId == deckEntity.Id).OrderByDescending(card => card.SequenceNumber).ToArrayAsync(); var deck = _automapper.MappingToDeck(deckEntity, name); return deck; } - public string[] GetDecksNames() + public async Task GetDecksNamesAsync() { - var decksEntity = _context.Decks.ToList(); + var decksEntity = await _context.Decks.ToListAsync(); var decks = new List(); foreach (var deck in decksEntity) @@ -54,14 +58,14 @@ public string[] GetDecksNames() return decks.ToArray(); } - public Deck[] GetDecks() + public async Task GetDecksAsync() { - var decksEntity = _context.Decks.ToList(); + var decksEntity = await _context.Decks.ToListAsync(); if (decksEntity.Count == 0) return null; foreach (var deckEntity in decksEntity) { - deckEntity.Deck = _context.Cards.Where(card => card.DeckId == deckEntity.Id).OrderByDescending(card => card.SequenceNumber).ToArray(); + deckEntity.Deck = await _context.Cards.Where(card => card.DeckId == deckEntity.Id).OrderByDescending(card => card.SequenceNumber).ToArrayAsync(); } var decksResponse = new List(); @@ -74,26 +78,32 @@ public Deck[] GetDecks() return decksResponse.ToArray(); } - public void Delete(string name) + public async Task DeleteAsync(string name) { - var deck = _context.Decks.FirstOrDefault(deck => deck.Name == name); + var deck = await _context.Decks.FirstOrDefaultAsync(deck => deck.Name == name); + if (deck == null) return false; + _context.Decks.Remove(deck); - var cardsEntity = _context.Cards.Where(card => card.DeckId == deck.Id).ToArray(); + var cardsEntity = await _context.Cards.Where(card => card.DeckId == deck.Id).ToArrayAsync(); + if (cardsEntity == null) return false; + _context.Cards.RemoveRange(cardsEntity); - _context.SaveChanges(); + await _context.SaveChangesAsync(); + return true; } - public void DeleteDecks() + public async Task DeleteDecksAsync() { var decksEntity = _context.Decks.ToList(); - if (decksEntity.Count == 0) return; + if (decksEntity.Count == 0) return false; foreach (var deckEntity in decksEntity) { - Delete(deckEntity.Name); + await DeleteAsync(deckEntity.Name); } + return true; } } } diff --git a/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs b/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs index 24538e6..4197163 100644 --- a/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs +++ b/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs @@ -1,20 +1,21 @@  +using System.Threading.Tasks; using Tyche.Domain.Models; namespace Tyche.Domain.Interfaces { public interface IDeckRepository { - void Add(Deck deck, string name); + Task AddAsync(Deck deck, string name); - void Delete(string name); + Task GetDeckAsync(string name); + + Task DeleteAsync(string name); - Deck GetDeck(string name); + Task GetDecksAsync(); - Deck[] GetDecks(); + Task GetDecksNamesAsync(); - string[] GetDecksNames(); - - void DeleteDecks(); + Task DeleteDecksAsync(); } } diff --git a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs index bedd020..d891d92 100644 --- a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs +++ b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs @@ -1,22 +1,23 @@ -using Tyche.Domain.Models; +using System.Threading.Tasks; +using Tyche.Domain.Models; namespace Tyche.Domain.Interfaces { public interface IDeckService { - string CreateNamedDeck(string name, DeckType deckType); + Task CreateNamedDeckAsync(string name, DeckType deckType); - Deck GetDeckByName(string name); + Task GetDeckByNameAsync(string name); - Deck[] GetDecks(); + Task GetDecksAsync(); - string[] GetCreatedDecksNames(); + Task GetCreatedDecksNamesAsync(); - string DeleteDeckByName(string name); + Task DeleteDeckByNameAsync(string name); - string ShuffleDeckBySuit(int sortOption, string name); + Task ShuffleDeckByNameAsync(int sortOption, string name); - string DeleteDecks(); + Task DeleteDecksAsync(); } } From 2c511c50c5607426b9028dcf64144a39bdd05c62 Mon Sep 17 00:00:00 2001 From: "includingivansmirnov@gmail.com" Date: Tue, 3 May 2022 22:52:28 +0500 Subject: [PATCH 05/15] Start Creating client application(CLI) #7 --- Tyche/Client.CLI/Client.CLI.csproj | 12 +++ Tyche/Client.CLI/Client.cs | 64 +++++++++++++++ Tyche/Client.CLI/DeckHttpClient.cs | 55 +++++++++++++ .../Infrastructure/DisplayAttribute.cs | 15 ++++ .../Infrastructure/EnumDisplayExtensions.cs | 31 ++++++++ .../Client.CLI/Interfaces/IDeckHttpClient.cs | 24 ++++++ Tyche/Client.CLI/Models/Card.cs | 77 +++++++++++++++++++ Tyche/Client.CLI/Models/Deck.cs | 46 +++++++++++ Tyche/Client.CLI/Models/DeckType.cs | 9 +++ Tyche/Client.CLI/Models/Rank.cs | 35 +++++++++ Tyche/Client.CLI/Models/Suit.cs | 17 ++++ Tyche/Client.CLI/Program.cs | 18 +++++ Tyche/Tyche.API/Controllers/DeckController.cs | 4 +- Tyche/Tyche.API/appsettings.json | 3 +- ...er.cs => 20220503171037_First.Designer.cs} | 2 +- ...44457_First.cs => 20220503171037_First.cs} | 0 Tyche/Tyche.sln | 6 ++ 17 files changed, 413 insertions(+), 5 deletions(-) create mode 100644 Tyche/Client.CLI/Client.CLI.csproj create mode 100644 Tyche/Client.CLI/Client.cs create mode 100644 Tyche/Client.CLI/DeckHttpClient.cs create mode 100644 Tyche/Client.CLI/Infrastructure/DisplayAttribute.cs create mode 100644 Tyche/Client.CLI/Infrastructure/EnumDisplayExtensions.cs create mode 100644 Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs create mode 100644 Tyche/Client.CLI/Models/Card.cs create mode 100644 Tyche/Client.CLI/Models/Deck.cs create mode 100644 Tyche/Client.CLI/Models/DeckType.cs create mode 100644 Tyche/Client.CLI/Models/Rank.cs create mode 100644 Tyche/Client.CLI/Models/Suit.cs create mode 100644 Tyche/Client.CLI/Program.cs rename Tyche/Tyche.DataAccess.MsSql/Migrations/{20220503144457_First.Designer.cs => 20220503171037_First.Designer.cs} (98%) rename Tyche/Tyche.DataAccess.MsSql/Migrations/{20220503144457_First.cs => 20220503171037_First.cs} (100%) diff --git a/Tyche/Client.CLI/Client.CLI.csproj b/Tyche/Client.CLI/Client.CLI.csproj new file mode 100644 index 0000000..aa43dce --- /dev/null +++ b/Tyche/Client.CLI/Client.CLI.csproj @@ -0,0 +1,12 @@ + + + + Exe + net5.0 + + + + + + + diff --git a/Tyche/Client.CLI/Client.cs b/Tyche/Client.CLI/Client.cs new file mode 100644 index 0000000..44e489a --- /dev/null +++ b/Tyche/Client.CLI/Client.cs @@ -0,0 +1,64 @@ +using Client.CLI.Interfaces; +using System; +using System.Linq; + + +namespace Client.CLI +{ + internal partial class Client + { + private IDeckHttpClient _deckHttpClient; + + public Client(IDeckHttpClient deckHttpClient) + { + _deckHttpClient = deckHttpClient; + } + + internal void Start() + { + Console.WriteLine("Client started"); + + var isUserContinue = true; + string userAnswer; + + do + { + Console.WriteLine("Select a menu item:" + + "\n\t1) Create named deck" + + "\n\t2) Getting a deck of cards by name" + + "\n\t3) Get a list of deck names" + + "\n\t4) Getting all decks of cards" + + "\n\t5) Deleting all deck of cards" + + "\n\t6) Deleting deck of cards by name" + + "\n\t7) Shuffle dekcs of cards in the selected way"); + + + userAnswer = Console.ReadLine(); + + switch (userAnswer) + { + case "1": + break; + case "2": + break; + case "3": + break; + case "4": + break; + case "5": + break; + case "6": + break; + case "7": + break; + } + + Console.WriteLine("Continue? (y/n)"); + userAnswer = Console.ReadLine(); + + isUserContinue = userAnswer.ToLower() == "y"; + + } while (isUserContinue); + } + } +} diff --git a/Tyche/Client.CLI/DeckHttpClient.cs b/Tyche/Client.CLI/DeckHttpClient.cs new file mode 100644 index 0000000..336c45b --- /dev/null +++ b/Tyche/Client.CLI/DeckHttpClient.cs @@ -0,0 +1,55 @@ +using Client.CLI.Interfaces; +using Client.CLI.Models; +using System; +using System.Net.Http; +using System.Threading.Tasks; + + +namespace Client.CLI +{ + public class DeckHttpClient : IDeckHttpClient + { + private readonly HttpClient _client; + + public DeckHttpClient(HttpClient client, Uri baseUri) + { + _client = client; + _client.BaseAddress = baseUri; + } + + public Task CreateNamedDeckAsync(string name, DeckType deckType) + { + throw new NotImplementedException(); + } + + public Task DeleteDeckByNameAsync(string name) + { + throw new NotImplementedException(); + } + + public Task DeleteDecksAsync() + { + throw new NotImplementedException(); + } + + public Task GetCreatedDecksNamesAsync() + { + throw new NotImplementedException(); + } + + public Task GetDeckByNameAsync(string name) + { + throw new NotImplementedException(); + } + + public Task GetDecksAsync() + { + throw new NotImplementedException(); + } + + public Task ShuffleDeckByNameAsync(int sortOption, string name) + { + throw new NotImplementedException(); + } + } +} diff --git a/Tyche/Client.CLI/Infrastructure/DisplayAttribute.cs b/Tyche/Client.CLI/Infrastructure/DisplayAttribute.cs new file mode 100644 index 0000000..537ba21 --- /dev/null +++ b/Tyche/Client.CLI/Infrastructure/DisplayAttribute.cs @@ -0,0 +1,15 @@ +using System; + + +namespace Client.CLI.Infrastructure +{ + public class DisplayAttribute : Attribute + { + public string Name { get; set; } + + public DisplayAttribute() + { + + } + } +} diff --git a/Tyche/Client.CLI/Infrastructure/EnumDisplayExtensions.cs b/Tyche/Client.CLI/Infrastructure/EnumDisplayExtensions.cs new file mode 100644 index 0000000..d77c85d --- /dev/null +++ b/Tyche/Client.CLI/Infrastructure/EnumDisplayExtensions.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + + +namespace Client.CLI.Infrastructure +{ + public static class EnumDisplayExtensions + { + public static string GetDisplayName(this Enum enumValue) + { + var attributeType = typeof(DisplayAttribute); + + FieldInfo fi = enumValue.GetType().GetField(enumValue.ToString()); + + var attributes = fi.GetCustomAttributes(attributeType, false) + .Cast() + .ToList(); + + List names = new List(); + foreach (var attribute in attributes) + { + string name = attribute.Name; + names.Add(name); + } + + return String.Join("", names); + } + } +} diff --git a/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs b/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs new file mode 100644 index 0000000..feb16ad --- /dev/null +++ b/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs @@ -0,0 +1,24 @@ +using Client.CLI.Models; +using System.Threading.Tasks; + + +namespace Client.CLI.Interfaces +{ + public interface IDeckHttpClient + { + Task CreateNamedDeckAsync(string name, DeckType deckType); + + Task GetDeckByNameAsync(string name); + + Task GetDecksAsync(); + + Task GetCreatedDecksNamesAsync(); + + Task DeleteDeckByNameAsync(string name); + + Task ShuffleDeckByNameAsync(int sortOption, string name); + + Task DeleteDecksAsync(); + + } +} diff --git a/Tyche/Client.CLI/Models/Card.cs b/Tyche/Client.CLI/Models/Card.cs new file mode 100644 index 0000000..0132d00 --- /dev/null +++ b/Tyche/Client.CLI/Models/Card.cs @@ -0,0 +1,77 @@ +using Client.CLI.Infrastructure; +using System; +using System.Text; + +namespace Client.CLI.Models +{ + public class Card + { + public int SequenceNumber { get; } + + public ConsoleColor Color { get; private set; } + + public char UnicodeSign { get; private set; } + + public Rank Rank { get; } + + public Suit Suit { get; } + + public Card(Rank rank, Suit suit, int sequenceNumber) + { + if (suit == Suit.Hearts || suit == Suit.Diamonds) + Color = ConsoleColor.Red; + else + Color = ConsoleColor.White; + + Rank = rank; + Suit = suit; + + SequenceNumber = sequenceNumber; + + UnicodeSign = SetUnicodeSign(); + } + + private char SetUnicodeSign() + { + switch (Suit) + { + case Suit.Spades: + return '\u2660'; + case Suit.Clubs: + return '\u2663'; + case Suit.Hearts: + return '\u2665'; + case Suit.Diamonds: + return '\u2666'; + default: + return '-'; + } + } + + public void ShowCard() + { + Console.OutputEncoding = Encoding.Unicode; + + Console.ForegroundColor = this.Color; + + string rank = Rank.GetDisplayName(); + + string output = $"[{UnicodeSign}{rank}]"; + if (output.Length < 9) + { + output = String.Concat(output, new string(' ', 9 - output.Length)); + } + + Console.Write(output); + } + + public override string ToString() + { + string rank = Rank.GetDisplayName(); + + var result = $"{Suit}-{rank}"; + + return result; + } + } +} diff --git a/Tyche/Client.CLI/Models/Deck.cs b/Tyche/Client.CLI/Models/Deck.cs new file mode 100644 index 0000000..e71124f --- /dev/null +++ b/Tyche/Client.CLI/Models/Deck.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + + +namespace Client.CLI.Models +{ + public class Deck + { + private Stack _cards; + + public Stack Cards { get { return _cards; } } + + public int Count { get; private set; } + + public string Name { get; private set; } + + public Deck(Card[] cards, string name) + { + if (cards == null || cards.Length == 0) + throw new ArgumentException(nameof(cards)); + + Count = cards.Length; + _cards = new Stack(cards); + Name = name; + } + + public Card Pull() + { + Count = _cards.Count - 1; + return _cards.Pop(); + } + + public virtual void ShowDeck() + { + Console.WriteLine(new string('-', 115)); + + while(Cards.Count > 0) + { + var card = Cards.Pop(); + card.ShowCard(); + } + + Console.WriteLine(new string('-', 115)); + } + } +} diff --git a/Tyche/Client.CLI/Models/DeckType.cs b/Tyche/Client.CLI/Models/DeckType.cs new file mode 100644 index 0000000..bab3db5 --- /dev/null +++ b/Tyche/Client.CLI/Models/DeckType.cs @@ -0,0 +1,9 @@ + +namespace Client.CLI.Models +{ + public enum DeckType + { + StandartDeck = 52, + SmalDeck = 36 + } +} diff --git a/Tyche/Client.CLI/Models/Rank.cs b/Tyche/Client.CLI/Models/Rank.cs new file mode 100644 index 0000000..abc74f9 --- /dev/null +++ b/Tyche/Client.CLI/Models/Rank.cs @@ -0,0 +1,35 @@ +using Client.CLI.Infrastructure; + + +namespace Client.CLI.Models +{ + public enum Rank + { + [Display(Name = "2")] + Two, + [Display(Name = "3")] + Three, + [Display(Name = "4")] + Four, + [Display(Name = "5")] + Five, + [Display(Name = "6")] + Six, + [Display(Name = "7")] + Seven, + [Display(Name = "8")] + Eight, + [Display(Name = "9")] + Nine, + [Display(Name = "10")] + Ten, + [Display(Name = "Валет")] + Jack, + [Display(Name = "Дама")] + Queen, + [Display(Name = "Король")] + King, + [Display(Name = "Туз")] + Ace + } +} diff --git a/Tyche/Client.CLI/Models/Suit.cs b/Tyche/Client.CLI/Models/Suit.cs new file mode 100644 index 0000000..226e1a2 --- /dev/null +++ b/Tyche/Client.CLI/Models/Suit.cs @@ -0,0 +1,17 @@ +using Client.CLI.Infrastructure; + + +namespace Client.CLI.Models +{ + public enum Suit + { + [Display(Name = "Пики")] + Spades, + [Display(Name = "Трефы")] + Clubs, + [Display(Name = "Червы")] + Hearts, + [Display(Name = "Бубны")] + Diamonds + } +} diff --git a/Tyche/Client.CLI/Program.cs b/Tyche/Client.CLI/Program.cs new file mode 100644 index 0000000..0a25789 --- /dev/null +++ b/Tyche/Client.CLI/Program.cs @@ -0,0 +1,18 @@ +using System; +using System.Net.Http; + +namespace Client.CLI +{ + internal class Program + { + static void Main(string[] args) + { + var httpClient = new HttpClient(); + var baseCafeUri = new Uri("http://localhost:5000"); + var cafeHttpClient = new DeckHttpClient(httpClient, baseCafeUri); + + var application = new Client(cafeHttpClient); + application.Start(); + } + } +} diff --git a/Tyche/Tyche.API/Controllers/DeckController.cs b/Tyche/Tyche.API/Controllers/DeckController.cs index bc52993..8d8e45d 100644 --- a/Tyche/Tyche.API/Controllers/DeckController.cs +++ b/Tyche/Tyche.API/Controllers/DeckController.cs @@ -79,7 +79,7 @@ public async Task GetNames() } /// - /// Getting a all decks of cards + /// Getting all decks of cards /// /// [HttpGet("Decks/")] @@ -101,7 +101,7 @@ public async Task> GetDecks() } /// - /// Deleting a deck of cards by name + /// Deleting deck of cards by name /// /// [HttpDelete("ByNames/")] diff --git a/Tyche/Tyche.API/appsettings.json b/Tyche/Tyche.API/appsettings.json index fe25ec2..d394ec8 100644 --- a/Tyche/Tyche.API/appsettings.json +++ b/Tyche/Tyche.API/appsettings.json @@ -8,7 +8,6 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - //"DeckContext": "Data Source=(LocalDb)\\MSSQLLocalDB;Database=DeckDB;Trusted_Connection=True;MultipleActiveResultSets=true" - "DeckContext": "Data Source=DESKTOP-KJ6048R;Database=DeckDB;Trusted_Connection=True;MultipleActiveResultSets=true" + "DeckContext": "Data Source=(LocalDb)\\MSSQLLocalDB;Database=Deck_DB;Trusted_Connection=True;MultipleActiveResultSets=true" } } diff --git a/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.Designer.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503171037_First.Designer.cs similarity index 98% rename from Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.Designer.cs rename to Tyche/Tyche.DataAccess.MsSql/Migrations/20220503171037_First.Designer.cs index e04d7ae..ecdb105 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.Designer.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503171037_First.Designer.cs @@ -9,7 +9,7 @@ namespace Tyche.DataAccess.MsSql.Migrations { [DbContext(typeof(DeckContext))] - [Migration("20220503144457_First")] + [Migration("20220503171037_First")] partial class First { protected override void BuildTargetModel(ModelBuilder modelBuilder) diff --git a/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503171037_First.cs similarity index 100% rename from Tyche/Tyche.DataAccess.MsSql/Migrations/20220503144457_First.cs rename to Tyche/Tyche.DataAccess.MsSql/Migrations/20220503171037_First.cs diff --git a/Tyche/Tyche.sln b/Tyche/Tyche.sln index 8ea74b7..515ac2b 100644 --- a/Tyche/Tyche.sln +++ b/Tyche/Tyche.sln @@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.IntegrationTests", "T EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.DataAccess.MsSql", "Tyche.DataAccess.MsSql\Tyche.DataAccess.MsSql.csproj", "{DF99F54A-0C13-47AC-BF39-06183CD40417}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client.CLI", "Client.CLI\Client.CLI.csproj", "{146160C3-F8F7-4A03-A3DE-AD7A396EC808}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {DF99F54A-0C13-47AC-BF39-06183CD40417}.Debug|Any CPU.Build.0 = Debug|Any CPU {DF99F54A-0C13-47AC-BF39-06183CD40417}.Release|Any CPU.ActiveCfg = Release|Any CPU {DF99F54A-0C13-47AC-BF39-06183CD40417}.Release|Any CPU.Build.0 = Release|Any CPU + {146160C3-F8F7-4A03-A3DE-AD7A396EC808}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {146160C3-F8F7-4A03-A3DE-AD7A396EC808}.Debug|Any CPU.Build.0 = Debug|Any CPU + {146160C3-F8F7-4A03-A3DE-AD7A396EC808}.Release|Any CPU.ActiveCfg = Release|Any CPU + {146160C3-F8F7-4A03-A3DE-AD7A396EC808}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 2d79451a87fcdd802e07af98695f51402722dbfa Mon Sep 17 00:00:00 2001 From: Smirnov Ivan <86609845+includingByMeAndMyself@users.noreply.github.com> Date: Tue, 3 May 2022 22:55:39 +0500 Subject: [PATCH 06/15] Create dotnet.yml --- .github/workflows/dotnet.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/dotnet.yml diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 0000000..858e410 --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,27 @@ +name: .NET + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v2 + with: + dotnet-version: 5.0.x + - name: Change Directory + run: cd Tyche + - name: Restore dependencies + run: dotnet restore Tyche/Tyche.sln + - name: Build + run: dotnet build Tyche/Tyche.sln --no-restore + - name: Test + run: dotnet test Tyche/Tyche.sln --no-build --verbosity normal From 616bfa381b536fc8061ec2a2756c2ddc83dffd9f Mon Sep 17 00:00:00 2001 From: "includingivansmirnov@gmail.com" Date: Tue, 3 May 2022 22:56:51 +0500 Subject: [PATCH 07/15] Testing workFlow Action --- Tyche/Client.CLI/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tyche/Client.CLI/Program.cs b/Tyche/Client.CLI/Program.cs index 0a25789..00d28ea 100644 --- a/Tyche/Client.CLI/Program.cs +++ b/Tyche/Client.CLI/Program.cs @@ -8,7 +8,7 @@ internal class Program static void Main(string[] args) { var httpClient = new HttpClient(); - var baseCafeUri = new Uri("http://localhost:5000"); + var baseCafeUri = new Uri("http://localhost:5001"); var cafeHttpClient = new DeckHttpClient(httpClient, baseCafeUri); var application = new Client(cafeHttpClient); From 7123be6400d79fac3fc4e6bc94a0ee31c0d4fd51 Mon Sep 17 00:00:00 2001 From: IvanSminrov Date: Wed, 4 May 2022 12:21:15 +0500 Subject: [PATCH 08/15] Part of issue Create client application(CLI) #7 --- Tyche/Client.CLI/Client.CLI.csproj | 3 +- Tyche/Client.CLI/Client.cs | 79 ++++++++++++++++--- Tyche/Client.CLI/DeckHttpClient.cs | 30 ++++++- .../Infrastructure/ClientExtensions.cs | 30 +++++++ .../Client.CLI/Interfaces/IDeckHttpClient.cs | 1 + Tyche/Client.CLI/Models/DeckRequestDto.cs | 14 ++++ Tyche/Client.CLI/Program.cs | 6 +- Tyche/Tyche.API/Program.cs | 7 +- .../Services/DeckService.cs | 2 +- .../Infrastructure/MigrationManager.cs | 34 ++++++++ .../Tyche.DataAccess.MsSql.csproj | 1 + Tyche/Tyche/Tyche.API/Tyche.API.xml | 4 +- 12 files changed, 189 insertions(+), 22 deletions(-) create mode 100644 Tyche/Client.CLI/Infrastructure/ClientExtensions.cs create mode 100644 Tyche/Client.CLI/Models/DeckRequestDto.cs create mode 100644 Tyche/Tyche.DataAccess.MsSql/Infrastructure/MigrationManager.cs diff --git a/Tyche/Client.CLI/Client.CLI.csproj b/Tyche/Client.CLI/Client.CLI.csproj index aa43dce..9a4397d 100644 --- a/Tyche/Client.CLI/Client.CLI.csproj +++ b/Tyche/Client.CLI/Client.CLI.csproj @@ -6,7 +6,8 @@ - + + diff --git a/Tyche/Client.CLI/Client.cs b/Tyche/Client.CLI/Client.cs index 44e489a..d07ce9b 100644 --- a/Tyche/Client.CLI/Client.cs +++ b/Tyche/Client.CLI/Client.cs @@ -1,4 +1,6 @@ -using Client.CLI.Interfaces; +using Client.CLI.Infrastructure; +using Client.CLI.Interfaces; +using Client.CLI.Models; using System; using System.Linq; @@ -8,6 +10,7 @@ namespace Client.CLI internal partial class Client { private IDeckHttpClient _deckHttpClient; + private const int WIDTH_CONSOLE = 120; public Client(IDeckHttpClient deckHttpClient) { @@ -23,21 +26,22 @@ internal void Start() do { - Console.WriteLine("Select a menu item:" + - "\n\t1) Create named deck" + - "\n\t2) Getting a deck of cards by name" + - "\n\t3) Get a list of deck names" + - "\n\t4) Getting all decks of cards" + - "\n\t5) Deleting all deck of cards" + - "\n\t6) Deleting deck of cards by name" + - "\n\t7) Shuffle dekcs of cards in the selected way"); + Console.Clear(); + PrintLine(); + PrintMenu(); + PrintLine(); + + Console.Write("\n\tSelect a menu item: "); userAnswer = Console.ReadLine(); + Console.Clear(); + switch (userAnswer) { case "1": + CreateNamedDeckAsync(); break; case "2": break; @@ -51,14 +55,65 @@ internal void Start() break; case "7": break; + case "8": + break; + default : + continue; } - Console.WriteLine("Continue? (y/n)"); + Console.ForegroundColor = ConsoleColor.Red; + Console.Write("\n\tAre you sure you want to quit? (y/n): "); userAnswer = Console.ReadLine(); + Console.ResetColor(); - isUserContinue = userAnswer.ToLower() == "y"; - + isUserContinue = userAnswer.ToLower() == "n"; + } while (isUserContinue); } + + public void CreateNamedDeckAsync() + { + Console.WriteLine(); + Console.Write("\tEnter Decks name: "); + + var name = Console.ReadLine(); + + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("\tDecks Type:" + + "\r\n\t\"52\" if you want create StandartDeck = 52 cards " + + "\r\n\t\"36\" if you want create SmallDeck = 36 cards"); + Console.ResetColor(); + Console.Write("\r\n\tEnter Decks Type: "); + var type = Console.ReadLine(); + + var deckType = type.ToDeckType(); + + var response = _deckHttpClient.CreateNamedDeckAsync(name, deckType); + Console.WriteLine("\r\n\t" + response.Result); + } + + private static void PrintLine() + { + Console.WriteLine(); + Console.BackgroundColor = ConsoleColor.Cyan; + Console.WriteLine(new string('_', WIDTH_CONSOLE)); + Console.ResetColor(); + Console.WriteLine(); + } + + private static void PrintMenu() + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("\t1 - Create named deck;" + + "\n\t2 - Getting a deck of cards by name;" + + "\n\t3 - Get a list of deck names;" + + "\n\t4 - Getting all decks of cards;" + + "\n\t5 - Deleting all deck of cards;" + + "\n\t6 - Deleting deck of cards by name;" + + "\n\t7 - Shuffle named deck in the selected way;" + + "\n\t8 - Exit;"); + Console.ResetColor(); + } } } diff --git a/Tyche/Client.CLI/DeckHttpClient.cs b/Tyche/Client.CLI/DeckHttpClient.cs index 336c45b..149930c 100644 --- a/Tyche/Client.CLI/DeckHttpClient.cs +++ b/Tyche/Client.CLI/DeckHttpClient.cs @@ -1,7 +1,12 @@ using Client.CLI.Interfaces; using Client.CLI.Models; +using Microsoft.AspNet.SignalR.Client.Infrastructure; +using Newtonsoft.Json; using System; +using System.IO; +using System.Net; using System.Net.Http; +using System.Text; using System.Threading.Tasks; @@ -17,9 +22,30 @@ public DeckHttpClient(HttpClient client, Uri baseUri) _client.BaseAddress = baseUri; } - public Task CreateNamedDeckAsync(string name, DeckType deckType) + public async Task CreateNamedDeckAsync(string name, DeckType deckType) { - throw new NotImplementedException(); + var request = new DeckRequestDto + { + Name = name, + DeckType = deckType + }; + + var url = _client.BaseAddress.ToString() + "Deck"; + + var data = JsonConvert.SerializeObject(request); + var content = new StringContent(data, Encoding.UTF8, "application/json"); + + try + { + var response = await _client.PostAsync(url, content); + + var responseBody = await response.Content.ReadAsStringAsync(); + return responseBody; + } + catch (Exception ex) + { + return ex.Message; + } } public Task DeleteDeckByNameAsync(string name) diff --git a/Tyche/Client.CLI/Infrastructure/ClientExtensions.cs b/Tyche/Client.CLI/Infrastructure/ClientExtensions.cs new file mode 100644 index 0000000..d37afac --- /dev/null +++ b/Tyche/Client.CLI/Infrastructure/ClientExtensions.cs @@ -0,0 +1,30 @@ +using Client.CLI.Models; +using System; + + +namespace Client.CLI.Infrastructure +{ + public static class ClientExtensions + { + public static DeckType ToDeckType(this string value) + { + if (string.IsNullOrWhiteSpace(value)) + return DeckType.SmalDeck; + + if (int.TryParse(value, out var res)) + { + if (res == 36) + { + Enum.TryParse(value, out DeckType smalDeck); + return smalDeck; + } + else if (res == 52) + { + Enum.TryParse(value, out DeckType standartDeck); + return standartDeck; + } + } + return DeckType.SmalDeck; + } + } +} diff --git a/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs b/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs index feb16ad..0b09346 100644 --- a/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs +++ b/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs @@ -1,4 +1,5 @@ using Client.CLI.Models; +using System.Net.Http; using System.Threading.Tasks; diff --git a/Tyche/Client.CLI/Models/DeckRequestDto.cs b/Tyche/Client.CLI/Models/DeckRequestDto.cs new file mode 100644 index 0000000..6863525 --- /dev/null +++ b/Tyche/Client.CLI/Models/DeckRequestDto.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + + +namespace Client.CLI.Models +{ + public class DeckRequestDto + { + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("deckType")] + public DeckType DeckType { get; set; } + } +} diff --git a/Tyche/Client.CLI/Program.cs b/Tyche/Client.CLI/Program.cs index 00d28ea..b57069c 100644 --- a/Tyche/Client.CLI/Program.cs +++ b/Tyche/Client.CLI/Program.cs @@ -8,10 +8,10 @@ internal class Program static void Main(string[] args) { var httpClient = new HttpClient(); - var baseCafeUri = new Uri("http://localhost:5001"); - var cafeHttpClient = new DeckHttpClient(httpClient, baseCafeUri); + var baseCafeUri = new Uri("https://localhost:5001"); + var deckHttpClient = new DeckHttpClient(httpClient, baseCafeUri); - var application = new Client(cafeHttpClient); + var application = new Client(deckHttpClient); application.Start(); } } diff --git a/Tyche/Tyche.API/Program.cs b/Tyche/Tyche.API/Program.cs index 9c78a54..08daf05 100644 --- a/Tyche/Tyche.API/Program.cs +++ b/Tyche/Tyche.API/Program.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Tyche.DataAccess.MsSql.Infrastructure; + namespace Tyche.API { @@ -13,7 +15,10 @@ public class Program { public static void Main(string[] args) { - CreateHostBuilder(args).Build().Run(); + CreateHostBuilder(args) + .Build() + .MigrateDatabase() + .Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => diff --git a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs index 85d5c72..867f08c 100644 --- a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs +++ b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs @@ -26,7 +26,7 @@ public async Task CreateNamedDeckAsync(string name, DeckType deckType) try { var existingDeck = await GetDeckByNameAsync(name); - if (existingDeck != null) return $"Deck this name {name} already exists"; + if (existingDeck != null) return $"Deck whit this name {name} already exists"; var cards = GetCardsArray(deckType); var deck = new Deck(cards, name); diff --git a/Tyche/Tyche.DataAccess.MsSql/Infrastructure/MigrationManager.cs b/Tyche/Tyche.DataAccess.MsSql/Infrastructure/MigrationManager.cs new file mode 100644 index 0000000..ea6f8e3 --- /dev/null +++ b/Tyche/Tyche.DataAccess.MsSql/Infrastructure/MigrationManager.cs @@ -0,0 +1,34 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using Tyche.DataAccess.MsSql.Context; + + + +namespace Tyche.DataAccess.MsSql.Infrastructure +{ + public static class MigrationManager + { + public static IHost MigrateDatabase(this IHost host) + { + using (var scope = host.Services.CreateScope()) + { + using (var appContext = scope.ServiceProvider.GetRequiredService()) + { + try + { + appContext.Database.Migrate(); + } + catch (Exception) + { + //Log errors or do anything you think it's needed + throw; + } + } + } + + return host; + } + } +} diff --git a/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj b/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj index d066449..2496076 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj +++ b/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj @@ -15,6 +15,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Tyche/Tyche/Tyche.API/Tyche.API.xml b/Tyche/Tyche/Tyche.API/Tyche.API.xml index a033792..0f03c8f 100644 --- a/Tyche/Tyche/Tyche.API/Tyche.API.xml +++ b/Tyche/Tyche/Tyche.API/Tyche.API.xml @@ -31,13 +31,13 @@ - Getting a all decks of cards + Getting all decks of cards - Deleting a deck of cards by name + Deleting deck of cards by name From 57885e493cfb5e2c5b2c4a071b0f69cd5c6a1432 Mon Sep 17 00:00:00 2001 From: IvanSminrov Date: Wed, 4 May 2022 17:00:21 +0500 Subject: [PATCH 09/15] Create client application(CLI) #7 --- Tyche/Client.CLI/Client.cs | 136 +++++++++++++++++- Tyche/Client.CLI/DeckHttpClient.cs | 135 ++++++++++++++--- Tyche/Client.CLI/Infrastructure/Automapper.cs | 32 +++++ .../Infrastructure/ClientExtensions.cs | 21 +++ .../Client.CLI/Interfaces/IDeckHttpClient.cs | 3 +- Tyche/Client.CLI/Models/Card.cs | 6 +- Tyche/Client.CLI/Models/Deck.cs | 21 ++- Tyche/Client.CLI/Models/DeckResponse.cs | 10 ++ Tyche/Client.CLI/Models/ShuffleOption.cs | 10 ++ Tyche/Client.CLI/Models/ShuffleRequest.cs | 11 ++ Tyche/Tyche.API/Controllers/DeckController.cs | 8 +- Tyche/Tyche.API/Models/ShuffleRequest.cs | 2 +- Tyche/Tyche.API/Program.cs | 6 - Tyche/Tyche/Tyche.API/Tyche.API.xml | 2 +- 14 files changed, 359 insertions(+), 44 deletions(-) create mode 100644 Tyche/Client.CLI/Infrastructure/Automapper.cs create mode 100644 Tyche/Client.CLI/Models/DeckResponse.cs create mode 100644 Tyche/Client.CLI/Models/ShuffleOption.cs create mode 100644 Tyche/Client.CLI/Models/ShuffleRequest.cs diff --git a/Tyche/Client.CLI/Client.cs b/Tyche/Client.CLI/Client.cs index d07ce9b..8962f11 100644 --- a/Tyche/Client.CLI/Client.cs +++ b/Tyche/Client.CLI/Client.cs @@ -1,8 +1,6 @@ using Client.CLI.Infrastructure; using Client.CLI.Interfaces; -using Client.CLI.Models; using System; -using System.Linq; namespace Client.CLI @@ -11,14 +9,18 @@ internal partial class Client { private IDeckHttpClient _deckHttpClient; private const int WIDTH_CONSOLE = 120; + private const int HIGHT_CONSOLE = 30; public Client(IDeckHttpClient deckHttpClient) { _deckHttpClient = deckHttpClient; + Console.SetWindowSize(WIDTH_CONSOLE, HIGHT_CONSOLE); + } internal void Start() { + Console.Title= "Tyche"; Console.WriteLine("Client started"); var isUserContinue = true; @@ -44,16 +46,22 @@ internal void Start() CreateNamedDeckAsync(); break; case "2": + GetDeckByNameAsync(); break; case "3": + GetCreatedDecksNamesAsync(); break; case "4": + GetDecksAsync(); break; case "5": + DeleteDecksAsync(); break; case "6": + DeleteDeckByNameAsync(); break; case "7": + ShuffleDeckByNameAsync(); break; case "8": break; @@ -74,7 +82,9 @@ internal void Start() public void CreateNamedDeckAsync() { Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Green; Console.Write("\tEnter Decks name: "); + Console.ResetColor(); var name = Console.ReadLine(); @@ -83,31 +93,145 @@ public void CreateNamedDeckAsync() Console.WriteLine("\tDecks Type:" + "\r\n\t\"52\" if you want create StandartDeck = 52 cards " + "\r\n\t\"36\" if you want create SmallDeck = 36 cards"); - Console.ResetColor(); Console.Write("\r\n\tEnter Decks Type: "); + Console.ResetColor(); var type = Console.ReadLine(); var deckType = type.ToDeckType(); var response = _deckHttpClient.CreateNamedDeckAsync(name, deckType); - Console.WriteLine("\r\n\t" + response.Result); + + if(response.Result != null) + Console.WriteLine("\r\n\t" + response.Result); + } + + public void GetCreatedDecksNamesAsync() + { + Console.WriteLine(); + + var response = _deckHttpClient.GetCreatedDecksNamesAsync(); + var count = 1; + + if(response.Result != null) + { + Console.ForegroundColor= ConsoleColor.Green; + Console.WriteLine("\r\n\tNames of deck(s):"); + Console.ResetColor(); + + foreach (var name in response.Result) + { + Console.WriteLine($"\r\n\t{count}) " + name); + count++; + } + } + else + { + Console.WriteLine("\r\n\tNo decks of cards created"); + } + } + + public void GetDeckByNameAsync() + { + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Green; + Console.Write("\tEnter Decks name: "); + Console.ResetColor(); + + var name = Console.ReadLine(); + + var response = _deckHttpClient.GetDeckByNameAsync(name); + if (response.Result != null) + { + response.Result.ShowDeck(); + } + else + { + Console.WriteLine($"\r\n\tNo deck of cards whit name {name} created"); + } + } + + public void GetDecksAsync() + { + + var response = _deckHttpClient.GetDecksAsync(); + + if (response.Result != null) + { + foreach (var deck in response.Result) + { + deck.ShowDeck(); + } + } + else + { + Console.WriteLine($"\r\n\tHave no decks of cards"); + } + } + + public void DeleteDeckByNameAsync() + { + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Green; + Console.Write("\tEnter Decks name: "); + Console.ResetColor(); + + var name = Console.ReadLine(); + + var response = _deckHttpClient.DeleteDeckByNameAsync(name); + + if (response.Result != null) + Console.WriteLine("\r\n\t" + response.Result); + } + + public void DeleteDecksAsync() + { + var response = _deckHttpClient.DeleteDecksAsync(); + + if (response.Result != null) + Console.WriteLine("\r\n\t" + response.Result); } private static void PrintLine() { Console.WriteLine(); Console.BackgroundColor = ConsoleColor.Cyan; - Console.WriteLine(new string('_', WIDTH_CONSOLE)); + Console.WriteLine(new string(' ', WIDTH_CONSOLE)); Console.ResetColor(); Console.WriteLine(); } + public void ShuffleDeckByNameAsync() + { + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Green; + Console.Write("\tEnter Decks name: "); + Console.ResetColor(); + + var name = Console.ReadLine(); + + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("\tShuffle Option:" + + "\r\n\t\"1\" if you want to shuffle a deck of cards" + + "\r\n\t\"2\" if you want to shuffle the deck of cards in order"); + Console.Write("\r\n\tEnter Shuffle Option: "); + Console.ResetColor(); + var type = Console.ReadLine(); + + var shuffleType = type.ToShuffleOption(); + + var response = _deckHttpClient.ShuffleDeckByNameAsync(shuffleType, name); + + if (response.Result != null) + Console.WriteLine("\r\n\t" + response.Result); + } + private static void PrintMenu() { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("\t1 - Create named deck;" + "\n\t2 - Getting a deck of cards by name;" + - "\n\t3 - Get a list of deck names;" + + "\n\t3 - Get list of deck names;" + "\n\t4 - Getting all decks of cards;" + "\n\t5 - Deleting all deck of cards;" + "\n\t6 - Deleting deck of cards by name;" + diff --git a/Tyche/Client.CLI/DeckHttpClient.cs b/Tyche/Client.CLI/DeckHttpClient.cs index 149930c..4630c44 100644 --- a/Tyche/Client.CLI/DeckHttpClient.cs +++ b/Tyche/Client.CLI/DeckHttpClient.cs @@ -1,10 +1,9 @@ -using Client.CLI.Interfaces; +using Client.CLI.Infrastructure; +using Client.CLI.Interfaces; using Client.CLI.Models; -using Microsoft.AspNet.SignalR.Client.Infrastructure; using Newtonsoft.Json; using System; -using System.IO; -using System.Net; +using System.Collections.Generic; using System.Net.Http; using System.Text; using System.Threading.Tasks; @@ -48,34 +47,138 @@ public async Task CreateNamedDeckAsync(string name, DeckType deckType) } } - public Task DeleteDeckByNameAsync(string name) + public async Task DeleteDeckByNameAsync(string name) { - throw new NotImplementedException(); + var url = _client.BaseAddress.ToString() + $"Deck/DeckByName/{name}"; + + try + { + var response = await _client.DeleteAsync(url); + + var responseBody = await response.Content.ReadAsStringAsync(); + return responseBody; + } + catch (Exception ex) + { + return ex.Message; + } } - public Task DeleteDecksAsync() + public async Task DeleteDecksAsync() { - throw new NotImplementedException(); + var url = _client.BaseAddress.ToString() + $"Deck/Decks"; + + try + { + var response = await _client.DeleteAsync(url); + + var responseBody = await response.Content.ReadAsStringAsync(); + return responseBody; + } + catch (Exception ex) + { + return ex.Message; + } } - public Task GetCreatedDecksNamesAsync() + public async Task GetCreatedDecksNamesAsync() { - throw new NotImplementedException(); + var url = _client.BaseAddress.ToString() + "Deck/Names"; + + try + { + var response = _client.GetAsync(url).Result; + var json = await response.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(json); + } + catch (Exception) + { + return null; + } } - public Task GetDeckByNameAsync(string name) + public async Task GetDeckByNameAsync(string name) { - throw new NotImplementedException(); + var url = _client.BaseAddress.ToString() + $"Deck/DeckByName/{name}"; + try + { + var response = _client.GetAsync(url).Result; + var json = await response.Content.ReadAsStringAsync(); + + var deckResponse = JsonConvert.DeserializeObject(json); + + if(deckResponse != null) + { + var deck = Automapper.MappingToDeck(deckResponse); + return deck; + } + else + { + return null; + } + } + catch (Exception) + { + return null; + } } - public Task GetDecksAsync() + public async Task GetDecksAsync() { - throw new NotImplementedException(); + var url = _client.BaseAddress.ToString() + $"Deck/Decks"; + try + { + var response = _client.GetAsync(url).Result; + var json = await response.Content.ReadAsStringAsync(); + + var decksResponse = JsonConvert.DeserializeObject(json); + + if (decksResponse != null) + { + var decks = new List(); + foreach (var deckResponse in decksResponse) + { + var deck = Automapper.MappingToDeck(deckResponse); + decks.Add(deck); + } + return decks.ToArray(); + } + else + { + return null; + } + } + catch (Exception) + { + return null; + } } - public Task ShuffleDeckByNameAsync(int sortOption, string name) + public async Task ShuffleDeckByNameAsync(ShuffleOption shuffleOption, string name) { - throw new NotImplementedException(); + var request = new ShuffleRequest + { + Name = name, + ShuffleOption = (int)shuffleOption + }; + + var url = _client.BaseAddress.ToString() + "Deck/Shuffle"; + + var data = JsonConvert.SerializeObject(request); + var content = new StringContent(data, Encoding.UTF8, "application/json"); + + try + { + var response = await _client.PutAsync(url, content); + + var responseBody = await response.Content.ReadAsStringAsync(); + return responseBody; + } + catch (Exception ex) + { + return ex.Message; + } } } } diff --git a/Tyche/Client.CLI/Infrastructure/Automapper.cs b/Tyche/Client.CLI/Infrastructure/Automapper.cs new file mode 100644 index 0000000..a14a43d --- /dev/null +++ b/Tyche/Client.CLI/Infrastructure/Automapper.cs @@ -0,0 +1,32 @@ +using Client.CLI.Models; +using System; +using System.Collections.Generic; +using System.Linq; + + +namespace Client.CLI.Infrastructure +{ + public static class Automapper + { + public static Deck MappingToDeck(DeckResponse deckResponse) + { + var cardsResponse = deckResponse.Cards.ToList(); + var cards = new List(); + + foreach (var cardResponse in cardsResponse) + { + var splitResult = cardResponse.Split(';'); + + var sequenceNumber = int.Parse(splitResult[0]); + var rank = (Rank)Enum.Parse(typeof(Rank), splitResult[1]); + var suit = (Suit)Enum.Parse(typeof(Suit), splitResult[2]); + + cards.Add(new Card(rank, suit, sequenceNumber)); + } + + var name = deckResponse.Name; + + return new Deck(cards.ToArray(), name); + } + } +} diff --git a/Tyche/Client.CLI/Infrastructure/ClientExtensions.cs b/Tyche/Client.CLI/Infrastructure/ClientExtensions.cs index d37afac..322cb6c 100644 --- a/Tyche/Client.CLI/Infrastructure/ClientExtensions.cs +++ b/Tyche/Client.CLI/Infrastructure/ClientExtensions.cs @@ -26,5 +26,26 @@ public static DeckType ToDeckType(this string value) } return DeckType.SmalDeck; } + + public static ShuffleOption ToShuffleOption(this string value) + { + if (string.IsNullOrWhiteSpace(value)) + return ShuffleOption.InOrder; + + if (int.TryParse(value, out var res)) + { + if (res == 1) + { + Enum.TryParse(value, out ShuffleOption simpleShuffle); + return simpleShuffle; + } + else if (res == 2) + { + Enum.TryParse(value, out ShuffleOption inOrder); + return inOrder; + } + } + return ShuffleOption.InOrder; + } } } diff --git a/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs b/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs index 0b09346..70dfa27 100644 --- a/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs +++ b/Tyche/Client.CLI/Interfaces/IDeckHttpClient.cs @@ -1,5 +1,4 @@ using Client.CLI.Models; -using System.Net.Http; using System.Threading.Tasks; @@ -17,7 +16,7 @@ public interface IDeckHttpClient Task DeleteDeckByNameAsync(string name); - Task ShuffleDeckByNameAsync(int sortOption, string name); + Task ShuffleDeckByNameAsync(ShuffleOption shuffleRequest, string name); Task DeleteDecksAsync(); diff --git a/Tyche/Client.CLI/Models/Card.cs b/Tyche/Client.CLI/Models/Card.cs index 0132d00..48daf33 100644 --- a/Tyche/Client.CLI/Models/Card.cs +++ b/Tyche/Client.CLI/Models/Card.cs @@ -57,12 +57,8 @@ public void ShowCard() string rank = Rank.GetDisplayName(); string output = $"[{UnicodeSign}{rank}]"; - if (output.Length < 9) - { - output = String.Concat(output, new string(' ', 9 - output.Length)); - } - Console.Write(output); + Console.WriteLine("\t"+output); } public override string ToString() diff --git a/Tyche/Client.CLI/Models/Deck.cs b/Tyche/Client.CLI/Models/Deck.cs index e71124f..849edc5 100644 --- a/Tyche/Client.CLI/Models/Deck.cs +++ b/Tyche/Client.CLI/Models/Deck.cs @@ -6,6 +6,8 @@ namespace Client.CLI.Models { public class Deck { + private const int WIDTH_CONSOLE = 120; + private Stack _cards; public Stack Cards { get { return _cards; } } @@ -32,15 +34,28 @@ public Card Pull() public virtual void ShowDeck() { - Console.WriteLine(new string('-', 115)); + Console.ForegroundColor = ConsoleColor.Green; + Console.Write("\r\n\tDeck name: "); + Console.ResetColor(); + Console.WriteLine(Name + "\r\n"); + - while(Cards.Count > 0) + while (Cards.Count > 0) { var card = Cards.Pop(); card.ShowCard(); } - Console.WriteLine(new string('-', 115)); + PrintLine(); + } + + private static void PrintLine() + { + Console.WriteLine(); + Console.BackgroundColor = ConsoleColor.Cyan; + Console.WriteLine(new string(' ', WIDTH_CONSOLE)); + Console.ResetColor(); + Console.WriteLine(); } } } diff --git a/Tyche/Client.CLI/Models/DeckResponse.cs b/Tyche/Client.CLI/Models/DeckResponse.cs new file mode 100644 index 0000000..40f5b94 --- /dev/null +++ b/Tyche/Client.CLI/Models/DeckResponse.cs @@ -0,0 +1,10 @@ + +namespace Client.CLI.Models +{ + public class DeckResponse + { + public string[] Cards { get; set; } + + public string Name { get; set; } + } +} diff --git a/Tyche/Client.CLI/Models/ShuffleOption.cs b/Tyche/Client.CLI/Models/ShuffleOption.cs new file mode 100644 index 0000000..3a2d24a --- /dev/null +++ b/Tyche/Client.CLI/Models/ShuffleOption.cs @@ -0,0 +1,10 @@ + + +namespace Client.CLI.Models +{ + public enum ShuffleOption + { + SimpleShuffle, + InOrder + } +} diff --git a/Tyche/Client.CLI/Models/ShuffleRequest.cs b/Tyche/Client.CLI/Models/ShuffleRequest.cs new file mode 100644 index 0000000..2bfcab2 --- /dev/null +++ b/Tyche/Client.CLI/Models/ShuffleRequest.cs @@ -0,0 +1,11 @@ + + +namespace Client.CLI.Models +{ + public class ShuffleRequest + { + public int ShuffleOption { get; set; } + + public string Name { get; set; } + } +} diff --git a/Tyche/Tyche.API/Controllers/DeckController.cs b/Tyche/Tyche.API/Controllers/DeckController.cs index 8d8e45d..02e56e2 100644 --- a/Tyche/Tyche.API/Controllers/DeckController.cs +++ b/Tyche/Tyche.API/Controllers/DeckController.cs @@ -48,7 +48,7 @@ public async Task Create(DeckRequest request) /// /// /// - [HttpGet("{name}")] + [HttpGet("DeckByName/{name}")] public async Task> GetDeckByName(string name) { @@ -104,7 +104,7 @@ public async Task> GetDecks() /// Deleting deck of cards by name /// /// - [HttpDelete("ByNames/")] + [HttpDelete("DeckByName/{name}")] public async Task Delete(string name) { var response = await _deckService.DeleteDeckByNameAsync(name); @@ -126,12 +126,12 @@ public async Task Delete() /// /// Shuffle dekcs of cards in the selected way /// - /// + /// /// [HttpPut("Shuffle/")] public async Task Update(ShuffleRequest request) { - var response = await _deckService.ShuffleDeckByNameAsync(request.SortOption, request.Name); + var response = await _deckService.ShuffleDeckByNameAsync(request.ShuffleOption, request.Name); return Ok(response); } } diff --git a/Tyche/Tyche.API/Models/ShuffleRequest.cs b/Tyche/Tyche.API/Models/ShuffleRequest.cs index c61e6b0..19d8200 100644 --- a/Tyche/Tyche.API/Models/ShuffleRequest.cs +++ b/Tyche/Tyche.API/Models/ShuffleRequest.cs @@ -6,7 +6,7 @@ namespace Tyche.API.Models public class ShuffleRequest { [Range(1, 2)] - public int SortOption { get; set; } + public int ShuffleOption { get; set; } [StringLength(50, MinimumLength = 3, ErrorMessage = "Name length must be in the family from {2}-{1} characters")] public string Name { get; set; } diff --git a/Tyche/Tyche.API/Program.cs b/Tyche/Tyche.API/Program.cs index 08daf05..bf6ea54 100644 --- a/Tyche/Tyche.API/Program.cs +++ b/Tyche/Tyche.API/Program.cs @@ -1,11 +1,5 @@ using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Tyche.DataAccess.MsSql.Infrastructure; diff --git a/Tyche/Tyche/Tyche.API/Tyche.API.xml b/Tyche/Tyche/Tyche.API/Tyche.API.xml index 0f03c8f..7d0c147 100644 --- a/Tyche/Tyche/Tyche.API/Tyche.API.xml +++ b/Tyche/Tyche/Tyche.API/Tyche.API.xml @@ -52,7 +52,7 @@ Shuffle dekcs of cards in the selected way - + From bd7c83b5d0bfa92c4d61fa976c0b138c3c175fcf Mon Sep 17 00:00:00 2001 From: Smirnov Ivan <86609845+includingByMeAndMyself@users.noreply.github.com> Date: Wed, 4 May 2022 17:22:36 +0500 Subject: [PATCH 10/15] Update README.md --- README.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b69018..cb4a994 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,23 @@ # Tyche -Deck sorter project: a simple project that implements a RESTful API service for sorting a deck of cards by certain parameters +

Простой проект, реализующий сервис RESTful API для сортировки колоды карт по определенным параметрам.

+

Этот проект состоит из серверной части:

+

+ +

+

И из клиентской части:

+

+ +

+

Для хранения данных используется: LocalDb

+

Строка подключения располагается в Tyche.API/appsettings.json (Можно заменить на свою строку подключения)

+

+ +

Для успешного запуска приложения необходимо выполнить команду:

+

Для консоли диспетчера пакетов:

+

+ Update-Database [options] +

+

Для окна командной строки:

+

+ dotnet ef database update [options] +

From 9a79026a1b662583b491b13f1dca3503b172e1b7 Mon Sep 17 00:00:00 2001 From: "includingivansmirnov@gmail.com" Date: Wed, 4 May 2022 19:29:20 +0500 Subject: [PATCH 11/15] =?UTF-8?q?=D0=A1orrected=20the=20output=20of=20card?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tyche/Client.CLI/Client.cs | 61 ++++++++++++++++++--------------- Tyche/Client.CLI/Models/Card.cs | 11 ++++-- Tyche/Tyche.API/Program.cs | 2 ++ 3 files changed, 43 insertions(+), 31 deletions(-) diff --git a/Tyche/Client.CLI/Client.cs b/Tyche/Client.CLI/Client.cs index 8962f11..755f143 100644 --- a/Tyche/Client.CLI/Client.cs +++ b/Tyche/Client.CLI/Client.cs @@ -20,7 +20,7 @@ public Client(IDeckHttpClient deckHttpClient) internal void Start() { - Console.Title= "Tyche"; + Console.Title= "Tyche Client"; Console.WriteLine("Client started"); var isUserContinue = true; @@ -81,10 +81,8 @@ internal void Start() public void CreateNamedDeckAsync() { - Console.WriteLine(); - Console.ForegroundColor = ConsoleColor.Green; - Console.Write("\tEnter Decks name: "); - Console.ResetColor(); + var mesg = "\tEnter Decks name: "; + PrintLineGreen(mesg); var name = Console.ReadLine(); @@ -114,9 +112,8 @@ public void GetCreatedDecksNamesAsync() if(response.Result != null) { - Console.ForegroundColor= ConsoleColor.Green; - Console.WriteLine("\r\n\tNames of deck(s):"); - Console.ResetColor(); + var mesg = "\r\n\tNames of deck(s):"; + PrintGreen(mesg); foreach (var name in response.Result) { @@ -132,10 +129,8 @@ public void GetCreatedDecksNamesAsync() public void GetDeckByNameAsync() { - Console.WriteLine(); - Console.ForegroundColor = ConsoleColor.Green; - Console.Write("\tEnter Decks name: "); - Console.ResetColor(); + var mesg = "\tEnter Decks name: "; + PrintLineGreen(mesg); var name = Console.ReadLine(); @@ -152,7 +147,6 @@ public void GetDeckByNameAsync() public void GetDecksAsync() { - var response = _deckHttpClient.GetDecksAsync(); if (response.Result != null) @@ -170,11 +164,8 @@ public void GetDecksAsync() public void DeleteDeckByNameAsync() { - Console.WriteLine(); - Console.ForegroundColor = ConsoleColor.Green; - Console.Write("\tEnter Decks name: "); - Console.ResetColor(); - + var mesg = "\tEnter Decks name: "; + PrintLineGreen(mesg); var name = Console.ReadLine(); var response = _deckHttpClient.DeleteDeckByNameAsync(name); @@ -186,20 +177,10 @@ public void DeleteDeckByNameAsync() public void DeleteDecksAsync() { var response = _deckHttpClient.DeleteDecksAsync(); - if (response.Result != null) Console.WriteLine("\r\n\t" + response.Result); } - private static void PrintLine() - { - Console.WriteLine(); - Console.BackgroundColor = ConsoleColor.Cyan; - Console.WriteLine(new string(' ', WIDTH_CONSOLE)); - Console.ResetColor(); - Console.WriteLine(); - } - public void ShuffleDeckByNameAsync() { Console.WriteLine(); @@ -226,6 +207,30 @@ public void ShuffleDeckByNameAsync() Console.WriteLine("\r\n\t" + response.Result); } + private static void PrintLineGreen(string mesg) + { + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Green; + Console.Write(mesg); + Console.ResetColor(); + } + + private static void PrintGreen(string mesg) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine("\r\n\tNames of deck(s):"); + Console.ResetColor(); + } + + private static void PrintLine() + { + Console.WriteLine(); + Console.BackgroundColor = ConsoleColor.Cyan; + Console.WriteLine(new string(' ', WIDTH_CONSOLE)); + Console.ResetColor(); + Console.WriteLine(); + } + private static void PrintMenu() { Console.ForegroundColor = ConsoleColor.Green; diff --git a/Tyche/Client.CLI/Models/Card.cs b/Tyche/Client.CLI/Models/Card.cs index 48daf33..091814f 100644 --- a/Tyche/Client.CLI/Models/Card.cs +++ b/Tyche/Client.CLI/Models/Card.cs @@ -6,7 +6,7 @@ namespace Client.CLI.Models { public class Card { - public int SequenceNumber { get; } + public int SequenceNumber { get; private set; } public ConsoleColor Color { get; private set; } @@ -56,9 +56,14 @@ public void ShowCard() string rank = Rank.GetDisplayName(); - string output = $"[{UnicodeSign}{rank}]"; + string output = $"{UnicodeSign}{rank}"; - Console.WriteLine("\t"+output); + if (output.Length < 9) + { + output = String.Concat(output, new string(' ', 9 - output.Length)); + } + + Console.WriteLine($"\t[{output}]"); } public override string ToString() diff --git a/Tyche/Tyche.API/Program.cs b/Tyche/Tyche.API/Program.cs index bf6ea54..8979996 100644 --- a/Tyche/Tyche.API/Program.cs +++ b/Tyche/Tyche.API/Program.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; +using System; using Tyche.DataAccess.MsSql.Infrastructure; @@ -9,6 +10,7 @@ public class Program { public static void Main(string[] args) { + Console.Title = "Tyche Server"; CreateHostBuilder(args) .Build() .MigrateDatabase() From f2e728dfcb6b79398e7adbc5520d6acf3e7ace04 Mon Sep 17 00:00:00 2001 From: "includingivansmirnov@gmail.com" Date: Wed, 4 May 2022 22:06:22 +0500 Subject: [PATCH 12/15] Implement Unit tests for DeckService #3 --- .../Services/DeckService.cs | 2 +- .../Tyche.IntegrationTests.csproj | 26 ------ Tyche/Tyche.IntegrationTests/UnitTest1.cs | 14 ---- Tyche/Tyche.UnitTests/DeckServiceTests.cs | 82 +++++++++++++++++++ Tyche/Tyche.UnitTests/Tyche.UnitTests.csproj | 13 +-- Tyche/Tyche.UnitTests/UnitTest1.cs | 14 ---- Tyche/Tyche.sln | 20 ++--- 7 files changed, 94 insertions(+), 77 deletions(-) delete mode 100644 Tyche/Tyche.IntegrationTests/Tyche.IntegrationTests.csproj delete mode 100644 Tyche/Tyche.IntegrationTests/UnitTest1.cs create mode 100644 Tyche/Tyche.UnitTests/DeckServiceTests.cs delete mode 100644 Tyche/Tyche.UnitTests/UnitTest1.cs diff --git a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs index 867f08c..41d52d3 100644 --- a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs +++ b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs @@ -140,4 +140,4 @@ private static Card[] GetCardsArray(DeckType deckType) return cards.ToArray(); } } -} +} \ No newline at end of file diff --git a/Tyche/Tyche.IntegrationTests/Tyche.IntegrationTests.csproj b/Tyche/Tyche.IntegrationTests/Tyche.IntegrationTests.csproj deleted file mode 100644 index b43a489..0000000 --- a/Tyche/Tyche.IntegrationTests/Tyche.IntegrationTests.csproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - net5.0 - - false - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/Tyche/Tyche.IntegrationTests/UnitTest1.cs b/Tyche/Tyche.IntegrationTests/UnitTest1.cs deleted file mode 100644 index 3d61659..0000000 --- a/Tyche/Tyche.IntegrationTests/UnitTest1.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Xunit; - -namespace Tyche.IntegrationTests -{ - public class UnitTest1 - { - [Fact] - public void Test1() - { - - } - } -} diff --git a/Tyche/Tyche.UnitTests/DeckServiceTests.cs b/Tyche/Tyche.UnitTests/DeckServiceTests.cs new file mode 100644 index 0000000..5698977 --- /dev/null +++ b/Tyche/Tyche.UnitTests/DeckServiceTests.cs @@ -0,0 +1,82 @@ +using Moq; +using NUnit.Framework; +using System.Collections.Generic; +using Tyche.BusinessLogic.Services; +using Tyche.Domain.Interfaces; +using Tyche.Domain.Models; + + +namespace Tyche.UnitTests +{ + public class DeckServiceTests + { + private DeckService _service; + private Mock _deckRepositoryMock; + + [SetUp] + public void SetUp() + { + _deckRepositoryMock = new Mock(); + _service = new DeckService(_deckRepositoryMock.Object); + } + + [Test] + public void GetDeckByName_ShouldReturnTrue() + { + //arrange + var expectedDeckName = "TestDeck"; + + var Cards = new List(); + var card1 = new Card(Rank.Ace, Suit.Diamonds, 1); + var card2 = new Card(Rank.Ace, Suit.Spades, 2); + + Cards.Add(card1); + Cards.Add(card2); + + var deck = new Deck(Cards.ToArray(), expectedDeckName); + + _deckRepositoryMock + .Setup(x => x.GetDeckAsync(expectedDeckName)) + .ReturnsAsync(() => deck) + .Verifiable(); + + //act + var result = _service.GetDeckByNameAsync(expectedDeckName); + + //assert + _deckRepositoryMock.VerifyAll(); + + Assert.AreEqual(expectedDeckName, result.Result.Name); + } + + public void GetCreatedDecksNames_ShouldReturnTrue() + { + //arrange + var expectedDeckName = "TestDeck"; + + var Cards = new List(); + var card1 = new Card(Rank.Ace, Suit.Diamonds, 1); + var card2 = new Card(Rank.Ace, Suit.Spades, 2); + + Cards.Add(card1); + Cards.Add(card2); + + var deck = new Deck(Cards.ToArray(), expectedDeckName); + + _deckRepositoryMock + .Setup(x => x.GetDecksNamesAsync()) + .ReturnsAsync(() => new string[] { expectedDeckName }) + .Verifiable(); + + //act + var result = _service.GetCreatedDecksNamesAsync(); + + //assert + _deckRepositoryMock.VerifyAll(); + + Assert.NotNull(result.Result); + Assert.IsNotEmpty(result.Result); + Assert.AreEqual(expectedDeckName, result.Result[0]); + } + } +} \ No newline at end of file diff --git a/Tyche/Tyche.UnitTests/Tyche.UnitTests.csproj b/Tyche/Tyche.UnitTests/Tyche.UnitTests.csproj index 7b2e2b0..95efe8b 100644 --- a/Tyche/Tyche.UnitTests/Tyche.UnitTests.csproj +++ b/Tyche/Tyche.UnitTests/Tyche.UnitTests.csproj @@ -8,15 +8,10 @@ - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + + + + diff --git a/Tyche/Tyche.UnitTests/UnitTest1.cs b/Tyche/Tyche.UnitTests/UnitTest1.cs deleted file mode 100644 index b7caf15..0000000 --- a/Tyche/Tyche.UnitTests/UnitTest1.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Xunit; - -namespace Tyche.UnitTests -{ - public class UnitTest1 - { - [Fact] - public void Test1() - { - - } - } -} diff --git a/Tyche/Tyche.sln b/Tyche/Tyche.sln index 515ac2b..62213ce 100644 --- a/Tyche/Tyche.sln +++ b/Tyche/Tyche.sln @@ -9,13 +9,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.Domain", "Tyche.Domai EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.BusinessLogic", "Tyche.BusinessLogic\Tyche.BusinessLogic.csproj", "{5FC62F53-A220-4483-A965-12B214712FF8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.UnitTests", "Tyche.UnitTests\Tyche.UnitTests.csproj", "{80151682-6D95-4A4F-8D30-C370E9FEC971}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.IntegrationTests", "Tyche.IntegrationTests\Tyche.IntegrationTests.csproj", "{45CEE789-234D-4ED9-A11C-8876D4C5DDB5}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.DataAccess.MsSql", "Tyche.DataAccess.MsSql\Tyche.DataAccess.MsSql.csproj", "{DF99F54A-0C13-47AC-BF39-06183CD40417}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client.CLI", "Client.CLI\Client.CLI.csproj", "{146160C3-F8F7-4A03-A3DE-AD7A396EC808}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client.CLI", "Client.CLI\Client.CLI.csproj", "{146160C3-F8F7-4A03-A3DE-AD7A396EC808}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tyche.UnitTests", "Tyche.UnitTests\Tyche.UnitTests.csproj", "{8609CFE9-D770-45CF-B692-AF12A9BD5E85}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -35,14 +33,6 @@ Global {5FC62F53-A220-4483-A965-12B214712FF8}.Debug|Any CPU.Build.0 = Debug|Any CPU {5FC62F53-A220-4483-A965-12B214712FF8}.Release|Any CPU.ActiveCfg = Release|Any CPU {5FC62F53-A220-4483-A965-12B214712FF8}.Release|Any CPU.Build.0 = Release|Any CPU - {80151682-6D95-4A4F-8D30-C370E9FEC971}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {80151682-6D95-4A4F-8D30-C370E9FEC971}.Debug|Any CPU.Build.0 = Debug|Any CPU - {80151682-6D95-4A4F-8D30-C370E9FEC971}.Release|Any CPU.ActiveCfg = Release|Any CPU - {80151682-6D95-4A4F-8D30-C370E9FEC971}.Release|Any CPU.Build.0 = Release|Any CPU - {45CEE789-234D-4ED9-A11C-8876D4C5DDB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {45CEE789-234D-4ED9-A11C-8876D4C5DDB5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {45CEE789-234D-4ED9-A11C-8876D4C5DDB5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {45CEE789-234D-4ED9-A11C-8876D4C5DDB5}.Release|Any CPU.Build.0 = Release|Any CPU {DF99F54A-0C13-47AC-BF39-06183CD40417}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DF99F54A-0C13-47AC-BF39-06183CD40417}.Debug|Any CPU.Build.0 = Debug|Any CPU {DF99F54A-0C13-47AC-BF39-06183CD40417}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -51,6 +41,10 @@ Global {146160C3-F8F7-4A03-A3DE-AD7A396EC808}.Debug|Any CPU.Build.0 = Debug|Any CPU {146160C3-F8F7-4A03-A3DE-AD7A396EC808}.Release|Any CPU.ActiveCfg = Release|Any CPU {146160C3-F8F7-4A03-A3DE-AD7A396EC808}.Release|Any CPU.Build.0 = Release|Any CPU + {8609CFE9-D770-45CF-B692-AF12A9BD5E85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8609CFE9-D770-45CF-B692-AF12A9BD5E85}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8609CFE9-D770-45CF-B692-AF12A9BD5E85}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8609CFE9-D770-45CF-B692-AF12A9BD5E85}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From d285c820b95b5118f39392f54fca9e2fd0d62f38 Mon Sep 17 00:00:00 2001 From: Smirnov Ivan <86609845+includingByMeAndMyself@users.noreply.github.com> Date: Wed, 4 May 2022 22:41:46 +0500 Subject: [PATCH 13/15] Update README.md --- README.md | 74 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index cb4a994..a04f209 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,57 @@ -# Tyche -

Простой проект, реализующий сервис RESTful API для сортировки колоды карт по определенным параметрам.

-

Этот проект состоит из серверной части:

-

- -

-

И из клиентской части:

-

- +

Tyche

+ +

+ + +

-

Для хранения данных используется: LocalDb

+ +

Описание:

+

Простой проект, реализующий сервис RESTful API для сортировки колоды карт по определенным параметрам.

+

Этот проект состоит из серверной части, которая представляет из себя монолитный REST web API проект, включает:

+
    +
  • Tyche.API
  • +
  • Tyche.BusinessLogic
  • +
  • Tyche.DataAccess.MsSql
  • +
  • Tyche.Domain
  • +
+

И из клиентской части, которая представляет из себя консольное приложение с простым интерфейсом взаимодествия:

+
    +
  • Client.CLI
  • +
+

Основной функционал приложения:

+ +``` +1 - Создать именованную колоду карт; +2 - Получить созданную колоду карт, выбранную по названию колоды; +3 - Получить список названий созданных колод карт; +4 - Получить все созданные колоды карт; +5 - Удалить все созданные колоды карт; +6 - Удалить созданную колоду карт, выбранную по названию колоды; +7 - Перетасовать колоду карт, выбранную по названию колоды. +``` +

Как запускать:

Строка подключения располагается в Tyche.API/appsettings.json (Можно заменить на свою строку подключения)

-

-

Для успешного запуска приложения необходимо выполнить команду:

-

Для консоли диспетчера пакетов:

-

- Update-Database [options] -

-

Для окна командной строки:

-

- dotnet ef database update [options] -

+``` +"DeckContext": "Data Source=(LocalDb)\\MSSQLLocalDB;Database=Deck_DB;Trusted_Connection=True;MultipleActiveResultSets=true" +``` + +

Для успешного запуска приложения необходимо выполнить команду на выбор:

+
    +
  • Для консоли диспетчера пакетов:
  • + + ``` +Update-Database +``` +
  • Для окна командной строки:
  • + + ``` +dotnet ef database update +``` +
+ +

Используемые технологии:

+

Серверная и клиентская часть выполненны на c# .NET Core 5, ASP Web API

+

Для хранения данных используется LocalDb

+

Для работы с базой данных используется ORM entity framework core 5

From 5c122c9a87de352d3e9d174b90d3fd1ff54413f3 Mon Sep 17 00:00:00 2001 From: Smirnov Ivan <86609845+includingByMeAndMyself@users.noreply.github.com> Date: Thu, 5 May 2022 13:23:04 +0500 Subject: [PATCH 14/15] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a04f209..0b4a01d 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@

+

Описание:

Простой проект, реализующий сервис RESTful API для сортировки колоды карт по определенным параметрам.

Этот проект состоит из серверной части, которая представляет из себя монолитный REST web API проект, включает:

From 58f3302f4fbf3048dcc1010130a6559d14def776 Mon Sep 17 00:00:00 2001 From: "includingivansmirnov@gmail.com" Date: Mon, 9 May 2022 13:02:34 +0500 Subject: [PATCH 15/15] baseUri --- Tyche/Client.CLI/Program.cs | 4 ++-- Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tyche/Client.CLI/Program.cs b/Tyche/Client.CLI/Program.cs index b57069c..49ec181 100644 --- a/Tyche/Client.CLI/Program.cs +++ b/Tyche/Client.CLI/Program.cs @@ -8,8 +8,8 @@ internal class Program static void Main(string[] args) { var httpClient = new HttpClient(); - var baseCafeUri = new Uri("https://localhost:5001"); - var deckHttpClient = new DeckHttpClient(httpClient, baseCafeUri); + var baseUri = new Uri("https://localhost:5001"); + var deckHttpClient = new DeckHttpClient(httpClient, baseUri); var application = new Client(deckHttpClient); application.Start(); diff --git a/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs b/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs index 5d27e56..7c5e084 100644 --- a/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs +++ b/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs @@ -1,4 +1,4 @@ - +Ы using System.ComponentModel.DataAnnotations; namespace Tyche.DataAccess.MsSql.Entities