|
|
|
|
From 490d7c31855f8b8723bed6c997c310db25242fb8 Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: Dmitry Samoylik <Dmitriy.Samoylik@softline.com>
|
|
|
|
|
Date: Thu, 26 Sep 2024 16:57:48 +0300
|
|
|
|
|
Subject: [PATCH 15/15] Implement show EULA before installation
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
data/anaconda.conf | 4 +-
|
|
|
|
|
po/ru.po | 31 ++++++
|
|
|
|
|
pyanaconda/core/configuration/license.py | 2 -
|
|
|
|
|
pyanaconda/core/eula.py | 23 ++++
|
|
|
|
|
pyanaconda/ui/categories/eula.py | 14 +++
|
|
|
|
|
pyanaconda/ui/gui/spokes/eula.glade | 136 +++++++++++++++++++++++
|
|
|
|
|
pyanaconda/ui/gui/spokes/eula.py | 107 ++++++++++++++++++
|
|
|
|
|
pyanaconda/ui/tui/spokes/eula.py | 128 +++++++++++++++++++++
|
|
|
|
|
8 files changed, 440 insertions(+), 5 deletions(-)
|
|
|
|
|
create mode 100644 pyanaconda/core/eula.py
|
|
|
|
|
create mode 100644 pyanaconda/ui/categories/eula.py
|
|
|
|
|
create mode 100644 pyanaconda/ui/gui/spokes/eula.glade
|
|
|
|
|
create mode 100644 pyanaconda/ui/gui/spokes/eula.py
|
|
|
|
|
create mode 100644 pyanaconda/ui/tui/spokes/eula.py
|
|
|
|
|
|
|
|
|
|
diff --git a/data/anaconda.conf b/data/anaconda.conf
|
|
|
|
|
index b5878e3..c15e99d 100644
|
|
|
|
|
--- a/data/anaconda.conf
|
|
|
|
|
+++ b/data/anaconda.conf
|
|
|
|
|
@@ -308,9 +308,7 @@ password_policies =
|
|
|
|
|
# If the given distribution has an EULA & feels the need to
|
|
|
|
|
# tell the user about it fill in this variable by a path
|
|
|
|
|
# pointing to a file with the EULA on the installed system.
|
|
|
|
|
-#
|
|
|
|
|
-# This is currently used just to show the path to the file to
|
|
|
|
|
-# the user at the end of the installation.
|
|
|
|
|
+
|
|
|
|
|
eula =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
diff --git a/po/ru.po b/po/ru.po
|
|
|
|
|
index 02bf92b..06005c0 100644
|
|
|
|
|
--- a/po/ru.po
|
|
|
|
|
+++ b/po/ru.po
|
|
|
|
|
@@ -7766,6 +7766,37 @@ msgstr "К системе прикреплено {} подписок"
|
|
|
|
|
msgid "{}. {}"
|
|
|
|
|
msgstr "{}. {}"
|
|
|
|
|
|
|
|
|
|
+msgid "LICENSING"
|
|
|
|
|
+msgstr "ЛИЦЕНЗИРОВАНИЕ"
|
|
|
|
|
+
|
|
|
|
|
+msgctxt "GUI|Spoke"
|
|
|
|
|
+msgid "_License Information"
|
|
|
|
|
+msgstr "О _лицензии"
|
|
|
|
|
+
|
|
|
|
|
+msgid "License information"
|
|
|
|
|
+msgstr "О лицензии"
|
|
|
|
|
+
|
|
|
|
|
+msgid "License Information"
|
|
|
|
|
+msgstr "О лицензии"
|
|
|
|
|
+
|
|
|
|
|
+msgid "License accepted"
|
|
|
|
|
+msgstr "Лицензия принята"
|
|
|
|
|
+
|
|
|
|
|
+msgid "License not accepted"
|
|
|
|
|
+msgstr "Лицензия не принята"
|
|
|
|
|
+
|
|
|
|
|
+msgid "Read the License Agreement"
|
|
|
|
|
+msgstr "Прочитайте лицензионное соглашение"
|
|
|
|
|
+
|
|
|
|
|
+msgid "I accept the license agreement"
|
|
|
|
|
+msgstr "Принимаю лицензионное соглашение"
|
|
|
|
|
+
|
|
|
|
|
+msgid "I _accept the license agreement"
|
|
|
|
|
+msgstr "_Принимаю лицензионное соглашение"
|
|
|
|
|
+
|
|
|
|
|
+msgid "License Agreement:"
|
|
|
|
|
+msgstr "Лицензионное соглашение:"
|
|
|
|
|
+
|
|
|
|
|
#~ msgid "Try Fedora"
|
|
|
|
|
#~ msgstr "Попробуйте Fedora"
|
|
|
|
|
|
|
|
|
|
diff --git a/pyanaconda/core/configuration/license.py b/pyanaconda/core/configuration/license.py
|
|
|
|
|
index 04c44bf..a51f52a 100644
|
|
|
|
|
--- a/pyanaconda/core/configuration/license.py
|
|
|
|
|
+++ b/pyanaconda/core/configuration/license.py
|
|
|
|
|
@@ -31,7 +31,5 @@ class LicenseSection(Section):
|
|
|
|
|
tell the user about it fill in this variable by a path
|
|
|
|
|
pointing to a file with the EULA on the installed system.
|
|
|
|
|
|
|
|
|
|
- This is currently used just to show the path to the file to
|
|
|
|
|
- the user at the end of the installation.
|
|
|
|
|
"""
|
|
|
|
|
return self._get_option("eula", str)
|
|
|
|
|
diff --git a/pyanaconda/core/eula.py b/pyanaconda/core/eula.py
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000..15a393e
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/pyanaconda/core/eula.py
|
|
|
|
|
@@ -0,0 +1,23 @@
|
|
|
|
|
+import os
|
|
|
|
|
+from pyanaconda.core.configuration.anaconda import conf
|
|
|
|
|
+
|
|
|
|
|
+def get_license_file_name():
|
|
|
|
|
+ """Get filename of the license file best matching current localization settings.
|
|
|
|
|
+ :return: filename of the license file or None if no license file found
|
|
|
|
|
+ :rtype: str or None
|
|
|
|
|
+ """
|
|
|
|
|
+ if not conf.license.eula:
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ if not os.path.exists(conf.license.eula):
|
|
|
|
|
+ return None
|
|
|
|
|
+
|
|
|
|
|
+ return conf.license.eula
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+def eula_available():
|
|
|
|
|
+ """Report if it looks like there is an EULA available on the system.
|
|
|
|
|
+ :return: True if an EULA seems to be available, False otherwise
|
|
|
|
|
+ :rtype: bool
|
|
|
|
|
+ """
|
|
|
|
|
+ return bool(get_license_file_name())
|
|
|
|
|
diff --git a/pyanaconda/ui/categories/eula.py b/pyanaconda/ui/categories/eula.py
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000..0a4fe96
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/pyanaconda/ui/categories/eula.py
|
|
|
|
|
@@ -0,0 +1,14 @@
|
|
|
|
|
+from pyanaconda.ui.categories import SpokeCategory
|
|
|
|
|
+from pyanaconda.core.i18n import _
|
|
|
|
|
+
|
|
|
|
|
+__all__ = ["LicensingCategory"]
|
|
|
|
|
+
|
|
|
|
|
+class LicensingCategory(SpokeCategory):
|
|
|
|
|
+
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def get_title():
|
|
|
|
|
+ return _("LICENSING")
|
|
|
|
|
+
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def get_sort_order():
|
|
|
|
|
+ return 900
|
|
|
|
|
diff --git a/pyanaconda/ui/gui/spokes/eula.glade b/pyanaconda/ui/gui/spokes/eula.glade
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000..1d340f0
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/pyanaconda/ui/gui/spokes/eula.glade
|
|
|
|
|
@@ -0,0 +1,136 @@
|
|
|
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
|
+<interface>
|
|
|
|
|
+ <!-- interface-requires gtk+ 3.6 -->
|
|
|
|
|
+ <!-- interface-requires AnacondaWidgets 1.0 -->
|
|
|
|
|
+ <object class="GtkTextBuffer" id="eulaBuffer">
|
|
|
|
|
+ <property name="text">The license will go here</property>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ <object class="AnacondaSpokeWindow" id="eulaWindow">
|
|
|
|
|
+ <property name="can_focus">False</property>
|
|
|
|
|
+ <property name="hexpand">True</property>
|
|
|
|
|
+ <property name="vexpand">True</property>
|
|
|
|
|
+ <property name="window_name" translatable="yes">License Information</property>
|
|
|
|
|
+ <signal name="button-clicked" handler="on_back_clicked" swapped="no"/>
|
|
|
|
|
+ <child internal-child="main_box">
|
|
|
|
|
+ <object class="GtkBox" id="AnacondaSpokeWindow-main_box1">
|
|
|
|
|
+ <property name="can_focus">False</property>
|
|
|
|
|
+ <property name="orientation">vertical</property>
|
|
|
|
|
+ <property name="spacing">6</property>
|
|
|
|
|
+ <child internal-child="nav_box">
|
|
|
|
|
+ <object class="GtkEventBox" id="AnacondaSpokeWindow-nav_box1">
|
|
|
|
|
+ <property name="can_focus">False</property>
|
|
|
|
|
+ <child internal-child="nav_area">
|
|
|
|
|
+ <object class="GtkGrid" id="AnacondaSpokeWindow-nav_area1">
|
|
|
|
|
+ <property name="can_focus">False</property>
|
|
|
|
|
+ <property name="margin_left">6</property>
|
|
|
|
|
+ <property name="margin_right">6</property>
|
|
|
|
|
+ <property name="margin_top">6</property>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ <packing>
|
|
|
|
|
+ <property name="expand">False</property>
|
|
|
|
|
+ <property name="fill">False</property>
|
|
|
|
|
+ <property name="position">0</property>
|
|
|
|
|
+ </packing>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ <child internal-child="alignment">
|
|
|
|
|
+ <object class="GtkAlignment" id="AnacondaSpokeWindow-alignment1">
|
|
|
|
|
+ <property name="can_focus">False</property>
|
|
|
|
|
+ <property name="xscale">0.8</property>
|
|
|
|
|
+ <property name="yscale">0.8</property>
|
|
|
|
|
+ <child internal-child="action_area">
|
|
|
|
|
+ <object class="GtkBox" id="mainBox">
|
|
|
|
|
+ <property name="can_focus">False</property>
|
|
|
|
|
+ <property name="orientation">vertical</property>
|
|
|
|
|
+ <child>
|
|
|
|
|
+ <object class="GtkLabel" id="licenseAgreementLabel">
|
|
|
|
|
+ <property name="visible">True</property>
|
|
|
|
|
+ <property name="can_focus">False</property>
|
|
|
|
|
+ <property name="halign">start</property>
|
|
|
|
|
+ <property name="margin_top">24</property>
|
|
|
|
|
+ <property name="margin_bottom">6</property>
|
|
|
|
|
+ <property name="label" translatable="yes">License Agreement:</property>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ <packing>
|
|
|
|
|
+ <property name="expand">False</property>
|
|
|
|
|
+ <property name="fill">True</property>
|
|
|
|
|
+ <property name="position">0</property>
|
|
|
|
|
+ </packing>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ <child>
|
|
|
|
|
+ <object class="GtkBox" id="eulaBox">
|
|
|
|
|
+ <property name="visible">True</property>
|
|
|
|
|
+ <property name="can_focus">False</property>
|
|
|
|
|
+ <property name="hexpand">True</property>
|
|
|
|
|
+ <property name="vexpand">True</property>
|
|
|
|
|
+ <property name="orientation">vertical</property>
|
|
|
|
|
+ <child>
|
|
|
|
|
+ <object class="GtkScrolledWindow" id="eulaScrolledWindow">
|
|
|
|
|
+ <property name="visible">True</property>
|
|
|
|
|
+ <property name="can_focus">True</property>
|
|
|
|
|
+ <property name="shadow_type">in</property>
|
|
|
|
|
+ <child>
|
|
|
|
|
+ <object class="GtkTextView" id="eulaView">
|
|
|
|
|
+ <property name="visible">True</property>
|
|
|
|
|
+ <property name="can_focus">True</property>
|
|
|
|
|
+ <property name="margin_bottom">18</property>
|
|
|
|
|
+ <property name="hexpand">True</property>
|
|
|
|
|
+ <property name="vexpand">True</property>
|
|
|
|
|
+ <property name="vscroll_policy">natural</property>
|
|
|
|
|
+ <property name="pixels_above_lines">12</property>
|
|
|
|
|
+ <property name="editable">False</property>
|
|
|
|
|
+ <property name="wrap_mode">word</property>
|
|
|
|
|
+ <property name="left_margin">12</property>
|
|
|
|
|
+ <property name="right_margin">12</property>
|
|
|
|
|
+ <property name="cursor_visible">False</property>
|
|
|
|
|
+ <property name="buffer">eulaBuffer</property>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ <packing>
|
|
|
|
|
+ <property name="expand">False</property>
|
|
|
|
|
+ <property name="fill">True</property>
|
|
|
|
|
+ <property name="position">0</property>
|
|
|
|
|
+ </packing>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ <child>
|
|
|
|
|
+ <object class="GtkCheckButton" id="agreeCheckButton">
|
|
|
|
|
+ <property name="label" translatable="yes">I _accept the license agreement</property>
|
|
|
|
|
+ <property name="visible">True</property>
|
|
|
|
|
+ <property name="can_focus">True</property>
|
|
|
|
|
+ <property name="receives_default">False</property>
|
|
|
|
|
+ <property name="use_underline">True</property>
|
|
|
|
|
+ <property name="xalign">0</property>
|
|
|
|
|
+ <property name="draw_indicator">True</property>
|
|
|
|
|
+ <signal name="toggled" handler="on_check_button_toggled" swapped="no"/>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ <packing>
|
|
|
|
|
+ <property name="expand">False</property>
|
|
|
|
|
+ <property name="fill">True</property>
|
|
|
|
|
+ <property name="position">2</property>
|
|
|
|
|
+ </packing>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ <packing>
|
|
|
|
|
+ <property name="expand">False</property>
|
|
|
|
|
+ <property name="fill">True</property>
|
|
|
|
|
+ <property name="position">1</property>
|
|
|
|
|
+ </packing>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ <packing>
|
|
|
|
|
+ <property name="expand">True</property>
|
|
|
|
|
+ <property name="fill">True</property>
|
|
|
|
|
+ <property name="position">1</property>
|
|
|
|
|
+ </packing>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ <child>
|
|
|
|
|
+ <placeholder/>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ </object>
|
|
|
|
|
+ </child>
|
|
|
|
|
+ </object>
|
|
|
|
|
+</interface>
|
|
|
|
|
diff --git a/pyanaconda/ui/gui/spokes/eula.py b/pyanaconda/ui/gui/spokes/eula.py
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000..a487c6b
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/pyanaconda/ui/gui/spokes/eula.py
|
|
|
|
|
@@ -0,0 +1,107 @@
|
|
|
|
|
+import logging
|
|
|
|
|
+
|
|
|
|
|
+from pyanaconda.ui.common import FirstbootOnlySpokeMixIn
|
|
|
|
|
+from pyanaconda.ui.gui.spokes import NormalSpoke
|
|
|
|
|
+from pyanaconda.core.i18n import _, CN_
|
|
|
|
|
+from pyanaconda.core import eula
|
|
|
|
|
+from pyanaconda.ui.categories.eula import LicensingCategory
|
|
|
|
|
+from pyanaconda.anaconda_loggers import get_module_logger
|
|
|
|
|
+from pykickstart.constants import FIRSTBOOT_RECONFIG
|
|
|
|
|
+
|
|
|
|
|
+log = get_module_logger(__name__)
|
|
|
|
|
+__all__ = ["EULASpoke"]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class EULASpoke(FirstbootOnlySpokeMixIn, NormalSpoke):
|
|
|
|
|
+ """The EULA spoke"""
|
|
|
|
|
+
|
|
|
|
|
+ builderObjects = ["eulaBuffer", "eulaWindow"]
|
|
|
|
|
+ mainWidgetName = "eulaWindow"
|
|
|
|
|
+ uiFile = "spokes/eula.glade"
|
|
|
|
|
+ icon = "application-certificate-symbolic"
|
|
|
|
|
+ title = CN_("GUI|Spoke", "_License Information")
|
|
|
|
|
+ category = LicensingCategory
|
|
|
|
|
+
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def get_screen_id():
|
|
|
|
|
+ """Return a unique id of this UI screen."""
|
|
|
|
|
+ return "license-information"
|
|
|
|
|
+
|
|
|
|
|
+ def initialize(self):
|
|
|
|
|
+ log.debug("initializing the EULA spoke")
|
|
|
|
|
+ NormalSpoke.initialize(self)
|
|
|
|
|
+
|
|
|
|
|
+ self._have_eula = True
|
|
|
|
|
+ self._eula_buffer = self.builder.get_object("eulaBuffer")
|
|
|
|
|
+ self._agree_check_button = self.builder.get_object("agreeCheckButton")
|
|
|
|
|
+ self._agree_label = self._agree_check_button.get_child()
|
|
|
|
|
+ self._agree_text = self._agree_label.get_text()
|
|
|
|
|
+
|
|
|
|
|
+ log.debug("looking for the license file")
|
|
|
|
|
+ license_file = eula.get_license_file_name()
|
|
|
|
|
+ if not license_file:
|
|
|
|
|
+ log.error("no license found")
|
|
|
|
|
+ self._have_eula = False
|
|
|
|
|
+ self._eula_buffer.set_text(_("No license found"))
|
|
|
|
|
+ return
|
|
|
|
|
+
|
|
|
|
|
+ # if there is "eula <...>" in kickstart, use its value
|
|
|
|
|
+ if self.data.eula.agreed is not None:
|
|
|
|
|
+ self._agree_check_button.set_active(self.data.eula.agreed)
|
|
|
|
|
+
|
|
|
|
|
+ self._eula_buffer.set_text("")
|
|
|
|
|
+ itr = self._eula_buffer.get_iter_at_offset(0)
|
|
|
|
|
+ log.debug("opening the license file")
|
|
|
|
|
+ with open(license_file, "r") as fobj:
|
|
|
|
|
+ # insert the first line without prefixing with space
|
|
|
|
|
+ try:
|
|
|
|
|
+ first_line = next(fobj)
|
|
|
|
|
+ except StopIteration:
|
|
|
|
|
+ # nothing in the file
|
|
|
|
|
+ return
|
|
|
|
|
+ self._eula_buffer.insert(itr, first_line.strip())
|
|
|
|
|
+
|
|
|
|
|
+ # EULA file may be preformatted for the console, we want to let Gtk
|
|
|
|
|
+ # format it (blank lines should be preserved)
|
|
|
|
|
+ for line in fobj:
|
|
|
|
|
+ stripped_line = line.strip()
|
|
|
|
|
+ if stripped_line:
|
|
|
|
|
+ self._eula_buffer.insert(itr, " " + stripped_line)
|
|
|
|
|
+ else:
|
|
|
|
|
+ self._eula_buffer.insert(itr, "\n\n")
|
|
|
|
|
+
|
|
|
|
|
+ def refresh(self):
|
|
|
|
|
+ self._agree_check_button.set_sensitive(self._have_eula)
|
|
|
|
|
+ self._agree_check_button.set_active(self.data.eula.agreed)
|
|
|
|
|
+
|
|
|
|
|
+ def apply(self):
|
|
|
|
|
+ self.data.eula.agreed = self._agree_check_button.get_active()
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def completed(self):
|
|
|
|
|
+ return not self._have_eula or self.data.eula.agreed
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def status(self):
|
|
|
|
|
+ if not self._have_eula:
|
|
|
|
|
+ return _("No license found")
|
|
|
|
|
+
|
|
|
|
|
+ return _("License accepted") if self.data.eula.agreed else _("License not accepted")
|
|
|
|
|
+
|
|
|
|
|
+ @classmethod
|
|
|
|
|
+ def should_run(cls, environment, data):
|
|
|
|
|
+ if eula.eula_available():
|
|
|
|
|
+ # don't run if we are in initial-setup in reconfig mode and the EULA has already been accepted
|
|
|
|
|
+ if FirstbootOnlySpokeMixIn.should_run(environment, data) and data and data.firstboot.firstboot == FIRSTBOOT_RECONFIG and data.eula.agreed:
|
|
|
|
|
+ log.debug("not running license spoke: reconfig mode & license already accepted")
|
|
|
|
|
+ return False
|
|
|
|
|
+ return True
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ def on_check_button_toggled(self, *args):
|
|
|
|
|
+ if self._agree_check_button.get_active():
|
|
|
|
|
+ log.debug("license is now accepted")
|
|
|
|
|
+ self._agree_label.set_markup("<b>%s</b>" % self._agree_text)
|
|
|
|
|
+ else:
|
|
|
|
|
+ log.debug("license no longer accepted")
|
|
|
|
|
+ self._agree_label.set_markup(self._agree_text)
|
|
|
|
|
diff --git a/pyanaconda/ui/tui/spokes/eula.py b/pyanaconda/ui/tui/spokes/eula.py
|
|
|
|
|
new file mode 100644
|
|
|
|
|
index 0000000..a3e8e62
|
|
|
|
|
--- /dev/null
|
|
|
|
|
+++ b/pyanaconda/ui/tui/spokes/eula.py
|
|
|
|
|
@@ -0,0 +1,128 @@
|
|
|
|
|
+import logging
|
|
|
|
|
+
|
|
|
|
|
+from pyanaconda.ui.tui.spokes import NormalTUISpoke
|
|
|
|
|
+from simpleline.render.widgets import TextWidget, CheckboxWidget
|
|
|
|
|
+from simpleline.render.containers import ListRowContainer
|
|
|
|
|
+from simpleline.render.screen import UIScreen, InputState
|
|
|
|
|
+from simpleline.render.screen_handler import ScreenHandler
|
|
|
|
|
+from pyanaconda.ui.common import FirstbootOnlySpokeMixIn
|
|
|
|
|
+from pyanaconda.core import eula
|
|
|
|
|
+from pyanaconda.ui.categories.eula import LicensingCategory
|
|
|
|
|
+from pyanaconda.core.i18n import _, N_
|
|
|
|
|
+from pykickstart.constants import FIRSTBOOT_RECONFIG
|
|
|
|
|
+
|
|
|
|
|
+log = logging.getLogger("initial-setup")
|
|
|
|
|
+
|
|
|
|
|
+__all__ = ["EULASpoke"]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class EULASpoke(FirstbootOnlySpokeMixIn, NormalTUISpoke):
|
|
|
|
|
+ """The EULA spoke providing ways to read the license and agree/disagree with it."""
|
|
|
|
|
+
|
|
|
|
|
+ category = LicensingCategory
|
|
|
|
|
+
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def get_screen_id():
|
|
|
|
|
+ """Return a unique id of this UI screen."""
|
|
|
|
|
+ return "license-information"
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self, *args, **kwargs):
|
|
|
|
|
+ NormalTUISpoke.__init__(self, *args, **kwargs)
|
|
|
|
|
+ self.title = _("License information")
|
|
|
|
|
+ self._container = None
|
|
|
|
|
+
|
|
|
|
|
+ def initialize(self):
|
|
|
|
|
+ NormalTUISpoke.initialize(self)
|
|
|
|
|
+
|
|
|
|
|
+ def refresh(self, args=None):
|
|
|
|
|
+ NormalTUISpoke.refresh(self, args)
|
|
|
|
|
+
|
|
|
|
|
+ self._container = ListRowContainer(1)
|
|
|
|
|
+
|
|
|
|
|
+ log.debug("license found")
|
|
|
|
|
+ # make the options aligned to the same column (the checkbox has the
|
|
|
|
|
+ # '[ ]' prepended)
|
|
|
|
|
+ self._container.add(TextWidget("%s\n" % _("Read the License Agreement")),
|
|
|
|
|
+ self._show_license_screen_callback)
|
|
|
|
|
+
|
|
|
|
|
+ self._container.add(CheckboxWidget(title=_("I accept the license agreement"),
|
|
|
|
|
+ completed=self.data.eula.agreed),
|
|
|
|
|
+ self._license_accepted_callback)
|
|
|
|
|
+ self.window.add_with_separator(self._container)
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def completed(self):
|
|
|
|
|
+ # Either there is no EULA available, or user agrees/disagrees with it.
|
|
|
|
|
+ return self.data.eula.agreed
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def mandatory(self):
|
|
|
|
|
+ # This spoke is always mandatory.
|
|
|
|
|
+ return True
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def status(self):
|
|
|
|
|
+ return _("License accepted") if self.data.eula.agreed else _("License not accepted")
|
|
|
|
|
+
|
|
|
|
|
+ @classmethod
|
|
|
|
|
+ def should_run(cls, environment, data):
|
|
|
|
|
+ if eula.eula_available():
|
|
|
|
|
+ # don't run if we are in initial-setup in reconfig mode and the EULA has already been accepted
|
|
|
|
|
+ if FirstbootOnlySpokeMixIn.should_run(environment, data) and data and data.firstboot.firstboot == FIRSTBOOT_RECONFIG and data.eula.agreed:
|
|
|
|
|
+ log.debug("not running license spoke: reconfig mode & license already accepted")
|
|
|
|
|
+ return False
|
|
|
|
|
+ return True
|
|
|
|
|
+ return False
|
|
|
|
|
+
|
|
|
|
|
+ def apply(self):
|
|
|
|
|
+ # nothing needed here, the agreed field is changed in the input method
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+ def input(self, args, key):
|
|
|
|
|
+ if not self._container.process_user_input(key):
|
|
|
|
|
+ return key
|
|
|
|
|
+
|
|
|
|
|
+ return InputState.PROCESSED
|
|
|
|
|
+
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def _show_license_screen_callback(data):
|
|
|
|
|
+ # show license
|
|
|
|
|
+ log.debug("showing the license")
|
|
|
|
|
+ eula_screen = LicenseScreen()
|
|
|
|
|
+ ScreenHandler.push_screen(eula_screen)
|
|
|
|
|
+
|
|
|
|
|
+ def _license_accepted_callback(self, data):
|
|
|
|
|
+ # toggle EULA agreed checkbox by changing ksdata
|
|
|
|
|
+ log.debug("license accepted state changed to: %s", self.data.eula.agreed)
|
|
|
|
|
+ self.data.eula.agreed = not self.data.eula.agreed
|
|
|
|
|
+ self.redraw()
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+class LicenseScreen(UIScreen):
|
|
|
|
|
+ """Screen showing the License without any input from user requested."""
|
|
|
|
|
+
|
|
|
|
|
+ def __init__(self):
|
|
|
|
|
+ super().__init__()
|
|
|
|
|
+
|
|
|
|
|
+ self._license_file = eula.get_license_file_name()
|
|
|
|
|
+
|
|
|
|
|
+ def refresh(self, args=None):
|
|
|
|
|
+ super().refresh(args)
|
|
|
|
|
+
|
|
|
|
|
+ # read the license file and make it one long string so that it can be
|
|
|
|
|
+ # processed by the TextWidget to fit in the screen in a best possible
|
|
|
|
|
+ # way
|
|
|
|
|
+ log.debug("reading the license file")
|
|
|
|
|
+ with open(self._license_file, 'r') as f:
|
|
|
|
|
+ license_text = f.read()
|
|
|
|
|
+
|
|
|
|
|
+ self.window.add_with_separator(TextWidget(license_text))
|
|
|
|
|
+
|
|
|
|
|
+ def input(self, args, key):
|
|
|
|
|
+ """ Handle user input. """
|
|
|
|
|
+ return InputState.PROCESSED_AND_CLOSE
|
|
|
|
|
+
|
|
|
|
|
+ def prompt(self, args=None):
|
|
|
|
|
+ # we don't want to prompt user, just close the screen
|
|
|
|
|
+ self.close()
|
|
|
|
|
+ return None
|
|
|
|
|
--
|
|
|
|
|
2.47.0
|
|
|
|
|
|