Browse Source

Resending wip

Krzysztof Krysiński 4 months ago
parent
commit
c5d10ae625

+ 11 - 0
src/PixiEditor.PixiAuth/Exceptions/TooManyRequestsException.cs

@@ -0,0 +1,11 @@
+namespace PixiEditor.PixiAuth.Exceptions;
+
+public class TooManyRequestsException : Exception
+{
+    public double TimeLeft { get; }
+
+    public TooManyRequestsException(string message, double timeLeft) : base(message)
+    {
+        TimeLeft = timeLeft;
+    }
+}

+ 37 - 0
src/PixiEditor.PixiAuth/PixiAuthClient.cs

@@ -149,4 +149,41 @@ public class PixiAuthClient
 
         await httpClient.SendAsync(request);
     }
+
+    public async Task ResendActivation(string userEmail, Guid userSessionId)
+    {
+        if (string.IsNullOrEmpty(userEmail))
+        {
+            return;
+        }
+
+        var response = await httpClient.PostAsJsonAsync("/session/resendActivation",
+            new ResendActivationModel(userEmail, userSessionId));
+
+        if (!response.IsSuccessStatusCode)
+        {
+            Dictionary<string, object> responseData =
+                System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(
+                    await response.Content.ReadAsStringAsync());
+            if (responseData != null && responseData.TryGetValue("error", out object? error))
+            {
+                if (error is string errorString and "TOO_MANY_REQUESTS")
+                {
+                    if (responseData.TryGetValue("timeLeft", out object? timeLeft))
+                    {
+                        if (timeLeft is double timeLeftDouble)
+                        {
+                            throw new TooManyRequestsException(errorString, timeLeftDouble);
+                        }
+                    }
+
+                    throw new BadRequestException(errorString);
+                }
+            }
+            else if (response.StatusCode == HttpStatusCode.InternalServerError)
+            {
+                throw new InternalServerErrorException("INTERNAL_SERVER_ERROR");
+            }
+        }
+    }
 }

+ 14 - 0
src/PixiEditor.PixiAuth/ResendActivationModel.cs

@@ -0,0 +1,14 @@
+namespace PixiEditor.PixiAuth;
+
+public class ResendActivationModel
+{
+    public string Email { get; set; }
+
+    public Guid SessionId { get; set; }
+
+    public ResendActivationModel(string email, Guid sessionId)
+    {
+        Email = email;
+        SessionId = sessionId;
+    }
+}

+ 3 - 1
src/PixiEditor/Data/Localization/Languages/en.json

@@ -1028,5 +1028,7 @@
   "OPEN_ONBOARDING_WINDOW": "Open onboarding window",
   "USER_NOT_FOUND": "User not found",
   "SESSION_NOT_VALID": "Session is not valid, please log in again",
-  "INTERNAL_SERVER_ERROR": "There was an internal server error. Please try again later."
+  "SESSION_NOT_FOUND": "Session not found, try logging in again",
+  "INTERNAL_SERVER_ERROR": "There was an internal server error. Please try again later.",
+  "TOO_MANY_REQUESTS": "Too many requests. Try again in {0}"
 }

+ 31 - 0
src/PixiEditor/ViewModels/SubViewModels/UserViewModel.cs

@@ -19,6 +19,7 @@ internal class UserViewModel : SubViewModel<ViewModelMain>
 
     public AsyncRelayCommand<string> RequestLoginCommand { get; }
     public AsyncRelayCommand TryValidateSessionCommand { get; }
+    public AsyncRelayCommand ResendActivationCommand { get; }
     public AsyncRelayCommand LogoutCommand { get; }
 
     public LocalizedString? LastError
@@ -33,6 +34,7 @@ internal class UserViewModel : SubViewModel<ViewModelMain>
     {
         RequestLoginCommand = new AsyncRelayCommand<string>(RequestLogin);
         TryValidateSessionCommand = new AsyncRelayCommand(TryValidateSession);
+        ResendActivationCommand = new AsyncRelayCommand(ResendActivation, CanResendActivation);
         LogoutCommand = new AsyncRelayCommand(Logout);
 
         string baseUrl = BuildConstants.PixiEditorApiUrl;
@@ -85,6 +87,35 @@ internal class UserViewModel : SubViewModel<ViewModelMain>
         }
     }
 
+    public async Task ResendActivation()
+    {
+        if (!apiValid) return;
+
+        if (User?.SessionId == null)
+        {
+            return;
+        }
+
+        try
+        {
+            await PixiAuthClient.ResendActivation(User.Email, User.SessionId.Value);
+            LastError = null;
+        }
+        catch (TooManyRequestsException e)
+        {
+            LastError = new LocalizedString(e.Message, e.TimeLeft);
+        }
+        catch (PixiAuthException authException)
+        {
+            LastError = new LocalizedString(authException.Message);
+        }
+    }
+
+    public bool CanResendActivation()
+    {
+        return WaitingForActivation;
+    }
+
     public async Task<bool> TryRefreshToken()
     {
         if (!apiValid) return false;

+ 7 - 4
src/PixiEditor/Views/Auth/LoginPopup.axaml

@@ -16,13 +16,16 @@
     </Design.DataContext>
     <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="5" Margin="10" MinWidth="300">
         <auth:LoginForm IsVisible="{Binding NotLoggedIn}" RequestLoginCommand="{Binding Path=RequestLoginCommand}" />
-        <TextBlock Text="Email sent! Check your inbox." IsVisible="{Binding WaitingForActivation}"/>
+        <TextBlock Text="Email sent! Check your inbox." IsVisible="{Binding WaitingForActivation}" />
         <TextBlock Text="Logged in as " IsVisible="{Binding IsLoggedIn}">
-            <Run Text="{Binding User.Email}"/>
+            <Run Text="{Binding User.Email}" />
         </TextBlock>
+        <Button IsVisible="{Binding WaitingForActivation}"
+                Command="{Binding Path=ResendActivationCommand}" Content="Resend" HorizontalAlignment="Right">
+        </Button>
         <Button IsVisible="{Binding IsLoggedIn}"
-                Command="{Binding Path=LogoutCommand}" Content="Logout" HorizontalAlignment="Right"/>
+                Command="{Binding Path=LogoutCommand}" Content="Logout" HorizontalAlignment="Right" />
         <TextBlock ui:Translator.LocalizedString="{Binding LastError}" IsVisible="{Binding !!LastError}"
-                   Foreground="{DynamicResource ErrorBrush}"/>
+                   Foreground="{DynamicResource ErrorBrush}" />
     </StackPanel>
 </dialogs:PixiEditorPopup>