Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/menu
diff options
context:
space:
mode:
authorDaniel Girtler <blackrabbit256@gmail.com>2022-05-27 05:48:29 +1000
committerGitHub <noreply@github.com>2022-05-26 21:48:29 +0200
commit870da403e79ab50350803b45f200e0b272334989 (patch)
tree9b203a054bd10cbc73a81b4fd5fe24ef8e6f141a /archinstall/lib/menu
parent353c05318ce80b8eec32031c9e14b8471b458548 (diff)
Rework user management (#1220)
* Rework users * Update user installation * Fix config serialization * Update * Update schemas and documentation * Update * Fix flake8 * Make users mypy compatible * Fix minor copy Co-authored-by: Daniel Girtler <girtler.daniel@gmail.com> Co-authored-by: Anton Hvornum <anton@hvornum.se>
Diffstat (limited to 'archinstall/lib/menu')
-rw-r--r--archinstall/lib/menu/global_menu.py53
-rw-r--r--archinstall/lib/menu/list_manager.py37
2 files changed, 39 insertions, 51 deletions
diff --git a/archinstall/lib/menu/global_menu.py b/archinstall/lib/menu/global_menu.py
index 53e0941d..5cb27cab 100644
--- a/archinstall/lib/menu/global_menu.py
+++ b/archinstall/lib/menu/global_menu.py
@@ -21,7 +21,6 @@ from ..user_interaction import ask_hostname
from ..user_interaction import ask_for_audio_selection
from ..user_interaction import ask_additional_packages_to_install
from ..user_interaction import ask_to_configure_network
-from ..user_interaction import ask_for_superuser_account
from ..user_interaction import ask_for_additional_users
from ..user_interaction import select_language
from ..user_interaction import select_mirror_regions
@@ -33,7 +32,9 @@ from ..user_interaction import select_encrypted_partitions
from ..user_interaction import select_harddrives
from ..user_interaction import select_profile
from ..user_interaction import select_additional_repositories
+from ..models.users import User
from ..user_interaction.partitioning_conf import current_partition_layout
+from ..output import FormattedOutput
if TYPE_CHECKING:
_: Any
@@ -122,21 +123,13 @@ class GlobalMenu(GeneralMenu):
_('Root password'),
lambda preset:self._set_root_password(),
display_func=lambda x: secret(x) if x else 'None')
- self._menu_options['!superusers'] = \
- Selector(
- _('Superuser account'),
- lambda preset: self._create_superuser_account(),
- default={},
- exec_func=lambda n,v:self._users_resynch(),
- dependencies_not=['!root-password'],
- display_func=lambda x: self._display_superusers())
self._menu_options['!users'] = \
Selector(
_('User account'),
- lambda x: self._create_user_account(),
+ lambda x: self._create_user_account(x),
default={},
- exec_func=lambda n,v:self._users_resynch(),
- display_func=lambda x: list(x.keys()) if x else '[]')
+ display_func=lambda x: f'{len(x)} {_("User(s)")}' if len(x) > 0 else None,
+ preview_func=self._prev_users)
self._menu_options['profile'] = \
Selector(
_('Profile'),
@@ -273,17 +266,28 @@ class GlobalMenu(GeneralMenu):
return text[:-1] # remove last new line
return None
+ def _prev_users(self) -> Optional[str]:
+ selector = self._menu_options['!users']
+ if selector.has_selection():
+ users: List[User] = selector.current_selection
+ return FormattedOutput.as_table(users)
+ return None
+
def _missing_configs(self) -> List[str]:
def check(s):
return self._menu_options.get(s).has_selection()
+ def has_superuser() -> bool:
+ users = self._menu_options['!users'].current_selection
+ return any([u.sudo for u in users])
+
missing = []
if not check('bootloader'):
missing += ['Bootloader']
if not check('hostname'):
missing += ['Hostname']
- if not check('!root-password') and not check('!superusers'):
- missing += [str(_('Either root-password or at least 1 superuser must be specified'))]
+ if not check('!root-password') and not has_superuser():
+ missing += [str(_('Either root-password or at least 1 user with sudo privileges must be specified'))]
if not check('harddrives'):
missing += ['Hard drives']
if check('harddrives'):
@@ -380,23 +384,6 @@ class GlobalMenu(GeneralMenu):
return ret
- def _create_superuser_account(self) -> Optional[Dict[str, Dict[str, str]]]:
- superusers = ask_for_superuser_account(str(_('Manage superuser accounts: ')))
- return superusers if superusers else None
-
- def _create_user_account(self) -> Dict[str, Dict[str, str | None]]:
- users = ask_for_additional_users(str(_('Manage ordinary user accounts: ')))
+ def _create_user_account(self, defined_users: List[User]) -> List[User]:
+ users = ask_for_additional_users(defined_users=defined_users)
return users
-
- def _display_superusers(self):
- superusers = self._data_store.get('!superusers', {})
-
- if self._menu_options.get('!root-password').has_selection():
- return list(superusers.keys()) if superusers else '[]'
- else:
- return list(superusers.keys()) if superusers else ''
-
- def _users_resynch(self) -> bool:
- self.synch('!superusers')
- self.synch('!users')
- return False
diff --git a/archinstall/lib/menu/list_manager.py b/archinstall/lib/menu/list_manager.py
index 7db3b3a9..cb567093 100644
--- a/archinstall/lib/menu/list_manager.py
+++ b/archinstall/lib/menu/list_manager.py
@@ -84,13 +84,13 @@ The contents in the base class of this methods serve for a very basic usage, and
```
"""
-
-from .text_input import TextInput
-from .menu import Menu, MenuSelectionType
+import copy
from os import system
-from copy import copy
from typing import Union, Any, TYPE_CHECKING, Dict, Optional
+from .text_input import TextInput
+from .menu import Menu
+
if TYPE_CHECKING:
_: Any
@@ -144,14 +144,14 @@ class ListManager:
self.bottom_list = [self.confirm_action,self.cancel_action]
self.bottom_item = [self.cancel_action]
self.base_actions = base_actions if base_actions else [str(_('Add')),str(_('Copy')),str(_('Edit')),str(_('Delete'))]
- self.base_data = base_list
- self._data = copy(base_list) # as refs, changes are immediate
+ self._original_data = copy.deepcopy(base_list)
+ self._data = copy.deepcopy(base_list) # as refs, changes are immediate
# default values for the null case
self.target: Optional[Any] = None
self.action = self._null_action
if len(self._data) == 0 and self._null_action:
- self.exec_action(self._data)
+ self._data = self.exec_action(self._data)
def run(self):
while True:
@@ -175,12 +175,10 @@ class ListManager:
clear_screen=False,
clear_menu_on_exit=False,
header=self.header,
- skip_empty_entries=True
+ skip_empty_entries=True,
+ skip=False
).run()
- if target.type_ == MenuSelectionType.Esc:
- return self.run()
-
if not target.value or target.value in self.bottom_list:
self.action = target
break
@@ -188,21 +186,23 @@ class ListManager:
if target.value and target.value in self._default_action:
self.action = target.value
self.target = None
- self.exec_action(self._data)
+ self._data = self.exec_action(self._data)
continue
if isinstance(self._data,dict):
data_key = data_formatted[target.value]
key = self._data[data_key]
self.target = {data_key: key}
+ elif isinstance(self._data, list):
+ self.target = [d for d in self._data if d == data_formatted[target.value]][0]
else:
self.target = self._data[data_formatted[target.value]]
# Possible enhacement. If run_actions returns false a message line indicating the failure
self.run_actions(target.value)
- if not target or target == self.cancel_action: # TODO dubious
- return self.base_data # return the original list
+ if target.value == self.cancel_action: # TODO dubious
+ return self._original_data # return the original list
else:
return self._data
@@ -221,10 +221,9 @@ class ListManager:
self.action = choice.value
- if not self.action or self.action == self.cancel_action:
- return False
- else:
- return self.exec_action(self._data)
+ if self.action and self.action != self.cancel_action:
+ self._data = self.exec_action(self._data)
+
"""
The following methods are expected to be overwritten by the user if the needs of the list are beyond the simple case
"""
@@ -293,3 +292,5 @@ class ListManager:
self._data[origkey] = value
elif self.action == str(_('Delete')):
del self._data[origkey]
+
+ return self._data