From 435d01ef903a4006c549708acd0eb64e84ee573a Mon Sep 17 00:00:00 2001 From: BobdaFett Date: Sat, 25 Nov 2023 02:16:53 -0500 Subject: [PATCH] Started framework of API key storage. --- PcgsInvUi/App.axaml.cs | 13 ++--- PcgsInvUi/Services/CoinDatabase.cs | 59 ++++++++++++++++++--- PcgsInvUi/Services/PcgsClient.cs | 9 ++-- PcgsInvUi/ViewModels/MainWindowViewModel.cs | 21 +++----- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/PcgsInvUi/App.axaml.cs b/PcgsInvUi/App.axaml.cs index e71a99c..a938ffb 100644 --- a/PcgsInvUi/App.axaml.cs +++ b/PcgsInvUi/App.axaml.cs @@ -1,12 +1,9 @@ -using System; -using System.Data.Entity.Migrations.Model; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using PcgsInvUi.Services; using PcgsInvUi.ViewModels; using PcgsInvUi.Views; -using PcgsInvUi.Models; namespace PcgsInvUi; @@ -20,17 +17,15 @@ public partial class App : Application { if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { var coins = new CoinDatabase(); desktop.MainWindow = new MainWindow { - DataContext = new MainWindowViewModel(coins), + DataContext = new MainWindowViewModel(), }; + // Allow the application to save the database when it exits. + // The issue is that this will break if the database is not initialized here. desktop.Exit += (sender, args) => { coins.UpdateCollection("CollectionTable"); }; } base.OnFrameworkInitializationCompleted(); } - - public void OnExit(object sender, ControlledApplicationLifetimeExitEventArgs e) { - // Save the database? - } -} \ No newline at end of file +} diff --git a/PcgsInvUi/Services/CoinDatabase.cs b/PcgsInvUi/Services/CoinDatabase.cs index 221d845..52f2dac 100644 --- a/PcgsInvUi/Services/CoinDatabase.cs +++ b/PcgsInvUi/Services/CoinDatabase.cs @@ -16,15 +16,40 @@ public class CoinDatabase { public CoinDatabase() { // Create a connection to SQLite Connection = CreateConnection(); - // Create a client to access the API. - _pcgsClient = new PcgsClient( - "eAb8gS0I2XAvT_5gJeiGJaglMia1Tk-oB4kJUK6kuafyrny_S61vIJY-Ikl4nCQM67wrdxzUqLVWTV2kBSxD3d5XNBHxHnYBhcSS6dOPug0hZaF3qAv56df3gYSzOGh9Tif5y0eP3Iw0LrqKDr1Hj-dk6SV6GKog2IIqCPQhhHH8FMTWBTYO-_O8cx7qLdM5GM8KlTsic6g3VRUhM8EA_4OO04dCfmNLGhqINRl3jGZ0Q4ziI8fng2bVWsIyteqiPzUn10rIQ3-OPpqVZG_DxeOmOejj4GzbUNyqUOajy-nr5rYY"); // Create a base table. CreateCollection("CollectionTable"); + CreateApiTable(); Console.WriteLine("Connected to database."); Collection = new ObservableCollection(); GetCollection("CollectionTable"); Console.WriteLine("Got collection."); + + // Initialize the PCGS client. Must get the API key from the database. + // Check the database for an API key. + SQLiteCommand cmd = Connection.CreateCommand(); + cmd.CommandText = "SELECT API_KEY FROM ApiTable"; + using (var reader = cmd.ExecuteReader()) { + // If there's no API key, we need to get one from the user. + // Eventually there will be a window that pops up adking for the API key. + var apiKey = ""; + if (reader.Read()) { + // Initialize the client. + apiKey = reader.GetString(0); + } + else { + // Get the API key from the user. + // TODO Create and open a window that asks for the API key. + // Since this needs to build before the main window is created, we can't do that yet. + Console.WriteLine("No API key found. Using default..."); + do { + // Console.Write("Enter a valid API key: "); + // apiKey = Console.ReadLine(); + // Eventually we actually want to throw an error here. + apiKey = "E8xivTVN_k4Q8ubk8Xv_uU11U91WX0wDht4S4m4BAf2HPmKnGrZ0J2f9nccM7Ns1VkGoT1SXYR74I7aNaMKqXlJGEy3oobseKV0nGiqu1IKvFkOTVjhV37SWUVExSDFMC6FLzs7xJQIHwkcxr5JFOQNmc4ZytEh_-hmCN3NL-z0fEk98tzBmPJ_F7bq_xNru86QMD2A9yalu_dWe-lCysfyE2bCA2EDqwvWenRYf-0XnNtp6qlxxCMlCd-TDqqRKLC3qefCwpXSemwBiNSP5gbC9pwcKrZugkruuJ0nyxxThZymm"; + } while (apiKey == "" || apiKey == null); + } + _pcgsClient = new PcgsClient(apiKey); + } } ~CoinDatabase() { @@ -38,9 +63,9 @@ public class CoinDatabase { private SQLiteConnection CreateConnection() { // Check if database exists. if (!System.IO.File.Exists("coin_collection")) { - // Create the database. + // If not, create the database. Console.Write("Creating database... "); - SQLiteConnection.CreateFile("coin_collection"); + SQLiteConnection.CreateFile("coin_collection.sqlite"); Console.WriteLine("Done."); } @@ -60,6 +85,27 @@ public class CoinDatabase { return connection; } + public void CreateApiTable() { + // Create a table to store the API key and the number of requests remaining. + if (!IsConnected) { + // TODO Create a NotConnectedToDatabaseException + Console.WriteLine("Not connected to database."); + return; + } + + // Create a SQL command. + SQLiteCommand cmd = Connection.CreateCommand(); + cmd.CommandText = + "CREATE TABLE IF NOT EXISTS ApiTable (" + + "API_KEY TEXT, " + + "REQUESTS_REMAINING INTEGER, " + + "PRIMARY KEY(API_KEY))"; + + // Execute the command + cmd.ExecuteNonQuery(); + Console.WriteLine("API table initialized."); + } + public void CreateCollection(string collectionName) { // Create a table to store the collection. if (!IsConnected) { @@ -93,6 +139,7 @@ public class CoinDatabase { // Execute the command. cmd.ExecuteNonQuery(); + Console.WriteLine("Collection table initialized."); } public void InsertCoin(Coin coin) { @@ -297,4 +344,4 @@ public class CoinDatabase { Console.WriteLine($"Grade is {actualGrade}"); return actualGrade; } -} \ No newline at end of file +} diff --git a/PcgsInvUi/Services/PcgsClient.cs b/PcgsInvUi/Services/PcgsClient.cs index e4329d2..2cfbf91 100644 --- a/PcgsInvUi/Services/PcgsClient.cs +++ b/PcgsInvUi/Services/PcgsClient.cs @@ -1,11 +1,9 @@ using System; -using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using System.Threading.Tasks; using PcgsInvUi.Models; using System.Text.Json; -using DynamicData.Kernel; using ReactiveUI; namespace PcgsInvUi.Services; @@ -28,9 +26,8 @@ public class PcgsClient : ReactiveObject { private int _numApiRequests; public PcgsClient(string apiKey) { - // _apiKey = apiKey; - _apiKey = - "E8xivTVN_k4Q8ubk8Xv_uU11U91WX0wDht4S4m4BAf2HPmKnGrZ0J2f9nccM7Ns1VkGoT1SXYR74I7aNaMKqXlJGEy3oobseKV0nGiqu1IKvFkOTVjhV37SWUVExSDFMC6FLzs7xJQIHwkcxr5JFOQNmc4ZytEh_-hmCN3NL-z0fEk98tzBmPJ_F7bq_xNru86QMD2A9yalu_dWe-lCysfyE2bCA2EDqwvWenRYf-0XnNtp6qlxxCMlCd-TDqqRKLC3qefCwpXSemwBiNSP5gbC9pwcKrZugkruuJ0nyxxThZymm"; + _apiKey = apiKey; + // "E8xivTVN_k4Q8ubk8Xv_uU11U91WX0wDht4S4m4BAf2HPmKnGrZ0J2f9nccM7Ns1VkGoT1SXYR74I7aNaMKqXlJGEy3oobseKV0nGiqu1IKvFkOTVjhV37SWUVExSDFMC6FLzs7xJQIHwkcxr5JFOQNmc4ZytEh_-hmCN3NL-z0fEk98tzBmPJ_F7bq_xNru86QMD2A9yalu_dWe-lCysfyE2bCA2EDqwvWenRYf-0XnNtp6qlxxCMlCd-TDqqRKLC3qefCwpXSemwBiNSP5gbC9pwcKrZugkruuJ0nyxxThZymm"; } public async Task<(ErrorType, Coin?)> GetCoinFactsByGrade(int pcgsNumber, string grade, bool plusGrade = false) { @@ -86,4 +83,4 @@ class CoinNotFoundException : Exception { public CoinNotFoundException() { } public CoinNotFoundException(string message) : base(message) { } public CoinNotFoundException(string message, Exception inner) : base(message, inner) { } -} \ No newline at end of file +} diff --git a/PcgsInvUi/ViewModels/MainWindowViewModel.cs b/PcgsInvUi/ViewModels/MainWindowViewModel.cs index af680ba..916e1f0 100644 --- a/PcgsInvUi/ViewModels/MainWindowViewModel.cs +++ b/PcgsInvUi/ViewModels/MainWindowViewModel.cs @@ -10,18 +10,6 @@ using ReactiveUI; namespace PcgsInvUi.ViewModels; -// TODO Create proper sums for total value. -// TODO Error handling for API calls. -// TODO Manual handling of API key. -// TODO Use CoinFacts link. -// TODO Splash screen during startup. -// TODO Take giant sheet of coins to integrate into the application. -// TODO Update all coins. Choose those that are older first. -// TODO API request tracker (1000 per day) -// TODO Ok button greys out while request is happening. -// TODO Track when coins were last updated. -// TODO Image for coin in notes view. - public class MainWindowViewModel : ViewModelBase { public ViewModelBase SidebarContent { get => _sideContent; @@ -48,7 +36,7 @@ public class MainWindowViewModel : ViewModelBase { private Coin? _selectedCoin; private double _totalValue; - public MainWindowViewModel(CoinDatabase coins) { + public MainWindowViewModel(CoinDatabase coins, bool askForApiKey) { ConnectedCoinDatabase = coins; var newViewModel = new NewViewModel(); _sideContent = newViewModel; @@ -126,4 +114,11 @@ public class MainWindowViewModel : ViewModelBase { TotalValue = ConnectedCoinDatabase.Collection.Sum(x => x.TotalPrice); }; } + + // Create destructor to save the database when the application exits. + // This is necessary because the database is initialized in this class. + ~MainWindowViewModel() { + Console.WriteLine("Running MainWindowViewModel destructor."); + ConnectedCoinDatabase.UpdateCollection("CollectionTable"); + } }