Browse Source

add: Buying from auction. Buying confirmation. Another instances for database (throws exception, when use one instance)

Tigran 4 years ago
parent
commit
deab8e06cd
29 changed files with 411 additions and 95 deletions
  1. 2 2
      CardCollector.sln.DotSettings.user
  2. 5 10
      CardCollector/Bot.cs
  3. 27 0
      CardCollector/Commands/CallbackQuery/BackToStickerQuery.cs
  4. 27 8
      CardCollector/Commands/CallbackQuery/BuyStickerQuery.cs
  5. 4 0
      CardCollector/Commands/CallbackQuery/CallbackQuery.cs
  6. 36 0
      CardCollector/Commands/CallbackQuery/ConfirmBuyingQuery.cs
  7. 4 8
      CardCollector/Commands/CallbackQuery/CountQuery.cs
  8. 3 0
      CardCollector/Commands/ChosenInlineResult/ChosenInlineResult.cs
  9. 1 1
      CardCollector/Commands/ChosenInlineResult/SelectStickerInlineResult.cs
  10. 34 0
      CardCollector/Commands/ChosenInlineResult/SelectTraderResult.cs
  11. 17 9
      CardCollector/Controllers/AuctionController.cs
  12. 9 0
      CardCollector/Controllers/ShopController.cs
  13. 27 1
      CardCollector/DataBase/CardCollectorDatabase.cs
  14. 1 3
      CardCollector/DataBase/Entity/AuctionEntity.cs
  15. 2 2
      CardCollector/DataBase/Entity/CashEntity.cs
  16. 30 11
      CardCollector/DataBase/EntityDao/AuctionDao.cs
  17. 3 1
      CardCollector/DataBase/EntityDao/CashDao.cs
  18. 10 1
      CardCollector/DataBase/EntityDao/ShopDao.cs
  19. 3 1
      CardCollector/DataBase/EntityDao/StickerDao.cs
  20. 11 6
      CardCollector/DataBase/EntityDao/UserDao.cs
  21. 3 1
      CardCollector/DataBase/EntityDao/UserStickerRelationDao.cs
  22. 3 0
      CardCollector/Others/StickerInfo.cs
  23. 9 0
      CardCollector/Resources/Command.Designer.cs
  24. 3 0
      CardCollector/Resources/Command.resx
  25. 89 30
      CardCollector/Resources/Keyboard.cs
  26. 27 0
      CardCollector/Resources/Messages.Designer.cs
  27. 9 0
      CardCollector/Resources/Messages.resx
  28. 9 0
      CardCollector/Resources/Text.Designer.cs
  29. 3 0
      CardCollector/Resources/Text.resx

+ 2 - 2
CardCollector.sln.DotSettings.user

@@ -1,11 +1,11 @@
 <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
 	
-	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FCommand/@EntryIndexedValue">False</s:Boolean>
+	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FCommand/@EntryIndexedValue">True</s:Boolean>
 	
 	
 	
 	
-	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FMessages/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FMessages/@EntryIndexedValue">False</s:Boolean>
 	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FSortingTypes/@EntryIndexedValue">False</s:Boolean>
 	<s:Boolean x:Key="/Default/ResxEditorPersonal/CheckedGroups/=CardCollector_002FResources_002FText/@EntryIndexedValue">False</s:Boolean>
 	

+ 5 - 10
CardCollector/Bot.cs

@@ -27,7 +27,7 @@ namespace CardCollector
         {
             var cts = new CancellationTokenSource();
             Client.StartReceiving(HandleUpdateAsync, HandleErrorAsync, cancellationToken: cts.Token);
-            Client.SetMyCommandsAsync(_commands, BotCommandScope.AllPrivateChats());
+            Client.SetMyCommandsAsync(_commands, BotCommandScope.AllPrivateChats(), cancellationToken: cts.Token);
             RunMemoryCleaner();
             
             Console.ReadLine();
@@ -46,16 +46,11 @@ namespace CardCollector
             timer.Elapsed += UserDao.ClearMemory;
         }
 
-        private static async void SavingChanges(object o, ElapsedEventArgs e)
+        private static void SavingChanges(object o, ElapsedEventArgs e)
         {
-            try
-            {
-                await CardCollectorDatabase.Instance.SaveChangesAsync();
-            }
-            catch (Exception)
-            {
-                // ignored
-            }
+            try {
+                CardCollectorDatabase.SaveAllChangesAsync();
+            } catch (Exception) { /*ignored*/ }
         }
     }
 }

+ 27 - 0
CardCollector/Commands/CallbackQuery/BackToStickerQuery.cs

@@ -0,0 +1,27 @@
+using System.Threading.Tasks;
+using CardCollector.Controllers;
+using CardCollector.DataBase.Entity;
+using CardCollector.Resources;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands.CallbackQuery
+{
+    public class BackToStickerQuery : CallbackQuery
+    {
+        protected override string CommandText => Command.back_to_sticker;
+        public override async Task Execute()
+        {
+            var sticker = User.Session.SelectedSticker;
+            var stickerCount = sticker.TraderInfo?.Quantity ?? sticker.Count;
+            var text = $"\n<<{sticker.Title}>>" +
+                       $"\n{Text.emoji}: {sticker.Emoji}" +
+                       $"\n{Text.author}: {sticker.Author}" +
+                       $"\n{Text.count}: {(stickerCount != -1 ? stickerCount : "∞")}" +
+                       $"\n{sticker.IncomeCoins}{Text.coin} / {sticker.IncomeGems}{Text.gem} {sticker.IncomeTime}{Text.time}{Text.minutes}";
+            await MessageController.EditMessage(User, CallbackMessageId, text, Keyboard.GetStickerKeyboard(User.Session));
+        }
+
+        public BackToStickerQuery() { }
+        public BackToStickerQuery(UserEntity user, Update update) : base(user, update) { }
+    }
+}

+ 27 - 8
CardCollector/Commands/CallbackQuery/BuyStickerQuery.cs

@@ -13,25 +13,44 @@ namespace CardCollector.Commands.CallbackQuery
         public override async Task Execute()
         {
             var selectedSticker = User.Session.SelectedSticker;
-            var product = await ShopDao.GetSticker(selectedSticker.Id);
-            if (selectedSticker.Count > product.Count && !product.IsInfinite)
+            var count = User.Session.State switch
+            {
+                UserState.AuctionMenu => await AuctionController.GetStickerCount(selectedSticker.TraderInfo.Id),
+                UserState.ShopMenu => await ShopController.GetStickerCount(selectedSticker.Id),
+                _ => 0
+            };
+            var coinsPrice = User.Session.SelectedSticker.Count * (User.Session.State == UserState.AuctionMenu 
+                ? User.Session.SelectedSticker.TraderInfo.PriceCoins
+                : User.Session.SelectedSticker.PriceCoins);
+            var gemsPrice = User.Session.SelectedSticker.Count * (User.Session.State == UserState.AuctionMenu 
+                ? User.Session.SelectedSticker.TraderInfo.PriceGems
+                : User.Session.SelectedSticker.PriceGems);
+            if (count < selectedSticker.Count && count != -1)
                 await MessageController.AnswerCallbackQuery(User, Update.CallbackQuery!.Id, Messages.not_enougth_stickers);
-            else if (selectedSticker.Count * selectedSticker.PriceCoins > User.Cash.Coins)
+            else if (coinsPrice > User.Cash.Coins)
                 await MessageController.AnswerCallbackQuery(User, Update.CallbackQuery!.Id, Messages.not_enougth_coins);
-            else if (selectedSticker.Count * selectedSticker.PriceGems > User.Cash.Gems)
+            else if (gemsPrice > User.Cash.Gems)
                 await MessageController.AnswerCallbackQuery(User, Update.CallbackQuery!.Id, Messages.not_enougth_gems);
             else
             {
-                if (!product.IsInfinite) product.Count -= selectedSticker.Count;
+                switch (User.Session.State)
+                {
+                    case UserState.AuctionMenu:
+                        await AuctionController.BuyCard(selectedSticker);
+                        break;
+                    case UserState.ShopMenu:
+                        await ShopController.SoldCard(selectedSticker);
+                        break;
+                }
                 if (User.Stickers.ContainsKey(selectedSticker.Md5Hash))
                 {
                     await User.Session.PayOutOne(selectedSticker.Md5Hash);
                     await MessageController.AnswerCallbackQuery(User, Update.CallbackQuery!.Id, 
-                        $"{Messages.you_collected} {User.Session.IncomeCoins}{Text.coin}/{User.Session.IncomeGems}{Text.gem}");
+                        $"{Messages.you_collected} {User.Session.IncomeCoins}{Text.coin} / {User.Session.IncomeGems}{Text.gem}");
                 }
                 await UserStickerRelationDao.AddNew(User, selectedSticker, selectedSticker.Count);
-                User.Cash.Coins -= selectedSticker.Count * selectedSticker.PriceCoins;
-                User.Cash.Gems -= selectedSticker.Count * selectedSticker.PriceGems;
+                User.Cash.Coins -= coinsPrice;
+                User.Cash.Gems -= gemsPrice;
                 User.Session.SelectedSticker = null;
                 await User.ClearChat();
             }

+ 4 - 0
CardCollector/Commands/CallbackQuery/CallbackQuery.cs

@@ -46,8 +46,12 @@ namespace CardCollector.Commands.CallbackQuery
             new CollectIncomeQuery(),
             /* Команда для упралвения количеством стикеров */
             new CountQuery(),
+            /* Команда для подтверждения покупки */
+            new ConfirmBuyingQuery(),
             /* Команда для покупки стикера */
             new BuyStickerQuery(),
+            /* Команда возврата к стикеру */
+            new BackToStickerQuery(),
             
             /* Отмена в момент выбора "значения фильтра", не в самом меню */
             new BackToFiltersMenu(),

+ 36 - 0
CardCollector/Commands/CallbackQuery/ConfirmBuyingQuery.cs

@@ -0,0 +1,36 @@
+using System.Threading.Tasks;
+using CardCollector.Controllers;
+using CardCollector.DataBase.Entity;
+using CardCollector.Resources;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands.CallbackQuery
+{
+    public class ConfirmBuyingQuery : CallbackQuery
+    {
+        protected override string CommandText => Command.confirm_buying;
+        public override async Task Execute()
+        {
+            var coinsPrice = User.Session.SelectedSticker.Count * (User.Session.State == UserState.AuctionMenu 
+                ? User.Session.SelectedSticker.TraderInfo.PriceCoins
+                : User.Session.SelectedSticker.PriceCoins);
+            var gemsPrice = User.Session.SelectedSticker.Count * (User.Session.State == UserState.AuctionMenu 
+                ? User.Session.SelectedSticker.TraderInfo.PriceGems
+                : User.Session.SelectedSticker.PriceGems);
+            if (coinsPrice > User.Cash.Coins)
+                await MessageController.AnswerCallbackQuery(User, Update.CallbackQuery!.Id, Messages.not_enougth_coins);
+            else if (gemsPrice > User.Cash.Gems)
+                await MessageController.AnswerCallbackQuery(User, Update.CallbackQuery!.Id, Messages.not_enougth_gems);
+            else
+            {
+                var text = $"{Messages.confirm_buying}" +
+                           $"\n{User.Session.SelectedSticker.Count}{Text.items} {Text.per} {coinsPrice}{Text.coin} / {gemsPrice}{Text.gem}" +
+                           $"\n{Messages.are_you_sure}";
+                await MessageController.EditMessage(User, CallbackMessageId, text, Keyboard.GetConfirmationKeyboard(Command.buy_sticker));
+            }
+        }
+
+        public ConfirmBuyingQuery() { }
+        public ConfirmBuyingQuery(UserEntity user, Update update) : base(user, update) { }
+    }
+}

+ 4 - 8
CardCollector/Commands/CallbackQuery/CountQuery.cs

@@ -15,10 +15,8 @@ namespace CardCollector.Commands.CallbackQuery
             var stickerCount = User.Session.State switch
             {
                 UserState.CollectionMenu => User.Stickers[User.Session.SelectedSticker.Md5Hash].Count,
-                UserState.ShopMenu => await ShopController.GetStickerCount(
-                    User.Session.SelectedSticker.Id),
-                UserState.AuctionMenu => await AuctionController.GetStickerCount(
-                    User.Session.SelectedSticker.Id),
+                UserState.ShopMenu => await ShopController.GetStickerCount(User.Session.SelectedSticker.Id),
+                UserState.AuctionMenu => User.Session.SelectedSticker.TraderInfo.Quantity,
                 _ => 0
             };
             if (CallbackData.Contains('+'))
@@ -26,8 +24,7 @@ namespace CardCollector.Commands.CallbackQuery
                 if (buyPositionCount < stickerCount || stickerCount == -1)
                 {
                     User.Session.SelectedSticker.Count++;
-                    await MessageController.EditReplyMarkup(User, CallbackMessageId,
-                        Keyboard.GetStickerKeyboard(User.Session.SelectedSticker, User.Session.State));
+                    await MessageController.EditReplyMarkup(User, CallbackMessageId, Keyboard.GetStickerKeyboard(User.Session));
                 }
                 else await MessageController.AnswerCallbackQuery(User, 
                     Update.CallbackQuery!.Id, Messages.cant_increase);
@@ -37,8 +34,7 @@ namespace CardCollector.Commands.CallbackQuery
                 if (buyPositionCount > 1)
                 {
                     User.Session.SelectedSticker.Count--;
-                    await MessageController.EditReplyMarkup(User, CallbackMessageId,
-                        Keyboard.GetStickerKeyboard(User.Session.SelectedSticker, User.Session.State));
+                    await MessageController.EditReplyMarkup(User, CallbackMessageId, Keyboard.GetStickerKeyboard(User.Session));
                 }
                 else await MessageController.AnswerCallbackQuery(User, 
                     Update.CallbackQuery!.Id, Messages.cant_decrease);

+ 3 - 0
CardCollector/Commands/ChosenInlineResult/ChosenInlineResult.cs

@@ -33,6 +33,9 @@ namespace CardCollector.Commands.ChosenInlineResult
         
             // Обработка результата при отправке стикера
             new SendStickerResult(),
+            // Обработка результата при выборе продавца
+            new SelectTraderResult(),
+            
             new SelectStickerInlineResult(),
         };
         

+ 1 - 1
CardCollector/Commands/ChosenInlineResult/SelectStickerInlineResult.cs

@@ -33,7 +33,7 @@ namespace CardCollector.Commands.ChosenInlineResult
             var stickerMessage = await MessageController.SendSticker(User, sticker.Id);
             var stickerInfo = new StickerInfo(sticker) {Count = 1};
             User.Session.SelectedSticker = stickerInfo;
-            var infoMessage = await MessageController.SendMessage(User, messageText, Keyboard.GetStickerKeyboard(stickerInfo, User.Session.State));
+            var infoMessage = await MessageController.SendMessage(User, messageText, Keyboard.GetStickerKeyboard(User.Session));
             User.Session.Messages.Add(stickerMessage.MessageId);
             User.Session.Messages.Add(infoMessage.MessageId);
         }

+ 34 - 0
CardCollector/Commands/ChosenInlineResult/SelectTraderResult.cs

@@ -0,0 +1,34 @@
+using System.Threading.Tasks;
+using CardCollector.Controllers;
+using CardCollector.DataBase.Entity;
+using CardCollector.DataBase.EntityDao;
+using CardCollector.Resources;
+using Telegram.Bot.Types;
+
+namespace CardCollector.Commands.ChosenInlineResult
+{
+    public class SelectTraderResult : ChosenInlineResult
+    {
+        protected override string CommandText => Command.buy_sticker;
+        public override async Task Execute()
+        {
+            await User.ClearChat();
+            var productId = int.Parse(InlineResult.Split('=')[1]);
+            var trader = await AuctionDao.GetTraderInfo(productId);
+            User.Session.SelectedSticker.TraderInfo = trader;
+            var sticker = User.Session.SelectedSticker;
+            var text = $"\n<<{sticker.Title}>>" +
+                       $"\n{Text.emoji}: {sticker.Emoji}" +
+                       $"\n{Text.author}: {sticker.Author}" +
+                       $"\n{Text.count}: {sticker.TraderInfo.Quantity}" +
+                       $"\n{sticker.IncomeCoins}{Text.coin} / {sticker.IncomeGems}{Text.gem} {sticker.IncomeTime}{Text.time}{Text.minutes}";
+            var messageSticker = await MessageController.SendSticker(User, User.Session.SelectedSticker.Id);
+            var message = await MessageController.SendMessage(User, text, Keyboard.GetStickerKeyboard(User.Session));
+            User.Session.Messages.Add(messageSticker.MessageId);
+            User.Session.Messages.Add(message.MessageId);
+        }
+
+        public SelectTraderResult() { }
+        public SelectTraderResult(UserEntity user, Update update, string inlineResult) : base(user, update, inlineResult) { }
+    }
+}

+ 17 - 9
CardCollector/Controllers/AuctionController.cs

@@ -1,11 +1,11 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading.Tasks;
+using CardCollector.DataBase;
 using CardCollector.DataBase.Entity;
 using CardCollector.DataBase.EntityDao;
 using CardCollector.Others;
 using CardCollector.Resources;
-using Telegram.Bot.Types.InlineQueryResults;
 
 namespace CardCollector.Controllers 
 {
@@ -43,15 +43,18 @@ namespace CardCollector.Controllers
         }
         
         //покупка стикера
-        private static async Task BuyCard(UserEntity user, int price, int count = 1)
+        public static async Task BuyCard(StickerInfo sticker)
         {
-            // TODO @darkgolly попробуй переписать метод аналогично тому, что выше
-            var hash = user.Session.SelectedSticker.Md5Hash;
-            user.Stickers[hash].Count += user.Session.SelectedSticker.Count;
-            user.Cash.Coins -= user.Session.IncomeCoins;
-            user.Cash.Gems -= user.Session.IncomeGems;
-            
-            AuctionDao.SoldStikers(hash);
+            var product = await AuctionDao.GetProduct(sticker.TraderInfo.Id);
+            product.Quantity -= sticker.Count;
+            var user = await UserDao.GetById(product.Trader);
+            var coinsSum = product.PriceCoins * sticker.Count;
+            var gemsSum = product.PriceGems * sticker.Count;
+            await MessageController.SendMessage(user, $"{Messages.you_sold} {sticker.Title} {sticker.Count}{Text.items}" +
+                                                      $"\n{Messages.you_collected} {coinsSum}{Text.coin} / {gemsSum}{Text.gem}");
+            user.Cash.Coins += coinsSum;
+            user.Cash.Gems += gemsSum;
+            if (product.Quantity == 0) AuctionDao.DeleteRow(sticker.TraderInfo.Id);
         }
         
         public static async Task<int> GetStickerCount(string stickerId)
@@ -76,5 +79,10 @@ namespace CardCollector.Controllers
             }
             return result;
         }
+
+        public static async Task<int> GetStickerCount(int productId)
+        {
+            return await AuctionDao.GetQuantity(productId);
+        }
     }
 }

+ 9 - 0
CardCollector/Controllers/ShopController.cs

@@ -3,6 +3,7 @@ using System.Linq;
 using System.Threading.Tasks;
 using CardCollector.DataBase.Entity;
 using CardCollector.DataBase.EntityDao;
+using CardCollector.Others;
 
 namespace CardCollector.Controllers
 {
@@ -19,5 +20,13 @@ namespace CardCollector.Controllers
             var result = await ShopDao.GetAllShopPositions(filter);
             return result.ToList();
         }
+
+        public static async Task SoldCard(StickerInfo selectedSticker)
+        {
+            var product = await ShopDao.GetSticker(selectedSticker.Id);
+            if (product.IsInfinite) return;
+            product.Count -= selectedSticker.Count;
+            if (product.Count == 0) ShopDao.DeleteRow(product.Id);
+        }
     }
 }

+ 27 - 1
CardCollector/DataBase/CardCollectorDatabase.cs

@@ -1,3 +1,5 @@
+using System;
+using System.Collections.Generic;
 using CardCollector.DataBase.Entity;
 using Microsoft.EntityFrameworkCore;
 
@@ -25,7 +27,31 @@ namespace CardCollector.DataBase
                 return _instance;
             }
         }
-        
+
+        private static Dictionary<Type, CardCollectorDatabase> _specificInstances = new ();
+
+        public static CardCollectorDatabase GetSpecificInstance(Type type)
+        {
+            try
+            {
+                return _specificInstances[type];
+            }
+            catch (Exception)
+            {
+                var newInstance = new CardCollectorDatabase();
+                _specificInstances.Add(type, newInstance);
+                newInstance.Database.EnsureCreated();
+                return newInstance;
+            }
+        }
+
+        public static async void SaveAllChangesAsync()
+        {
+            await Instance.SaveChangesAsync();
+            foreach (var instance in _specificInstances.Values)
+                await instance.SaveChangesAsync();
+        }
+
         /* Таблицы базы данных, представленные Entity объектами */
         public DbSet<UserEntity> Users { get; set; }
         public DbSet<CashEntity> CashTable { get; set; }

+ 1 - 3
CardCollector/DataBase/Entity/AuctionEntity.cs

@@ -1,7 +1,5 @@
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations.Schema;
-using Telegram.Bot.Types.InlineQueryResults;
 
 namespace CardCollector.DataBase.Entity
 {

+ 2 - 2
CardCollector/DataBase/Entity/CashEntity.cs

@@ -13,9 +13,9 @@ namespace CardCollector.DataBase.Entity
         [Column("user_id"), MaxLength(127)] public long UserId { get; set; }
         
         /* Количество монет */
-        [Column("coins"), MaxLength(32)] public int Coins { get; set; } = 0;
+        [Column("coins"), MaxLength(32)] public int Coins { get; set; } = 10000;
         
         /* Количество алмазов */
-        [Column("gems"), MaxLength(32)] public int Gems { get; set; } = 0;
+        [Column("gems"), MaxLength(32)] public int Gems { get; set; } = 1000;
     }
 }

+ 30 - 11
CardCollector/DataBase/EntityDao/AuctionDao.cs

@@ -2,23 +2,32 @@
 using System.Linq;
 using System.Threading.Tasks;
 using CardCollector.DataBase.Entity;
+using CardCollector.Others;
 using Microsoft.EntityFrameworkCore;
 
 namespace CardCollector.DataBase.EntityDao
 {
     public static class AuctionDao
     {
-        /* Таблица stickers в представлении Entity Framework */
-        private static readonly DbSet<AuctionEntity> Table = CardCollectorDatabase.Instance.Auction;
+        private static readonly CardCollectorDatabase Instance = CardCollectorDatabase.GetSpecificInstance(typeof(AuctionDao));
+        /* Таблица auction в представлении Entity Framework */
+        private static readonly DbSet<AuctionEntity> Table = Instance.Auction;
         
         public static async Task<List<AuctionEntity>> GetProducts(string stickerId)
         {
-            /* Заменил цикл на LINQ выражение и тип возвращаемого значение - список позиций,
+            /* Заменил цикл на LINQ выражение и тип возвращаемого значения - список позиций,
              так как один и тот же стикер может продавать несколько людей */
             return await Table
                 .Where(e => e.StickerId == stickerId).ToListAsync();
         }
 
+        public static async Task<TraderInformation> GetTraderInfo(int productId)
+        {
+            var product = await Table.FirstAsync(item => item.Id == productId);
+            var trader = await UserDao.GetById(product.Trader);
+            return new TraderInformation(product) {Username = trader.Username};
+        }
+
         public static async Task<int> GetTotalQuantity(string stickerId)
         {
             /* Добавил метод, который считает общее количество данных стикеров на аукционе */
@@ -36,18 +45,28 @@ namespace CardCollector.DataBase.EntityDao
             return stickersList.Where(e => entityList.Contains(e.Id));
         }
         //добавляем объект в аукцион
-        public static void AddNew(AuctionEntity product)
+        public static async void AddNew(AuctionEntity product)
         {
-            Table.AddAsync(product);
+            await Table.AddAsync(product);
+            await Instance.SaveChangesAsync();
         }
         //удаляем проданный объект
-        public static void SoldStikers(string hash)
+        public static async void DeleteRow(int productId)
+        {
+            if (await Table.FirstOrDefaultAsync(c => c.Id == productId) is not { } item) return;
+            Table.Attach(item);
+            Table.Remove(item);
+            await Instance.SaveChangesAsync();
+        }
+
+        public static async Task<int> GetQuantity(int productId)
+        {
+            return (await Table.FirstAsync(item => item.Id == productId)).Quantity;
+        }
+
+        public static async Task<AuctionEntity> GetProduct(int productId)
         {
-            var list = Table
-                .Where(c => c.StickerId == hash)
-                .FirstOrDefault();
-            
-            Table.Remove(list);
+            return await Table.FirstAsync(item => item.Id == productId);
         }
     }
 }

+ 3 - 1
CardCollector/DataBase/EntityDao/CashDao.cs

@@ -7,8 +7,9 @@ namespace CardCollector.DataBase.EntityDao
     /* Класс, позволяющий получить доступ к объектам таблицы Cash*/
     public static class CashDao
     {
+        private static readonly CardCollectorDatabase Instance = CardCollectorDatabase.GetSpecificInstance(typeof(CashDao));
         /* Таблица cash в представлении EntityFramework */
-        private static readonly DbSet<CashEntity> Table = CardCollectorDatabase.Instance.CashTable;
+        private static readonly DbSet<CashEntity> Table = Instance.CashTable;
         
         /* Получение объекта по Id */
         public static async Task<CashEntity> GetById(long userId)
@@ -22,6 +23,7 @@ namespace CardCollector.DataBase.EntityDao
         {
             var cash = new CashEntity { UserId = userId };
             var result = await Table.AddAsync(cash);
+            await Instance.SaveChangesAsync();
             return result.Entity;
         }
     }

+ 10 - 1
CardCollector/DataBase/EntityDao/ShopDao.cs

@@ -9,7 +9,8 @@ namespace CardCollector.DataBase.EntityDao
 {
     public static class ShopDao
     {
-        private static readonly DbSet<ShopEntity> Table = CardCollectorDatabase.Instance.Shop;
+        private static readonly CardCollectorDatabase Instance = CardCollectorDatabase.GetSpecificInstance(typeof(ShopDao));
+        private static readonly DbSet<ShopEntity> Table = Instance.Shop;
 
         public static async Task<IEnumerable<StickerEntity>> GetAllShopPositions(string filter = "")
         {
@@ -25,5 +26,13 @@ namespace CardCollector.DataBase.EntityDao
         {
             return await Table.FirstAsync(e => e.StickerId == stickerId);
         }
+
+        public static async void DeleteRow(int productId)
+        {
+            if (await Table.FirstOrDefaultAsync(c => c.Id == productId) is not { } item) return;
+            Table.Attach(item);
+            Table.Remove(item);
+            await Instance.SaveChangesAsync();
+        }
     }
 }

+ 3 - 1
CardCollector/DataBase/EntityDao/StickerDao.cs

@@ -10,8 +10,9 @@ namespace CardCollector.DataBase.EntityDao
     /* Класс, предоставляющий доступ к объектам таблицы Stickers*/
     public static class StickerDao
     {
+        private static readonly CardCollectorDatabase Instance = CardCollectorDatabase.GetSpecificInstance(typeof(StickerDao));
         /* Таблица stickers в представлении Entity Framework */
-        private static readonly DbSet<StickerEntity> Table = CardCollectorDatabase.Instance.Stickers;
+        private static readonly DbSet<StickerEntity> Table = Instance.Stickers;
         
         /* Получение информации о стикере по его хешу, возвращает Null, если стикера не существует */
         public static async Task<StickerEntity> GetStickerByHash(string hash)
@@ -40,6 +41,7 @@ namespace CardCollector.DataBase.EntityDao
                 Md5Hash = Utilities.CreateMd5(fileId)
             };
             var result = await Table.AddAsync(cash);
+            await Instance.SaveChangesAsync();
             return result.Entity;
         }
 

+ 11 - 6
CardCollector/DataBase/EntityDao/UserDao.cs

@@ -12,8 +12,9 @@ namespace CardCollector.DataBase.EntityDao
     /* Класс, предоставляющий доступ к объектам пользователей таблицы Users */
     public static class UserDao
     {
+        private static readonly CardCollectorDatabase Instance = CardCollectorDatabase.GetSpecificInstance(typeof(UserDao));
         /* Таблица Users в представлении EntityFramework */
-        private static readonly DbSet<UserEntity> Table = CardCollectorDatabase.Instance.Users;
+        private static readonly DbSet<UserEntity> Table = Instance.Users;
         
         /* Активные пользователи в системе */
         private static readonly Dictionary<long, UserEntity> ActiveUsers = new();
@@ -44,6 +45,11 @@ namespace CardCollector.DataBase.EntityDao
             return result;
         }
 
+        public static async Task<UserEntity> GetById(long userId)
+        {
+            return await Table.FirstAsync(item => item.Id == userId);
+        }
+
         /* Получение пользователя по представлению user из Базы данных */
         public static async Task<List<UserEntity>> GetUsersList(string filter)
         {
@@ -61,6 +67,7 @@ namespace CardCollector.DataBase.EntityDao
                 IsBlocked = false
             };
             var result = await Table.AddAsync(userEntity);
+            await Instance.SaveChangesAsync();
             return result.Entity;
         }
 
@@ -68,11 +75,9 @@ namespace CardCollector.DataBase.EntityDao
         {
             foreach (var (id, user) in ActiveUsers)
             {
-                if (user.Session.GetLastAccessInterval() > Constants.SESSION_ACTIVE_PERIOD)
-                {
-                    user.Session.EndSession();
-                    ActiveUsers.Remove(id);
-                }
+                if (user.Session.GetLastAccessInterval() <= Constants.SESSION_ACTIVE_PERIOD) continue;
+                user.Session.EndSession();
+                ActiveUsers.Remove(id);
             }
         }
     }

+ 3 - 1
CardCollector/DataBase/EntityDao/UserStickerRelationDao.cs

@@ -9,8 +9,9 @@ namespace CardCollector.DataBase.EntityDao
     /* Предоставляет доступ к соотношениям таблицы user_to_sticker_relation */
     public static class UserStickerRelationDao
     {
+        private static readonly CardCollectorDatabase Instance = CardCollectorDatabase.GetSpecificInstance(typeof(UserStickerRelationDao));
         /* Таблица user_to_sticker_relation в представлении Entity Framework */
-        private static readonly DbSet<UserStickerRelationEntity> Table = CardCollectorDatabase.Instance.UserStickerRelations;
+        private static readonly DbSet<UserStickerRelationEntity> Table = Instance.UserStickerRelations;
         
         /* Возвращает словарь стикеров по Id пользователя */
         public static async Task<Dictionary<string, UserStickerRelationEntity>> GetListById(long userId)
@@ -38,6 +39,7 @@ namespace CardCollector.DataBase.EntityDao
             };
             var result = await Table.AddAsync(relation);
             user.Stickers.Add(sticker.Md5Hash, result.Entity);
+            await Instance.SaveChangesAsync();
             return result.Entity;
         }
     }

+ 3 - 0
CardCollector/Others/StickerInfo.cs

@@ -22,5 +22,8 @@ namespace CardCollector.Others
         }
         
         public int Count;
+        
+        
+        public TraderInformation TraderInfo = null;
     }
 }

+ 9 - 0
CardCollector/Resources/Command.Designer.cs

@@ -78,6 +78,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to back_to_sticker.
+        /// </summary>
+        internal static string back_to_sticker {
+            get {
+                return ResourceManager.GetString("back_to_sticker", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to buy.
         /// </summary>

+ 3 - 0
CardCollector/Resources/Command.resx

@@ -90,4 +90,7 @@
     <data name="show_traders" xml:space="preserve">
         <value>show_traders</value>
     </data>
+    <data name="back_to_sticker" xml:space="preserve">
+        <value>back_to_sticker</value>
+    </data>
 </root>

+ 89 - 30
CardCollector/Resources/Keyboard.cs

@@ -173,38 +173,97 @@ namespace CardCollector.Resources
             return new InlineKeyboardMarkup(keyboardList);
         }
 
-        public static InlineKeyboardMarkup GetStickerKeyboard(StickerInfo stickerInfo, UserState state)
+        public static InlineKeyboardMarkup GetShopStickerKeyboard(StickerInfo stickerInfo)
         {
-            return state switch
+            return new InlineKeyboardMarkup(new[] {
+                new[]
+                {
+                    InlineKeyboardButton.WithCallbackData(
+                        $"{Text.buy} ({stickerInfo.Count})" +
+                        $" {stickerInfo.PriceCoins * stickerInfo.Count}{Text.coin} / " +
+                        $"{stickerInfo.PriceGems * stickerInfo.Count}{Text.gem}",
+                        Command.confirm_buying),
+                },
+                new[]
+                {
+                    InlineKeyboardButton.WithCallbackData(Text.minus, $"{Command.count}-"),
+                    InlineKeyboardButton.WithCallbackData(Text.plus, $"{Command.count}+"),
+                },
+                new[] {InlineKeyboardButton.WithCallbackData(Text.back, $"{Command.back}={Command.clear_chat}")},
+            });
+        }
+
+        public static InlineKeyboardMarkup GetCollectionStickerKeyboard(StickerInfo stickerInfo)
+        {
+            return new InlineKeyboardMarkup(new[] {
+                new[] {InlineKeyboardButton.WithSwitchInlineQuery(Text.send_sticker, stickerInfo.Title)},
+                new[] {InlineKeyboardButton.WithCallbackData($"{Text.sell_on_auction} ({stickerInfo.Count})", Command.confirm_selling)},
+                new[]
+                {
+                    InlineKeyboardButton.WithCallbackData(Text.minus, $"{Command.count}-"),
+                    InlineKeyboardButton.WithCallbackData(Text.plus, $"{Command.count}+"),
+                },
+                new[] {InlineKeyboardButton.WithCallbackData(Text.combine, Command.combine)},
+                new[] {InlineKeyboardButton.WithCallbackData(Text.back, $"{Command.back}={Command.clear_chat}")},
+            });
+        }
+
+        public static InlineKeyboardMarkup GetAuctionStickerKeyboard()
+        {
+            return new InlineKeyboardMarkup(new[] {
+                new[] {InlineKeyboardButton.WithSwitchInlineQueryCurrentChat(Text.show_traders)},
+                new[] {InlineKeyboardButton.WithCallbackData(Text.back, $"{Command.back}={Command.clear_chat}")},
+            });
+        }
+
+        public static InlineKeyboardMarkup GetAuctionProductKeyboard(StickerInfo stickerInfo)
+        {
+            return new InlineKeyboardMarkup(new[] {
+                new[]
+                {
+                    InlineKeyboardButton.WithCallbackData(
+                        $"{Text.buy} ({stickerInfo.Count})" +
+                        $" {stickerInfo.TraderInfo.PriceCoins * stickerInfo.Count}{Text.coin} / " +
+                        $"{stickerInfo.TraderInfo.PriceGems * stickerInfo.Count}{Text.gem}",
+                        Command.confirm_buying),
+                },
+                new[]
+                {
+                    InlineKeyboardButton.WithCallbackData(Text.minus, $"{Command.count}-"),
+                    InlineKeyboardButton.WithCallbackData(Text.plus, $"{Command.count}+"),
+                },
+                new[] {InlineKeyboardButton.WithCallbackData(Text.back, $"{Command.back}={Command.clear_chat}")},
+            });
+        }
+
+        public static InlineKeyboardMarkup GetStickerKeyboard(StickerInfo stickerInfo)
+        {
+            return new InlineKeyboardMarkup(new[] {
+                new[] {InlineKeyboardButton.WithSwitchInlineQuery(Text.send_sticker, stickerInfo.Title)},
+                new[] {InlineKeyboardButton.WithCallbackData(Text.back, Command.clear_chat)},
+            });
+        }
+
+        public static InlineKeyboardMarkup GetConfirmationKeyboard(string command)
+        {
+            return new InlineKeyboardMarkup(new[] {
+                new[]
+                {
+                    InlineKeyboardButton.WithCallbackData(Text.no, Command.back_to_sticker),
+                    InlineKeyboardButton.WithCallbackData(Text.yes, command)
+                }
+            });
+        }
+
+        public static InlineKeyboardMarkup GetStickerKeyboard(UserSession session)
+        {
+            return session.State switch
             {
-                UserState.ShopMenu => new InlineKeyboardMarkup(new[] {
-                    new[] {InlineKeyboardButton.WithCallbackData($"{Text.buy} ({stickerInfo.Count})", Command.buy_sticker),},
-                    new[]
-                    {
-                        InlineKeyboardButton.WithCallbackData(Text.minus, $"{Command.count}-"),
-                        InlineKeyboardButton.WithCallbackData(Text.plus, $"{Command.count}+"),
-                    },
-                    new[] {InlineKeyboardButton.WithCallbackData(Text.back, $"{Command.back}={Command.clear_chat}")},
-                }),
-                UserState.AuctionMenu => new InlineKeyboardMarkup(new[] {
-                    new[] {InlineKeyboardButton.WithSwitchInlineQueryCurrentChat(Text.show_traders)},
-                    new[] {InlineKeyboardButton.WithCallbackData(Text.back, $"{Command.back}={Command.clear_chat}")},
-                }),
-                UserState.CollectionMenu => new InlineKeyboardMarkup(new[] {
-                    new[] {InlineKeyboardButton.WithSwitchInlineQuery(Text.send_sticker, stickerInfo.Title)},
-                    new[] {InlineKeyboardButton.WithCallbackData($"{Text.sell_on_auction} ({stickerInfo.Count})", Command.confirm_selling)},
-                    new[]
-                    {
-                        InlineKeyboardButton.WithCallbackData(Text.minus, $"{Command.count}-"),
-                        InlineKeyboardButton.WithCallbackData(Text.plus, $"{Command.count}+"),
-                    },
-                    new[] {InlineKeyboardButton.WithCallbackData(Text.combine, Command.combine)},
-                    new[] {InlineKeyboardButton.WithCallbackData(Text.back, $"{Command.back}={Command.clear_chat}")},
-                }),
-                _ => new InlineKeyboardMarkup(new[] {
-                    new[] {InlineKeyboardButton.WithSwitchInlineQuery(Text.send_sticker, stickerInfo.Title)},
-                    new[] {InlineKeyboardButton.WithCallbackData(Text.back, Command.clear_chat)},
-                }),
+                UserState.AuctionMenu when session.SelectedSticker.TraderInfo is not null => GetAuctionProductKeyboard(session.SelectedSticker),
+                UserState.AuctionMenu => GetAuctionStickerKeyboard(),
+                UserState.ShopMenu => GetShopStickerKeyboard(session.SelectedSticker),
+                UserState.CollectionMenu => GetCollectionStickerKeyboard(session.SelectedSticker),
+                _ => GetStickerKeyboard(session.SelectedSticker)
             };
         }
         

+ 27 - 0
CardCollector/Resources/Messages.Designer.cs

@@ -69,6 +69,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Вы уверены?.
+        /// </summary>
+        internal static string are_you_sure {
+            get {
+                return ResourceManager.GetString("are_you_sure", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Автор:.
         /// </summary>
@@ -141,6 +150,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Подтверидте покупку.
+        /// </summary>
+        internal static string confirm_buying {
+            get {
+                return ResourceManager.GetString("confirm_buying", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Текущие примененные фильтры:.
         /// </summary>
@@ -357,6 +375,15 @@ namespace CardCollector.Resources {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Вы продали.
+        /// </summary>
+        internal static string you_sold {
+            get {
+                return ResourceManager.GetString("you_sold", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Ваш баланс.
         /// </summary>

+ 9 - 0
CardCollector/Resources/Messages.resx

@@ -120,4 +120,13 @@
     <data name="not_enougth_gems" xml:space="preserve">
         <value>Недостаточно алмазов!</value>
     </data>
+    <data name="confirm_buying" xml:space="preserve">
+        <value>Подтверидте покупку</value>
+    </data>
+    <data name="are_you_sure" xml:space="preserve">
+        <value>Вы уверены?</value>
+    </data>
+    <data name="you_sold" xml:space="preserve">
+        <value>Вы продали</value>
+    </data>
 </root>

+ 9 - 0
CardCollector/Resources/Text.Designer.cs

@@ -437,5 +437,14 @@ namespace CardCollector.Resources {
                 return ResourceManager.GetString("to", resourceCulture);
             }
         }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Да.
+        /// </summary>
+        internal static string yes {
+            get {
+                return ResourceManager.GetString("yes", resourceCulture);
+            }
+        }
     }
 }

+ 3 - 0
CardCollector/Resources/Text.resx

@@ -144,4 +144,7 @@
     <data name="per" xml:space="preserve">
         <value>за</value>
     </data>
+    <data name="yes" xml:space="preserve">
+        <value>Да</value>
+    </data>
 </root>