diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 3c99290080..cf2aae753e 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -5,7 +5,9 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Net; +using System.Net.Http; using System.Threading; +using Newtonsoft.Json.Linq; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Logging; @@ -189,13 +191,37 @@ namespace osu.Game.Online.API this.password = password; } - public void CreateAccount(string email, string username, string password) + public RegistrationRequest.RegistrationRequestErrors CreateAccount(string email, string username, string password) { Debug.Assert(State == APIState.Offline); - var req = new RegistrationRequest(); + var req = new RegistrationRequest + { + Url = $@"{Endpoint}/users", + Method = HttpMethod.Post, + Username = username, + Email = email, + Password = password + }; - req.Perform(); + try + { + req.Perform(); + } + catch (Exception e) + { + try + { + return JObject.Parse(req.ResponseString).SelectToken("form_error", true).ToObject(); + } + catch + { + // if we couldn't deserialize the error message let's throw the original exception outwards. + throw e; + } + } + + return null; } /// diff --git a/osu.Game/Online/API/RegsitrationRequest.cs b/osu.Game/Online/API/RegsitrationRequest.cs index 134bf45263..f703927101 100644 --- a/osu.Game/Online/API/RegsitrationRequest.cs +++ b/osu.Game/Online/API/RegsitrationRequest.cs @@ -1,11 +1,12 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using Newtonsoft.Json; using osu.Framework.IO.Network; namespace osu.Game.Online.API { - internal class RegsitrationRequest : JsonWebRequest + public class RegistrationRequest : WebRequest { internal string Username; internal string Email; @@ -13,11 +14,28 @@ namespace osu.Game.Online.API protected override void PrePerform() { - AddParameter("user", Username); - AddParameter("user_email", Email); - AddParameter("password", Password); + AddParameter("user[username]", Username); + AddParameter("user[user_email]", Email); + AddParameter("user[password]", Password); base.PrePerform(); } + + public class RegistrationRequestErrors + { + public UserErrors User; + + public class UserErrors + { + [JsonProperty("username")] + public string[] Username; + + [JsonProperty("user_email")] + public string[] Email; + + [JsonProperty("password")] + public string[] Password; + } + } } } diff --git a/osu.Game/Overlays/AccountCreation/ErrorTextFlowContainer.cs b/osu.Game/Overlays/AccountCreation/ErrorTextFlowContainer.cs new file mode 100644 index 0000000000..9ff6a5a7ef --- /dev/null +++ b/osu.Game/Overlays/AccountCreation/ErrorTextFlowContainer.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Graphics.Containers; +using osuTK.Graphics; + +namespace osu.Game.Overlays.AccountCreation +{ + public class ErrorTextFlowContainer : OsuTextFlowContainer + { + private readonly List errorDrawables = new List(); + + public ErrorTextFlowContainer() + : base(cp => { cp.TextSize = 12; }) + { + } + + public void ClearErrors() + { + errorDrawables.ForEach(d => d.Expire()); + } + + public void AddErrors(string[] errors) + { + ClearErrors(); + + if (errors == null) return; + + foreach (var error in errors) + errorDrawables.AddRange(AddParagraph(error, cp => cp.Colour = Color4.Red)); + } + } +} diff --git a/osu.Game/Overlays/AccountCreationOverlay.cs b/osu.Game/Overlays/AccountCreationOverlay.cs index b8d428a839..6be7ad031c 100644 --- a/osu.Game/Overlays/AccountCreationOverlay.cs +++ b/osu.Game/Overlays/AccountCreationOverlay.cs @@ -1,7 +1,9 @@ // Copyright (c) 2007-2018 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using System.Collections.Generic; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.IEnumerableExtensions; @@ -24,9 +26,9 @@ namespace osu.Game.Overlays { public class AccountCreationOverlay : OsuFocusedOverlayContainer, IOnlineComponent { - private OsuTextFlowContainer usernameDescription; - private OsuTextFlowContainer emailAddressDescription; - private OsuTextFlowContainer passwordDescription; + private ErrorTextFlowContainer usernameDescription; + private ErrorTextFlowContainer emailAddressDescription; + private ErrorTextFlowContainer passwordDescription; private OsuTextBox usernameTextBox; private OsuTextBox emailTextBox; @@ -43,8 +45,6 @@ namespace osu.Game.Overlays Size = new Vector2(620, 450); Anchor = Anchor.Centre; Origin = Anchor.Centre; - - State = Visibility.Visible; } [BackgroundDependencyLoader] @@ -114,9 +114,10 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, TabbableContentContainer = this }, - usernameDescription = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + usernameDescription = new ErrorTextFlowContainer { - RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y }, emailTextBox = new OsuTextBox { @@ -125,9 +126,10 @@ namespace osu.Game.Overlays Text = api.ProvidedUsername ?? string.Empty, TabbableContentContainer = this }, - emailAddressDescription = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + emailAddressDescription = new ErrorTextFlowContainer { - RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y }, passwordTextBox = new OsuPasswordTextBox { @@ -135,9 +137,10 @@ namespace osu.Game.Overlays RelativeSizeAxes = Axes.X, TabbableContentContainer = this, }, - passwordDescription = new OsuTextFlowContainer(cp => { cp.TextSize = 12; }) + passwordDescription = new ErrorTextFlowContainer { - RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y }, new Container { @@ -175,9 +178,7 @@ namespace osu.Game.Overlays characterCheckText = passwordDescription.AddText("8 characters long"); passwordDescription.AddText(". Choose something long but also something you will remember, like a line from your favourite song."); - passwordTextBox.Current.ValueChanged += text => { - characterCheckText.ForEach(s => s.Colour = text.Length == 0 ? Color4.White : Interpolation.ValueAt(text.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); - }; + passwordTextBox.Current.ValueChanged += text => { characterCheckText.ForEach(s => s.Colour = text.Length == 0 ? Color4.White : Interpolation.ValueAt(text.Length, Color4.OrangeRed, Color4.YellowGreen, 0, 8, Easing.In)); }; } private void performRegistration() @@ -191,7 +192,47 @@ namespace osu.Game.Overlays return; } - api.CreateAccount(emailTextBox.Text, usernameTextBox.Text, passwordTextBox.Text); + usernameDescription.ClearErrors(); + emailAddressDescription.ClearErrors(); + passwordDescription.ClearErrors(); + + Task.Run(() => + { + bool success; + RegistrationRequest.RegistrationRequestErrors errors = null; + + try + { + errors = api.CreateAccount(emailTextBox.Text, usernameTextBox.Text, passwordTextBox.Text); + success = errors == null; + } + catch (Exception) + { + success = false; + } + + Schedule(() => + { + if (!success) + { + if (errors != null) + { + usernameDescription.AddErrors(errors.User.Username); + emailAddressDescription.AddErrors(errors.User.Email); + passwordDescription.AddErrors(errors.User.Password); + } + else + { + passwordDescription.AddErrors(new[] { "Something happened... but we're not sure what." }); + } + + registerShake.Shake(); + return; + } + + api.Login(emailTextBox.Text, passwordTextBox.Text); + }); + }); } private OsuTextBox nextUnfilledTextbox()