On Fri, 2013-03-08 at 14:57 +0100, Martin Sivak wrote:
This adds three new classes:
EditTUIDialog - spoke/dialog used to read new value of textual
or password data
OneShotEditTUIDialog - the same as above, but closes automatically
after the value is read
EditTUISpoke - spoke with declarative semantics, it contains
a list of titles, attribute names and regexps
that specify the fields of an object the user
is allowed to edit
This patchset also adds the UserSpoke and modifies the Password
spoke to use the implemented helper classes.
---
pyanaconda/ui/tui/__init__.py | 83 ++-----------------
pyanaconda/ui/tui/spokes/__init__.py | 152 +++++++++++++++++++++++++++++++++--
pyanaconda/ui/tui/spokes/password.py | 35 +++-----
pyanaconda/ui/tui/spokes/user.py | 70 ++++++++++++++++
pyanaconda/ui/tui/tuiobject.py | 78 ++++++++++++++++++
5 files changed, 309 insertions(+), 109 deletions(-)
create mode 100644 pyanaconda/ui/tui/spokes/user.py
diff --git a/pyanaconda/ui/tui/__init__.py b/pyanaconda/ui/tui/__init__.py
index d051590..879f28e 100644
--- a/pyanaconda/ui/tui/__init__.py
+++ b/pyanaconda/ui/tui/__init__.py
@@ -21,12 +21,12 @@
from pyanaconda import ui
from pyanaconda.ui import common
-from pyanaconda.ui import communication
from pyanaconda.flags import flags
import simpleline as tui
from hubs.summary import SummaryHub
from hubs.progress import ProgressHub
from spokes import StandaloneSpoke
+from tuiobject import YesNoDialog, ErrorDialog
import os
import site
@@ -35,82 +35,6 @@ import meh.ui.text
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
-class ErrorDialog(tui.UIScreen):
- """Dialog screen for reporting errors to user."""
-
- title = _("Error")
-
- def __init__(self, app, message):
- """
- :param app: the running application reference
- :type app: instance of App class
-
- :param message: the message to show to the user
- :type message: unicode
- """
-
- tui.UIScreen.__init__(self, app)
- self._message = message
-
- def refresh(self, args = None):
- tui.UIScreen.refresh(self, args)
- text = tui.TextWidget(self._message)
- self._window.append(tui.CenterWidget(text))
-
- def prompt(self, args = None):
- return _("Press enter to exit.")
-
- def input(self, args, key):
- """This dialog is closed by any input."""
- self.close()
-
-class YesNoDialog(tui.UIScreen):
- """Dialog screen for Yes - No questions."""
-
- title = _("Question")
-
- def __init__(self, app, message):
- """
- :param app: the running application reference
- :type app: instance of App class
-
- :param message: the message to show to the user
- :type message: unicode
- """
-
- tui.UIScreen.__init__(self, app)
- self._message = message
- self._response = None
-
- def refresh(self, args = None):
- tui.UIScreen.refresh(self, args)
- text = tui.TextWidget(self._message)
- self._window.append(tui.CenterWidget(text))
- self._window.append(u"")
- return True
-
- def prompt(self, args):
- return _("Please respond 'yes' or 'no': ")
-
- def input(self, args, key):
- if key == _("yes"):
- self._response = True
- self.close()
- return None
-
- elif key == _("no"):
- self._response = False
- self.close()
- return None
-
- else:
- return False
-
- @property
- def answer(self):
- """The response can be True (yes), False (no) or None (no
response)."""
- return self._response
-
class TextUserInterface(ui.UserInterface):
"""This is the main class for Text user interface."""
@@ -183,6 +107,11 @@ class TextUserInterface(ui.UserInterface):
"""
self._app = tui.App(self.productTitle, yes_or_no_question = YesNoDialog,
quit_message = self.quitMessage)
+
+ import pdb
+ from pyanaconda.ui.communication import HUB_CODE_EXCEPTION, HUB_CODE_INPUT
+ self._app.register_event_handler(HUB_CODE_EXCEPTION, lambda e,x:
pdb.set_trace(), None)
+
Debugging leftover? Or do you want to put it there and I should remove
it when pushing my patches for processing text mode exceptions in the
main thread?
_hubs = self._list_hubs()
# First, grab a list of all the standalone spokes.
diff --git a/pyanaconda/ui/tui/spokes/__init__.py b/pyanaconda/ui/tui/spokes/__init__.py
index e4d7d33..6bac732 100644
--- a/pyanaconda/ui/tui/spokes/__init__.py
+++ b/pyanaconda/ui/tui/spokes/__init__.py
@@ -18,15 +18,17 @@
#
# Red Hat Author(s): Martin Sivak <msivak(a)redhat.com>
#
-from .. import simpleline as tui
-from pyanaconda.ui.tui.tuiobject import TUIObject
+from pyanaconda.ui.tui import simpleline as tui
+from pyanaconda.ui.tui.tuiobject import TUIObject, YesNoDialog
from pyanaconda.ui.common import Spoke, StandaloneSpoke, NormalSpoke,
PersonalizationSpoke, collect
-import os
+from pyanaconda.users import validatePassword
+from pwquality import PWQError
+import re
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
-__all__ = ["TUISpoke", "StandaloneSpoke", "NormalSpoke",
"PersonalizationSpoke",
+__all__ = ["TUISpoke", "EditTUISpoke", "EditTUIDialog",
"StandaloneSpoke", "NormalSpoke", "PersonalizationSpoke",
"collect_spokes", "collect_categories"]
class TUISpoke(TUIObject, tui.Widget, Spoke):
@@ -72,10 +74,148 @@ class TUISpoke(TUIObject, tui.Widget, Spoke):
c.render(width)
self.draw(c)
-class StandaloneTUISpoke(TUISpoke, StandaloneSpoke):
+class NormalTUISpoke(TUISpoke, NormalSpoke):
pass
-class NormalTUISpoke(TUISpoke, NormalSpoke):
+class EditTUIDialog(NormalTUISpoke):
+ title = _("New value")
+ PASSWORD = re.compile(".*")
+
+ def __init__(self, app, data, storage, payload, instclass):
+ NormalTUISpoke.__init__(self, app, data, storage, payload, instclass)
+ self.value = None
+
+ def refresh(self, args):
+ self._window = []
+ self.value = None
+ return True
+
+ def prompt(self, (title, value, regex)):
+ if regex == self.PASSWORD:
+ pw = self._app.raw_input(_("%s: ") % title, hidden=True)
+ confirm = self._app.raw_input(_("%s (confirm): ") % title,
hidden=True)
+ error = None
+ # just returning an error is either blank or mismatched
+ # passwords. Raising is because of poor quality.
^^^ two spaces
+ try:
+ error = validatePassword(pw, confirm)
+ if error:
+ print(error)
+ return None
+ except PWQError as (e, msg):
+ error = _("You have provided a weak password: %s. " % msg)
+ error += _("\nWould you like to use it anyway?")
+ question_window = YesNoDialog(self._app, error)
+ self._app.switch_screen_modal(question_window)
+ if not question_window.answer:
+ return None
+
+ self.value = pw
+ return None
+ else:
+ return _("Enter new value for '%s' and press enter\n") %
title
I don't follow the logic here. Is the way to switch to password input
passing one particular regexp? Wouldn't additional parameter like
"password=False" better? I know that we control the caller as well, but
it's
quite confusing.
--
Vratislav Podzimek
Anaconda Rider | Red Hat, Inc. | Brno - Czech Republic