diff --git a/BodyshopUploader/App.config b/BodyshopUploader/App.config
index 290b8b4..5434933 100644
--- a/BodyshopUploader/App.config
+++ b/BodyshopUploader/App.config
@@ -57,6 +57,12 @@
+
+
+
+
+
+
diff --git a/BodyshopUploader/Properties/Settings.Designer.cs b/BodyshopUploader/Properties/Settings.Designer.cs
index ec865ae..33d57f1 100644
--- a/BodyshopUploader/Properties/Settings.Designer.cs
+++ b/BodyshopUploader/Properties/Settings.Designer.cs
@@ -12,7 +12,7 @@ namespace BodyshopPartner.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.7.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -104,5 +104,29 @@ namespace BodyshopPartner.Properties {
this["QuickBooksFilePath"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("")]
+ public string AuthToken {
+ get {
+ return ((string)(this["AuthToken"]));
+ }
+ set {
+ this["AuthToken"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("")]
+ public string RefreshToken {
+ get {
+ return ((string)(this["RefreshToken"]));
+ }
+ set {
+ this["RefreshToken"] = value;
+ }
+ }
}
}
diff --git a/BodyshopUploader/Properties/Settings.settings b/BodyshopUploader/Properties/Settings.settings
index 4bc4dda..5913e1a 100644
--- a/BodyshopUploader/Properties/Settings.settings
+++ b/BodyshopUploader/Properties/Settings.settings
@@ -23,5 +23,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/BodyshopUploader/Utils/Auth.cs b/BodyshopUploader/Utils/Auth.cs
index b75f9ca..8d3d684 100644
--- a/BodyshopUploader/Utils/Auth.cs
+++ b/BodyshopUploader/Utils/Auth.cs
@@ -12,15 +12,57 @@ namespace BodyshopPartner.Utils
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public static FirebaseAuthLink authlink;
- static FirebaseAuthProvider ap = new FirebaseAuthProvider(new FirebaseConfig(Utils.AppMetaData.FirebaseAPIKey));
+ static FirebaseAuthProvider ap = new FirebaseAuthProvider(new FirebaseConfig(Utils.AppMetaData.FirebaseAPIKey));
private static Timer tokenTimer = new Timer();
private static string U;
private static string P;
-
+
public async static Task AuthTest()
{
- await ap.RefreshAuthAsync( new FirebaseAuth() { });
+ await ap.RefreshAuthAsync(new FirebaseAuth() { });
+ }
+
+ public async static Task<(bool, string)> AutoLogin(string AuthToken, string RefreshToken)
+ {
+ try
+ {
+ authlink = await new FirebaseAuthLink(ap, new FirebaseAuth() { FirebaseToken = AuthToken, RefreshToken = RefreshToken, }).GetFreshAuthAsync();
+ await authlink.RefreshUserDetails();
+ authlink.FirebaseAuthRefreshed += Authlink_FirebaseAuthRefreshed;
+
+ logger.Trace("Firebase Auth Token {0}.", authlink.FirebaseToken);
+ logger.Trace("Firebase Auth Token expires in {0} seconds.", authlink.ExpiresIn);
+ tokenTimer.Interval = (authlink.ExpiresIn - 600) * 1000; //Set the token to refresh 10 minutes before it has to.
+ logger.Trace("Refresh timer interval set to {0}ms", (authlink.ExpiresIn - 600) * 1000);
+ tokenTimer.Elapsed += TokenTimer_Tick;
+ tokenTimer.Start();
+ return (true, null);
+ }
+ catch (FirebaseAuthException Ex)
+ {
+ switch (Ex.Reason)
+ {
+ case AuthErrorReason.WrongPassword:
+ logger.Error("Incorrect password provided for user.");
+ return (false, Properties.Resources.Error_Login);
+
+ case AuthErrorReason.UnknownEmailAddress:
+ logger.Error("User does not exist.");
+ return (false, Properties.Resources.Error_Login);
+ case AuthErrorReason.TooManyAttemptsTryLater:
+ logger.Error("Too many attempts logging in.");
+ return (false, Properties.Resources.Error_Login_Attempts);
+ default:
+ logger.Error(Ex, "Unknown error occured while logging in. {0}", Ex.Reason);
+ return (false, Properties.Resources.Error_Login_Unknown);
+ }
+ }
+ catch (Exception Ex)
+ {
+ logger.Error(Ex, "Unknown error encountered while obtaining auth token.");
+ return (false, Properties.Resources.Error_Generic);
+ }
}
public async static Task<(bool, string)> LoginAsync(string Username, string Password)
@@ -31,8 +73,12 @@ namespace BodyshopPartner.Utils
{
authlink = await ap.SignInWithEmailAndPasswordAsync(Username, Password);
authlink.FirebaseAuthRefreshed += Authlink_FirebaseAuthRefreshed;
-
-
+
+ Properties.Settings.Default.AuthToken = authlink.FirebaseToken;
+ Properties.Settings.Default.RefreshToken = authlink.RefreshToken;
+ Properties.Settings.Default.Save();
+
+
logger.Trace("Firebase Auth Token {0}.", authlink.FirebaseToken);
logger.Trace("Firebase Auth Token expires in {0} seconds.", authlink.ExpiresIn);
@@ -73,7 +119,7 @@ namespace BodyshopPartner.Utils
{
logger.Trace("Old Token {0}", authlink.RefreshToken);
await authlink.GetFreshAuthAsync();
-
+
authlink = await ap.RefreshAuthAsync(authlink);
logger.Trace("new Token {0}", authlink.FirebaseToken);
}
diff --git a/BodyshopUploader/Utils/GraphQL.cs b/BodyshopUploader/Utils/GraphQL.cs
index 29a6e77..674ccbe 100644
--- a/BodyshopUploader/Utils/GraphQL.cs
+++ b/BodyshopUploader/Utils/GraphQL.cs
@@ -13,7 +13,7 @@ namespace BodyshopPartner.Utils
public static class GraphQL
{
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
-
+
public static GraphQLHttpClient CreateGQLClient()
{
var graphQLClient = new GraphQLHttpClient(AppMetaData.graphQlEndpoint, new NewtonsoftJsonSerializer());
@@ -31,7 +31,7 @@ namespace BodyshopPartner.Utils
var graphQLResponse = await g.SendQueryAsync(r);
if (graphQLResponse.Errors == null)
{
-
+
//logger.Trace("GQL Response: {0}", graphQLResponse.Data);
return graphQLResponse.Data;
}
@@ -42,7 +42,7 @@ namespace BodyshopPartner.Utils
logger.Error("Error executing query.");
Array.ForEach(graphQLResponse.Errors, x =>
{
- logger.Error(x.Message);
+ logger.Error("Graphql Error: " + x.Message);
if (x.Message.Contains("JWTExpired"))
{
jwtExpired = true;
diff --git a/BodyshopUploader/Utils/JobProcessingQueue.cs b/BodyshopUploader/Utils/JobProcessingQueue.cs
index a5ecb79..0848fbe 100644
--- a/BodyshopUploader/Utils/JobProcessingQueue.cs
+++ b/BodyshopUploader/Utils/JobProcessingQueue.cs
@@ -184,7 +184,7 @@ namespace BodyshopPartner.Utils
catch (Exception Ex)
{
- logger.Error("Job insert failed. Show notification");
+ logger.Error("Job insert failed. Show notification " + Ex.ToString());
//Succesful upsert
App.Current.Dispatcher.Invoke(() =>
{
diff --git a/BodyshopUploader/Utils/UiConverters.cs b/BodyshopUploader/Utils/UiConverters.cs
index e390171..7e74dda 100644
--- a/BodyshopUploader/Utils/UiConverters.cs
+++ b/BodyshopUploader/Utils/UiConverters.cs
@@ -25,6 +25,20 @@ namespace BodyshopPartner.Utils
}
}
+ public class InvertBoolConverter : IValueConverter
+ {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return !((bool)value);
+
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return ((bool)value);
+ }
+ }
+
public class NullVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
diff --git a/BodyshopUploader/ViewModels/LoginViewModel.cs b/BodyshopUploader/ViewModels/LoginViewModel.cs
index e16bd11..a56df03 100644
--- a/BodyshopUploader/ViewModels/LoginViewModel.cs
+++ b/BodyshopUploader/ViewModels/LoginViewModel.cs
@@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks;
using System.Windows;
+
namespace BodyshopPartner.ViewModels
{
public partial class LoginViewModel : BaseViewModel
@@ -15,6 +16,34 @@ namespace BodyshopPartner.ViewModels
public LoginViewModel()
{
logger.Trace("Login VM Created.");
+
+ AutoLogin();
+
+
+ }
+
+ private async Task AutoLogin()
+ {
+ Loading = true;
+ string AuthToken = Properties.Settings.Default.AuthToken;
+ string RefreshToken = Properties.Settings.Default.RefreshToken;
+
+
+ if (!String.IsNullOrEmpty(AuthToken) && !String.IsNullOrEmpty(RefreshToken))
+ {
+ //Attempt auto login.
+ logger.Debug("Good to attempt auto login.");
+ (Error, ErrorMsg) = await Utils.Auth.AutoLogin(AuthToken, RefreshToken);
+ if (ErrorMsg == null)
+ {
+ App.Current.MainWindow.Hide();
+ Views.Main m = new Views.Main();
+ m.Show();
+
+ }
+
+ }
+ Loading = false;
}
private async Task LoginAsync(Window W)
@@ -25,7 +54,7 @@ namespace BodyshopPartner.ViewModels
logger.Trace("Attempting to login as user: {0}", UserName);
(Error, ErrorMsg) = await Utils.Auth.LoginAsync(UserName, Utils.LoginHelpers.DecodePassword(UserPassword));
- if(ErrorMsg ==null)
+ if (ErrorMsg == null)
{
Views.Main m = new Views.Main();
m.Show();
diff --git a/BodyshopUploader/ViewModels/MainViewModel.commands.cs b/BodyshopUploader/ViewModels/MainViewModel.commands.cs
index 2f3fb3a..3b632c8 100644
--- a/BodyshopUploader/ViewModels/MainViewModel.commands.cs
+++ b/BodyshopUploader/ViewModels/MainViewModel.commands.cs
@@ -148,6 +148,7 @@ namespace BodyshopPartner.ViewModels
async p =>
{
await InstallUpdates();
+ UpdateAvailable = false;
});
}
return _installUpdatesCommand;
diff --git a/BodyshopUploader/Views/Login.xaml b/BodyshopUploader/Views/Login.xaml
index 90dd0c5..3d946ba 100644
--- a/BodyshopUploader/Views/Login.xaml
+++ b/BodyshopUploader/Views/Login.xaml
@@ -27,7 +27,7 @@
-
+