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
diff --git a/README.md b/README.md
index 0b69018..0b4a01d 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,58 @@
-# Tyche
-Deck sorter project: a simple project that implements a RESTful API service for sorting a deck of cards by certain parameters
+
Tyche
+
+
+
+
+
+
+
+
+Описание:
+Простой проект, реализующий сервис RESTful API для сортировки колоды карт по определенным параметрам.
+Этот проект состоит из серверной части, которая представляет из себя монолитный REST web API проект, включает:
+
+ - Tyche.API
+ - Tyche.BusinessLogic
+ - Tyche.DataAccess.MsSql
+ - Tyche.Domain
+
+И из клиентской части, которая представляет из себя консольное приложение с простым интерфейсом взаимодествия:
+
+Основной функционал приложения:
+
+```
+1 - Создать именованную колоду карт;
+2 - Получить созданную колоду карт, выбранную по названию колоды;
+3 - Получить список названий созданных колод карт;
+4 - Получить все созданные колоды карт;
+5 - Удалить все созданные колоды карт;
+6 - Удалить созданную колоду карт, выбранную по названию колоды;
+7 - Перетасовать колоду карт, выбранную по названию колоды.
+```
+Как запускать:
+Строка подключения располагается в Tyche.API/appsettings.json (Можно заменить на свою строку подключения)
+
+```
+"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
diff --git a/Tyche/Client.CLI/Client.CLI.csproj b/Tyche/Client.CLI/Client.CLI.csproj
new file mode 100644
index 0000000..9a4397d
--- /dev/null
+++ b/Tyche/Client.CLI/Client.CLI.csproj
@@ -0,0 +1,13 @@
+
+
+
+ Exe
+ net5.0
+
+
+
+
+
+
+
+
diff --git a/Tyche/Client.CLI/Client.cs b/Tyche/Client.CLI/Client.cs
new file mode 100644
index 0000000..755f143
--- /dev/null
+++ b/Tyche/Client.CLI/Client.cs
@@ -0,0 +1,248 @@
+using Client.CLI.Infrastructure;
+using Client.CLI.Interfaces;
+using System;
+
+
+namespace Client.CLI
+{
+ 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 Client";
+ Console.WriteLine("Client started");
+
+ var isUserContinue = true;
+ string userAnswer;
+
+ do
+ {
+ 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":
+ 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;
+ default :
+ continue;
+ }
+
+ Console.ForegroundColor = ConsoleColor.Red;
+ Console.Write("\n\tAre you sure you want to quit? (y/n): ");
+ userAnswer = Console.ReadLine();
+ Console.ResetColor();
+
+ isUserContinue = userAnswer.ToLower() == "n";
+
+ } while (isUserContinue);
+ }
+
+ public void CreateNamedDeckAsync()
+ {
+ var mesg = "\tEnter Decks name: ";
+ PrintLineGreen(mesg);
+
+ 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.Write("\r\n\tEnter Decks Type: ");
+ Console.ResetColor();
+ var type = Console.ReadLine();
+
+ var deckType = type.ToDeckType();
+
+ var response = _deckHttpClient.CreateNamedDeckAsync(name, deckType);
+
+ 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)
+ {
+ var mesg = "\r\n\tNames of deck(s):";
+ PrintGreen(mesg);
+
+ 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()
+ {
+ var mesg = "\tEnter Decks name: ";
+ PrintLineGreen(mesg);
+
+ 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()
+ {
+ var mesg = "\tEnter Decks name: ";
+ PrintLineGreen(mesg);
+ 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);
+ }
+
+ 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 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;
+ Console.WriteLine("\t1 - Create named deck;" +
+ "\n\t2 - Getting a deck of cards by name;" +
+ "\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;" +
+ "\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
new file mode 100644
index 0000000..4630c44
--- /dev/null
+++ b/Tyche/Client.CLI/DeckHttpClient.cs
@@ -0,0 +1,184 @@
+using Client.CLI.Infrastructure;
+using Client.CLI.Interfaces;
+using Client.CLI.Models;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+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 async Task CreateNamedDeckAsync(string name, DeckType deckType)
+ {
+ 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 async Task DeleteDeckByNameAsync(string name)
+ {
+ 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 async Task DeleteDecksAsync()
+ {
+ 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 async Task GetCreatedDecksNamesAsync()
+ {
+ 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 async Task GetDeckByNameAsync(string name)
+ {
+ 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 async Task GetDecksAsync()
+ {
+ 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 async Task ShuffleDeckByNameAsync(ShuffleOption shuffleOption, string name)
+ {
+ 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
new file mode 100644
index 0000000..322cb6c
--- /dev/null
+++ b/Tyche/Client.CLI/Infrastructure/ClientExtensions.cs
@@ -0,0 +1,51 @@
+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;
+ }
+
+ 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/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..70dfa27
--- /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(ShuffleOption shuffleRequest, 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..091814f
--- /dev/null
+++ b/Tyche/Client.CLI/Models/Card.cs
@@ -0,0 +1,78 @@
+using Client.CLI.Infrastructure;
+using System;
+using System.Text;
+
+namespace Client.CLI.Models
+{
+ public class Card
+ {
+ public int SequenceNumber { get; private set; }
+
+ 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.WriteLine($"\t[{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..849edc5
--- /dev/null
+++ b/Tyche/Client.CLI/Models/Deck.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+
+
+namespace Client.CLI.Models
+{
+ public class Deck
+ {
+ private const int WIDTH_CONSOLE = 120;
+
+ 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.ForegroundColor = ConsoleColor.Green;
+ Console.Write("\r\n\tDeck name: ");
+ Console.ResetColor();
+ Console.WriteLine(Name + "\r\n");
+
+
+ while (Cards.Count > 0)
+ {
+ var card = Cards.Pop();
+ card.ShowCard();
+ }
+
+ 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/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/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/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/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/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..49ec181
--- /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 baseUri = new Uri("https://localhost:5001");
+ var deckHttpClient = new DeckHttpClient(httpClient, baseUri);
+
+ var application = new Client(deckHttpClient);
+ application.Start();
+ }
+ }
+}
diff --git a/Tyche/Tyche.API/Controllers/DeckController.cs b/Tyche/Tyche.API/Controllers/DeckController.cs
index 1079b7f..02e56e2 100644
--- a/Tyche/Tyche.API/Controllers/DeckController.cs
+++ b/Tyche/Tyche.API/Controllers/DeckController.cs
@@ -1,34 +1,40 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
+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;
-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]
- [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
- [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
- [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
- public ActionResult Create(Suit suit)
+ public async Task Create(DeckRequest request)
{
- if (ModelState.IsValid == false)
- return BadRequest();
-
try
{
- var response = _deckService.CreateNamedDeck(suit);
+ var response = await _deckService.CreateNamedDeckAsync(request.Name, request.DeckType);
return Ok(response);
}
catch (Exception ex)
@@ -37,10 +43,95 @@ public ActionResult Create(Suit suit)
}
}
- [HttpGet("{DeckSuit:int}")]
- public IActionResult Get(int suit)
+ ///
+ /// Getting a deck of cards by name
+ ///
+ ///
+ ///
+ [HttpGet("DeckByName/{name}")]
+ public async Task> GetDeckByName(string name)
+ {
+
+ var deck = await _deckService.GetDeckByNameAsync(name);
+ if (deck != null)
+ {
+ var response = _automapper.MappingToDeckResponse(deck);
+ return Ok(response);
+ }
+ else
+ {
+ return Ok($"Have no decks of cards {name}");
+ }
+ }
+
+ ///
+ /// Get a list of deck names
+ ///
+ ///
+ [HttpGet("Names/")]
+ public async Task GetNames()
+ {
+ var names = await _deckService.GetCreatedDecksNamesAsync();
+ if (names.Length != 0)
+ return Ok(names);
+ else
+ return Ok("No decks of cards");
+ }
+
+ ///
+ /// Getting all decks of cards
+ ///
+ ///
+ [HttpGet("Decks/")]
+ public async Task> GetDecks()
+ {
+ var decks = await _deckService.GetDecksAsync();
+ 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 deck of cards by name
+ ///
+ ///
+ [HttpDelete("DeckByName/{name}")]
+ public async Task Delete(string name)
+ {
+ var response = await _deckService.DeleteDeckByNameAsync(name);
+ return Ok(response);
+ }
+
+ ///
+ /// Deleting all deck of cards
+ ///
+ ///
+ ///
+ [HttpDelete("Decks/")]
+ public async Task Delete()
+ {
+ var response = await _deckService.DeleteDecksAsync();
+ return Ok(response);
+ }
+
+ ///
+ /// Shuffle dekcs of cards in the selected way
+ ///
+ ///
+ ///
+ [HttpPut("Shuffle/")]
+ public async Task Update(ShuffleRequest request)
{
- var response = _deckService.GetNamedDeck(suit);
+ var response = await _deckService.ShuffleDeckByNameAsync(request.ShuffleOption, request.Name);
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/ShuffleRequest.cs b/Tyche/Tyche.API/Models/ShuffleRequest.cs
new file mode 100644
index 0000000..19d8200
--- /dev/null
+++ b/Tyche/Tyche.API/Models/ShuffleRequest.cs
@@ -0,0 +1,14 @@
+using System.ComponentModel.DataAnnotations;
+
+
+namespace Tyche.API.Models
+{
+ public class ShuffleRequest
+ {
+ [Range(1, 2)]
+ 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 9c78a54..8979996 100644
--- a/Tyche/Tyche.API/Program.cs
+++ b/Tyche/Tyche.API/Program.cs
@@ -1,11 +1,8 @@
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;
+
namespace Tyche.API
{
@@ -13,7 +10,11 @@ public class Program
{
public static void Main(string[] args)
{
- CreateHostBuilder(args).Build().Run();
+ Console.Title = "Tyche Server";
+ CreateHostBuilder(args)
+ .Build()
+ .MigrateDatabase()
+ .Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
diff --git a/Tyche/Tyche.API/Startup.cs b/Tyche/Tyche.API/Startup.cs
index b428a82..3aa2d79 100644
--- a/Tyche/Tyche.API/Startup.cs
+++ b/Tyche/Tyche.API/Startup.cs
@@ -1,19 +1,17 @@
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 System.IO;
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,21 +23,24 @@ 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 =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Tyche.API", Version = "v1" });
- });
+ var filePath = Path.Combine(System.AppContext.BaseDirectory, "Tyche.API.xml");
+ c.IncludeXmlComments(filePath);
+ });
}
- // 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..47713c4 100644
--- a/Tyche/Tyche.API/Tyche.API.csproj
+++ b/Tyche/Tyche.API/Tyche.API.csproj
@@ -2,19 +2,29 @@
net5.0
+ True
+ ..\\Tyche\Tyche.API\Tyche.API.xml
+
+
+
+ 1701;1702;1591;
+
+
+
+ 1701;1702;1591;
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
-
-
-
-
-
+
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.API/appsettings.json b/Tyche/Tyche.API/appsettings.json
index d9d9a9b..d394ec8 100644
--- a/Tyche/Tyche.API/appsettings.json
+++ b/Tyche/Tyche.API/appsettings.json
@@ -6,5 +6,8 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
- "AllowedHosts": "*"
+ "AllowedHosts": "*",
+ "ConnectionStrings": {
+ "DeckContext": "Data Source=(LocalDb)\\MSSQLLocalDB;Database=Deck_DB;Trusted_Connection=True;MultipleActiveResultSets=true"
+ }
}
diff --git a/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs b/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs
new file mode 100644
index 0000000..3f1abc1
--- /dev/null
+++ b/Tyche/Tyche.BusinessLogic/Infrasturcure/CardShuffler.cs
@@ -0,0 +1,30 @@
+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 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 e45629c..41d52d3 100644
--- a/Tyche/Tyche.BusinessLogic/Services/DeckService.cs
+++ b/Tyche/Tyche.BusinessLogic/Services/DeckService.cs
@@ -1,4 +1,7 @@
using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Tyche.BusinessLogic.Infrasturcure;
using Tyche.Domain.Interfaces;
using Tyche.Domain.Models;
@@ -7,14 +10,134 @@ namespace Tyche.BusinessLogic.Services
{
public class DeckService : IDeckService
{
- public string CreateNamedDeck(Suit suit)
+ private const int SIMPLE_SHUFFLING = 1;
+ private const int ASCENDING_ORDER = 2;
+
+ private readonly IDeckRepository _deckRepository;
+ private readonly CardShuffler _cardShuffler = new();
+
+ public DeckService(IDeckRepository deckRepository)
+ {
+ _deckRepository = deckRepository;
+ }
+
+ public async Task CreateNamedDeckAsync(string name, DeckType deckType)
+ {
+ try
+ {
+ var existingDeck = await GetDeckByNameAsync(name);
+ if (existingDeck != null) return $"Deck whit this name {name} already exists";
+
+ var cards = GetCardsArray(deckType);
+ var deck = new Deck(cards, name);
+
+ var isCreate = await _deckRepository.AddAsync(deck, name);
+ if (isCreate)
+ return "Success created";
+ else
+ return "Deck not created";
+ }
+ catch (Exception ex)
+ {
+ return ex.Message;
+ }
+ }
+
+ public async Task GetDeckByNameAsync(string name)
+ {
+ var deck = await _deckRepository.GetDeckAsync(name);
+ return deck;
+ }
+
+ public async Task GetCreatedDecksNamesAsync()
+ {
+ return await _deckRepository.GetDecksNamesAsync();
+ }
+
+ public async Task GetDecksAsync()
{
- throw new NotImplementedException();
+ return await _deckRepository.GetDecksAsync();
}
- public Deck GetNamedDeck(int suit)
+ public async Task DeleteDeckByNameAsync(string name)
{
- throw new NotImplementedException();
+ try
+ {
+ var existingDeck = await GetDeckByNameAsync(name);
+ if (existingDeck != null)
+ {
+ await _deckRepository.DeleteAsync(name);
+ return "Success deleted";
+ }
+ else
+ return "This deck was not created";
+ }
+ catch (Exception ex)
+ {
+ return ex.Message;
+ }
+ }
+
+ public async Task DeleteDecksAsync()
+ {
+ var decks = await _deckRepository.GetDecksAsync();
+ if (decks == null) return "Decks was not created";
+
+ await _deckRepository.DeleteDecksAsync();
+ return "Success deleted";
+ }
+
+ public async Task ShuffleDeckByNameAsync(int sortOption, string name)
+ {
+ var existingDeck = await GetDeckByNameAsync(name);
+
+ if (existingDeck != null)
+ {
+ switch (sortOption)
+ {
+ case SIMPLE_SHUFFLING:
+ await UpdateDeckAsync(name, _cardShuffler.SimpleShuffle(existingDeck));
+ break;
+ case ASCENDING_ORDER:
+ await DeleteDeckByNameAsync(name);
+ await CreateNamedDeckAsync(name, (DeckType)existingDeck.Count);
+ break;
+ default:
+ await UpdateDeckAsync(name, _cardShuffler.SimpleShuffle(existingDeck));
+ break;
+ }
+ return "Successfully shuffled";
+ }
+ else
+ return "This decks was not created";
+ }
+
+ private async Task UpdateDeckAsync(string name, Deck deck)
+ {
+ await DeleteDeckByNameAsync(name);
+ await _deckRepository.AddAsync(deck, name);
+ }
+
+ private static Card[] GetCardsArray(DeckType deckType)
+ {
+ var cards = new List();
+ var sequenceNumber = 1;
+
+ foreach (Suit suit in Enum.GetValues(typeof(Suit)))
+ {
+ foreach (Rank rank in Enum.GetValues(typeof(Rank)))
+ {
+ if (deckType == DeckType.SmalDeck)
+ {
+ if (rank < Rank.Six)
+ continue;
+ }
+
+ cards.Add(new Card(rank, suit, sequenceNumber));
+ sequenceNumber++;
+ }
+ }
+ return cards.ToArray();
}
}
-}
+}
\ No newline at end of file
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..7c5e084
--- /dev/null
+++ b/Tyche/Tyche.DataAccess.MsSql/Entities/CardEntity.cs
@@ -0,0 +1,22 @@
+Ы
+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; }
+
+ 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..2c8d189
--- /dev/null
+++ b/Tyche/Tyche.DataAccess.MsSql/Entities/DeckEntity.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+
+namespace Tyche.DataAccess.MsSql.Entities
+{
+ public class DeckEntity
+ {
+ public int Id { 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
new file mode 100644
index 0000000..e4a7d74
--- /dev/null
+++ b/Tyche/Tyche.DataAccess.MsSql/Infrastructure/Automapper.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using Tyche.DataAccess.MsSql.Entities;
+using Tyche.Domain.Models;
+
+
+namespace Tyche.DataAccess.MsSql.Infrastructure
+{
+ internal class Automapper
+ {
+ public DeckEntity MappingToDeckEntity(Deck deck, string name)
+ {
+ var cards = new List();
+
+ foreach (var card in deck.Cards)
+ {
+ var cardEntity = new CardEntity
+ {
+ Rank = card.Rank.ToString(),
+ Suit = card.Suit.ToString(),
+ SequenceNumber = card.SequenceNumber
+ };
+ cards.Add(cardEntity);
+ }
+
+ return new DeckEntity
+ {
+ Name = name,
+ Deck = cards.ToArray()
+ };
+ }
+
+ public Deck MappingToDeck(DeckEntity deckEntity, string name)
+ {
+ var cards = new List();
+ var decks = deckEntity.Deck;
+ var sequenceNumber = 1;
+
+ foreach (var deck in decks)
+ {
+ 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(), 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/Migrations/20220503171037_First.Designer.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503171037_First.Designer.cs
new file mode 100644
index 0000000..ecdb105
--- /dev/null
+++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503171037_First.Designer.cs
@@ -0,0 +1,85 @@
+//
+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("20220503171037_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")
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.Property("SequenceNumber")
+ .HasColumnType("int");
+
+ b.Property("Suit")
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ 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("Name")
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ 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/20220503171037_First.cs b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503171037_First.cs
new file mode 100644
index 0000000..be7e41c
--- /dev/null
+++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/20220503171037_First.cs
@@ -0,0 +1,59 @@
+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"),
+ Name = table.Column(type: "nvarchar(50)", maxLength: 50, 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"),
+ 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 =>
+ {
+ 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..339f470
--- /dev/null
+++ b/Tyche/Tyche.DataAccess.MsSql/Migrations/DeckContextModelSnapshot.cs
@@ -0,0 +1,83 @@
+//
+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")
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ b.Property("SequenceNumber")
+ .HasColumnType("int");
+
+ b.Property("Suit")
+ .HasMaxLength(20)
+ .HasColumnType("nvarchar(20)");
+
+ 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("Name")
+ .HasMaxLength(50)
+ .HasColumnType("nvarchar(50)");
+
+ 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..c77c572
--- /dev/null
+++ b/Tyche/Tyche.DataAccess.MsSql/Repository/DeckRepository.cs
@@ -0,0 +1,109 @@
+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;
+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 async Task AddAsync(Deck deck, string name)
+ {
+ if (deck == null) return false;
+
+ if (String.IsNullOrWhiteSpace(name)) return false;
+
+ var deckEntity = _automapper.MappingToDeckEntity(deck, name);
+
+ await _context.AddAsync(deckEntity);
+ await _context.SaveChangesAsync();
+
+ return true;
+ }
+
+ public async Task GetDeckAsync(string name)
+ {
+ var deckEntity = await _context.Decks.FirstOrDefaultAsync(deck => deck.Name == name);
+ if (deckEntity == null) return null;
+
+ 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 async Task GetDecksNamesAsync()
+ {
+ var decksEntity = await _context.Decks.ToListAsync();
+ var decks = new List();
+
+ foreach (var deck in decksEntity)
+ {
+ decks.Add(deck.Name);
+ }
+ return decks.ToArray();
+ }
+
+ public async Task GetDecksAsync()
+ {
+ var decksEntity = await _context.Decks.ToListAsync();
+ if (decksEntity.Count == 0) return null;
+
+ foreach (var deckEntity in decksEntity)
+ {
+ deckEntity.Deck = await _context.Cards.Where(card => card.DeckId == deckEntity.Id).OrderByDescending(card => card.SequenceNumber).ToArrayAsync();
+ }
+
+ var decksResponse = new List();
+
+ foreach (var deck in decksEntity)
+ {
+ decksResponse.Add(_automapper.MappingToDeck(deck, deck.Name));
+ }
+
+ return decksResponse.ToArray();
+ }
+
+ public async Task DeleteAsync(string name)
+ {
+ var deck = await _context.Decks.FirstOrDefaultAsync(deck => deck.Name == name);
+ if (deck == null) return false;
+
+ _context.Decks.Remove(deck);
+
+ var cardsEntity = await _context.Cards.Where(card => card.DeckId == deck.Id).ToArrayAsync();
+ if (cardsEntity == null) return false;
+
+ _context.Cards.RemoveRange(cardsEntity);
+
+ await _context.SaveChangesAsync();
+ return true;
+ }
+
+ public async Task DeleteDecksAsync()
+ {
+ var decksEntity = _context.Decks.ToList();
+ if (decksEntity.Count == 0) return false;
+
+ foreach (var deckEntity in decksEntity)
+ {
+ await DeleteAsync(deckEntity.Name);
+ }
+ return true;
+ }
+ }
+}
diff --git a/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj b/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj
index aefaff0..2496076 100644
--- a/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj
+++ b/Tyche/Tyche.DataAccess.MsSql/Tyche.DataAccess.MsSql.csproj
@@ -4,6 +4,20 @@
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..4197163
--- /dev/null
+++ b/Tyche/Tyche.Domain/Interfaces/IDeckRepository.cs
@@ -0,0 +1,21 @@
+
+using System.Threading.Tasks;
+using Tyche.Domain.Models;
+
+namespace Tyche.Domain.Interfaces
+{
+ public interface IDeckRepository
+ {
+ Task AddAsync(Deck deck, string name);
+
+ Task GetDeckAsync(string name);
+
+ Task DeleteAsync(string name);
+
+ Task GetDecksAsync();
+
+ Task GetDecksNamesAsync();
+
+ Task DeleteDecksAsync();
+ }
+}
diff --git a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs
index da74af5..d891d92 100644
--- a/Tyche/Tyche.Domain/Interfaces/IDeckService.cs
+++ b/Tyche/Tyche.Domain/Interfaces/IDeckService.cs
@@ -1,12 +1,23 @@
-using Tyche.Domain.Models;
+using System.Threading.Tasks;
+using Tyche.Domain.Models;
namespace Tyche.Domain.Interfaces
{
public interface IDeckService
{
- Deck GetNamedDeck(int suit);
+ Task CreateNamedDeckAsync(string name, DeckType deckType);
- string CreateNamedDeck(Suit suit);
+ Task GetDeckByNameAsync(string name);
+
+ Task GetDecksAsync();
+
+ Task GetCreatedDecksNamesAsync();
+
+ Task DeleteDeckByNameAsync(string name);
+
+ Task ShuffleDeckByNameAsync(int sortOption, string name);
+
+ Task DeleteDecksAsync();
}
}
diff --git a/Tyche/Tyche.Domain/Models/Card.cs b/Tyche/Tyche.Domain/Models/Card.cs
index 999c669..9a8d0b0 100644
--- a/Tyche/Tyche.Domain/Models/Card.cs
+++ b/Tyche/Tyche.Domain/Models/Card.cs
@@ -3,10 +3,17 @@ namespace Tyche.Domain.Models
{
public class Card
{
- public int Id { get; set; }
+ public int SequenceNumber { get; }
- public Rank Rank { get; set; }
+ public Rank Rank { get; }
- public Suit Suit { get; set; }
+ public Suit Suit { get; }
+
+ public Card(Rank rank, Suit suit, int sequenceNumber)
+ {
+ Rank = rank;
+ Suit = suit;
+ SequenceNumber = sequenceNumber;
+ }
}
}
diff --git a/Tyche/Tyche.Domain/Models/Deck.cs b/Tyche/Tyche.Domain/Models/Deck.cs
index c7a5d89..87a0cd1 100644
--- a/Tyche/Tyche.Domain/Models/Deck.cs
+++ b/Tyche/Tyche.Domain/Models/Deck.cs
@@ -8,20 +8,25 @@ 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 Deck(Card[] cards)
+ 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();
}
}
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.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 178f6df..62213ce 100644
--- a/Tyche/Tyche.sln
+++ b/Tyche/Tyche.sln
@@ -9,11 +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.DataAccess.MsSql", "Tyche.DataAccess.Postgres\Tyche.DataAccess.MsSql.csproj", "{67AB4D45-4003-42C5-99DA-CD7361ECCB58}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.DataAccess.MsSql", "Tyche.DataAccess.MsSql\Tyche.DataAccess.MsSql.csproj", "{DF99F54A-0C13-47AC-BF39-06183CD40417}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.UnitTests", "Tyche.UnitTests\Tyche.UnitTests.csproj", "{80151682-6D95-4A4F-8D30-C370E9FEC971}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client.CLI", "Client.CLI\Client.CLI.csproj", "{146160C3-F8F7-4A03-A3DE-AD7A396EC808}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tyche.IntegrationTests", "Tyche.IntegrationTests\Tyche.IntegrationTests.csproj", "{45CEE789-234D-4ED9-A11C-8876D4C5DDB5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tyche.UnitTests", "Tyche.UnitTests\Tyche.UnitTests.csproj", "{8609CFE9-D770-45CF-B692-AF12A9BD5E85}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -33,18 +33,18 @@ 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
- {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
+ {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
+ {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
diff --git a/Tyche/Tyche/Tyche.API/Tyche.API.xml b/Tyche/Tyche/Tyche.API/Tyche.API.xml
new file mode 100644
index 0000000..7d0c147
--- /dev/null
+++ b/Tyche/Tyche/Tyche.API/Tyche.API.xml
@@ -0,0 +1,59 @@
+
+
+
+ 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 all decks of cards
+
+
+
+
+
+ Deleting deck of cards by name
+
+
+
+
+
+ Deleting all deck of cards
+
+
+
+
+
+
+ Shuffle dekcs of cards in the selected way
+
+
+
+
+
+