From f576c6fc85c2e096b1bee092f87d394acc07a570 Mon Sep 17 00:00:00 2001 From: Carlos Nihelton Date: Wed, 11 May 2022 16:12:37 -0300 Subject: [PATCH] Won't store validation results in the controller. Instead the form itself keeps track of the active async task. The validation state is returned from the task object itself. --- subiquity/client/controllers/identity.py | 8 ++------ subiquity/ui/views/identity.py | 23 +++++++++++++++++++++-- subiquity/ui/views/tests/test_identity.py | 13 ++++++++----- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/subiquity/client/controllers/identity.py b/subiquity/client/controllers/identity.py index f6bb493b..c32d21d9 100644 --- a/subiquity/client/controllers/identity.py +++ b/subiquity/client/controllers/identity.py @@ -50,9 +50,5 @@ class IdentityController(SubiquityTuiController): identity_data) self.app.next_screen(self.endpoint.POST(identity_data)) - async def _validate_username(self, username): - self.username_validation = \ - await self.endpoint.validate_username.GET(username) - - def validate_username(self, _, value): - self.app.aio_loop.create_task(self._validate_username(value)) + async def validate_username(self, username): + return await self.endpoint.validate_username.GET(username) diff --git a/subiquity/ui/views/identity.py b/subiquity/ui/views/identity.py index f6c62c6a..2b3895ea 100644 --- a/subiquity/ui/views/identity.py +++ b/subiquity/ui/views/identity.py @@ -20,6 +20,7 @@ import re from urwid import ( connect_signal, ) +from subiquitycore.async_helpers import schedule_task from subiquitycore.ui.interactive import ( PasswordEditor, @@ -85,9 +86,10 @@ class IdentityForm(Form): def __init__(self, controller, initial): self.controller = controller + self.validation_task = None super().__init__(initial=initial) connect_signal(self.username.widget, 'change', - controller.validate_username) + self.on_username_change) realname = RealnameField(_("Your name:")) hostname = UsernameField( @@ -97,6 +99,23 @@ class IdentityForm(Form): password = PasswordField(_("Choose a password:")) confirm_password = PasswordField(_("Confirm your password:")) + def on_username_change(self, _, value): + if len(value) < 2: + return + + if self.validation_task is not None: + self.validation_task.cancel() + + self.validation_task = \ + schedule_task(self.controller.validate_username(value)) + + def username_validation_state(self): + task = self.validation_task + if task is None or not task.done(): + return UsernameValidation.OK + + return task.result() + def validate_realname(self): if len(self.realname.value) > REALNAME_MAXLEN: return _( @@ -118,7 +137,6 @@ class IdentityForm(Form): def validate_username(self): username = self.username.value - state = self.controller.username_validation if len(username) < 1: return _("Username missing") @@ -131,6 +149,7 @@ class IdentityForm(Form): return _( "Username must match USERNAME_REGEX: " + USERNAME_REGEX) + state = self.username_validation_state() if state == UsernameValidation.SYSTEM_RESERVED: return _( 'The username "{username}" is reserved for use by the system.' diff --git a/subiquity/ui/views/tests/test_identity.py b/subiquity/ui/views/tests/test_identity.py index 94f0d9ee..ffd594a2 100644 --- a/subiquity/ui/views/tests/test_identity.py +++ b/subiquity/ui/views/tests/test_identity.py @@ -1,3 +1,4 @@ +import asyncio import unittest from unittest import mock @@ -65,22 +66,24 @@ class IdentityViewTests(unittest.TestCase): view_helpers.enter_data(view.form, valid_data) self.assertTrue(view.form.done_btn.enabled) - def test_username_validation_system_reserved(self): + async def test_username_validation_system_reserved(self): view = self.make_view() - view.controller.username_validation = \ + view.controller.validate_username.return_value = \ UsernameValidation.SYSTEM_RESERVED view_helpers.enter_data(view.form, system_reserved) + await asyncio.wait(view.form.validation_task) self.assertFalse(view.form.done_btn.enabled) - def test_username_validation_in_use(self): + async def test_username_validation_in_use(self): view = self.make_view() - view.controller.username_validation = UsernameValidation.ALREADY_IN_USE + view.controller.validate_username.return_value = \ + UsernameValidation.ALREADY_IN_USE view_helpers.enter_data(view.form, already_taken) + await asyncio.wait(view.form.validation_task) self.assertFalse(view.form.done_btn.enabled) def test_username_validation_too_long(self): view = self.make_view() - view.controller.username_validation = UsernameValidation.TOO_LONG view_helpers.enter_data(view.form, too_long) self.assertFalse(view.form.done_btn.enabled)