mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-06 21:44:16 +02:00
[web] feature: new custom action button to install apps
This commit is contained in:
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [0.9.24]
|
||||
### Features
|
||||
- Web
|
||||
- new custom action button to install apps (to improve usability since some users don't know about how to install Web apps through the search bar)
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/vinifmor/bauh-files/master/pictures/releases/0.9.24/install_web_app.png">
|
||||
</p>
|
||||
|
||||
### Improvements
|
||||
- General
|
||||
- handling http redirect errors
|
||||
|
||||
@@ -56,6 +56,9 @@ class HttpClient:
|
||||
elif isinstance(e, requests.exceptions.TooManyRedirects):
|
||||
self.logger.warning(f"Too many redirects for GET -> {url}")
|
||||
raise e
|
||||
elif e.__class__ in (requests.exceptions.MissingSchema, requests.exceptions.InvalidSchema):
|
||||
self.logger.warning(f"The URL '{url}' has an invalid schema")
|
||||
raise e
|
||||
|
||||
self.logger.error("Could not retrieve data from '{}'".format(url))
|
||||
traceback.print_exc()
|
||||
|
||||
@@ -14,7 +14,7 @@ from typing import List, Type, Set, Tuple, Optional, Dict
|
||||
import requests
|
||||
import yaml
|
||||
from colorama import Fore
|
||||
from requests import exceptions, Response
|
||||
from requests import Response
|
||||
|
||||
from bauh.api.abstract.context import ApplicationContext
|
||||
from bauh.api.abstract.controller import SoftwareManager, SearchResult, UpgradeRequirements, TransactionResult, \
|
||||
@@ -74,13 +74,22 @@ class WebApplicationManager(SoftwareManager):
|
||||
self.suggestions = {}
|
||||
self.configman = WebConfigManager()
|
||||
self.idxman = SearchIndexManager(logger=context.logger)
|
||||
self.custom_actions = [CustomSoftwareAction(i18n_label_key='web.custom_action.clean_env',
|
||||
i18n_status_key='web.custom_action.clean_env.status',
|
||||
manager=self,
|
||||
manager_method='clean_environment',
|
||||
icon_path=resource.get_path('img/web.svg', ROOT_DIR),
|
||||
requires_root=False,
|
||||
refresh=False)]
|
||||
self.custom_actions = [
|
||||
CustomSoftwareAction(i18n_label_key='web.custom_action.install_app',
|
||||
i18n_status_key='web.custom_action.install_app.status',
|
||||
manager=self,
|
||||
manager_method='install_app',
|
||||
icon_path=resource.get_path('img/web.svg', ROOT_DIR),
|
||||
requires_root=False,
|
||||
refresh=True),
|
||||
CustomSoftwareAction(i18n_label_key='web.custom_action.clean_env',
|
||||
i18n_status_key='web.custom_action.clean_env.status',
|
||||
manager=self,
|
||||
manager_method='clean_environment',
|
||||
icon_path=resource.get_path('img/web.svg', ROOT_DIR),
|
||||
requires_root=False,
|
||||
refresh=False)
|
||||
]
|
||||
|
||||
def _get_lang_header(self) -> str:
|
||||
try:
|
||||
@@ -222,7 +231,7 @@ class WebApplicationManager(SoftwareManager):
|
||||
def _strip_url_protocol(self, url: str) -> str:
|
||||
return RE_PROTOCOL_STRIP.split(url)[1].strip().lower()
|
||||
|
||||
def serialize_to_disk(self, pkg: SoftwarePackage, icon_bytes: bytes, only_icon: bool):
|
||||
def serialize_to_disk(self, pkg: SoftwarePackage, icon_bytes: Optional[bytes], only_icon: bool):
|
||||
super(WebApplicationManager, self).serialize_to_disk(pkg=pkg, icon_bytes=None, only_icon=False)
|
||||
|
||||
def _request_url(self, url: str) -> Optional[Response]:
|
||||
@@ -230,8 +239,8 @@ class WebApplicationManager(SoftwareManager):
|
||||
|
||||
try:
|
||||
return self.http_client.get(url, headers=headers, ignore_ssl=True, single_call=True, session=False, allow_redirects=True)
|
||||
except (exceptions.ConnectionError, requests.exceptions.TooManyRedirects) as e:
|
||||
self.logger.warning(f"Could not GET {url}. Exception: {e.__class__.__name__}")
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Could not GET '{url}'. Exception: {e.__class__.__name__}")
|
||||
|
||||
def _map_url(self, url: str) -> Tuple["BeautifulSoup", requests.Response]:
|
||||
url_res = self._request_url(url)
|
||||
@@ -473,10 +482,10 @@ class WebApplicationManager(SoftwareManager):
|
||||
def get_history(self, pkg: SoftwarePackage) -> PackageHistory:
|
||||
pass
|
||||
|
||||
def _ask_install_options(self, app: WebApplication, watcher: ProcessWatcher) -> Tuple[bool, List[str]]:
|
||||
def _ask_install_options(self, app: WebApplication, watcher: ProcessWatcher, pre_validated: bool) -> Tuple[bool, List[str]]:
|
||||
watcher.change_substatus(self.i18n['web.install.substatus.options'])
|
||||
|
||||
inp_url = TextInputComponent(label=self.i18n['address'], value=app.url, read_only=True)
|
||||
inp_url = TextInputComponent(label=self.i18n['address'], value=app.url, read_only=pre_validated)
|
||||
inp_name = TextInputComponent(label=self.i18n['name'], value=app.name)
|
||||
inp_desc = TextInputComponent(label=self.i18n['description'], value=app.description)
|
||||
|
||||
@@ -513,11 +522,15 @@ class WebApplicationManager(SoftwareManager):
|
||||
|
||||
icon_op_ded = InputOption(id_='icon_ded', label=self.i18n['web.install.option.wicon.deducted.label'], value=0,
|
||||
tooltip=self.i18n['web.install.option.wicon.deducted.tip'].format('Nativefier'))
|
||||
icon_op_disp = InputOption(id_='icon_disp', label=self.i18n['web.install.option.wicon.displayed.label'],
|
||||
value=1, tooltip=self.i18n['web.install.option.wicon.displayed.tip'])
|
||||
|
||||
if pre_validated:
|
||||
icon_op_disp = InputOption(id_='icon_disp', label=self.i18n['web.install.option.wicon.displayed.label'],
|
||||
value=1, tooltip=self.i18n['web.install.option.wicon.displayed.tip'])
|
||||
else:
|
||||
icon_op_disp = None
|
||||
|
||||
inp_icon = SingleSelectComponent(type_=SelectViewType.COMBO,
|
||||
options=[icon_op_disp, icon_op_ded],
|
||||
options=[op for op in (icon_op_ded, icon_op_disp) if op],
|
||||
default_option=icon_op_disp if app.icon_url and app.save_icon else icon_op_ded,
|
||||
label=self.i18n['web.install.option.wicon.label'])
|
||||
|
||||
@@ -544,13 +557,24 @@ class WebApplicationManager(SoftwareManager):
|
||||
|
||||
check_options = MultipleSelectComponent(options=adv_opts, default_options=def_adv_opts, label=self.i18n['web.install.options.advanced'].capitalize())
|
||||
|
||||
res = watcher.request_confirmation(title=self.i18n['web.install.options_dialog.title'],
|
||||
body=None,
|
||||
components=[form_1, check_options],
|
||||
confirmation_label=self.i18n['continue'].capitalize(),
|
||||
deny_label=self.i18n['cancel'].capitalize())
|
||||
install_ = watcher.request_confirmation(title=self.i18n['web.install.options_dialog.title'],
|
||||
body=None,
|
||||
components=[form_1, check_options],
|
||||
confirmation_label=self.i18n['continue'].capitalize(),
|
||||
deny_label=self.i18n['cancel'].capitalize())
|
||||
|
||||
if install_:
|
||||
if not pre_validated:
|
||||
typed_url = inp_url.get_value().strip()
|
||||
|
||||
if not typed_url or not self._request_url(typed_url):
|
||||
watcher.show_message(title=self.i18n['error'].capitalize(),
|
||||
type_=MessageType.ERROR,
|
||||
body=self.i18n['web.custom_action.install_app.invalid_url'].format(url=bold(f'"{inp_url.get_value()}"')))
|
||||
return False, []
|
||||
else:
|
||||
app.url = typed_url
|
||||
|
||||
if res:
|
||||
selected = []
|
||||
|
||||
if check_options.values:
|
||||
@@ -579,9 +603,9 @@ class WebApplicationManager(SoftwareManager):
|
||||
app.set_custom_icon(icon_chooser.file_path)
|
||||
selected.append('--icon={}'.format(icon_chooser.file_path))
|
||||
|
||||
app.save_icon = inp_icon.value == icon_op_disp
|
||||
app.save_icon = inp_icon.value == icon_op_disp if icon_op_disp else False
|
||||
|
||||
return res, selected
|
||||
return True, selected
|
||||
|
||||
return False, []
|
||||
|
||||
@@ -649,13 +673,9 @@ class WebApplicationManager(SoftwareManager):
|
||||
pkg.name))
|
||||
traceback.print_exc()
|
||||
|
||||
def install(self, pkg: WebApplication, root_password: str, disk_loader: DiskCacheLoader, watcher: ProcessWatcher) -> TransactionResult:
|
||||
continue_install, install_options = self._ask_install_options(pkg, watcher)
|
||||
def _install(self, pkg: WebApplication, install_options: List[str], watcher: ProcessWatcher) -> TransactionResult:
|
||||
widevine_support = '--widevine' in install_options
|
||||
|
||||
if not continue_install:
|
||||
return TransactionResult(success=False, installed=[], removed=[])
|
||||
|
||||
watcher.change_substatus(self.i18n['web.env.checking'])
|
||||
handler = ProcessHandler(watcher)
|
||||
|
||||
@@ -664,7 +684,8 @@ class WebApplicationManager(SoftwareManager):
|
||||
|
||||
if web_config['environment']['system'] and not nativefier.is_available():
|
||||
watcher.show_message(title=self.i18n['error'].capitalize(),
|
||||
body=self.i18n['web.install.global_nativefier.unavailable'].format(n=bold('Nativefier'), app=bold(pkg.name)) + '.',
|
||||
body=self.i18n['web.install.global_nativefier.unavailable'].format(
|
||||
n=bold('Nativefier'), app=bold(pkg.name)) + '.',
|
||||
type_=MessageType.ERROR)
|
||||
return TransactionResult(success=False, installed=[], removed=[])
|
||||
|
||||
@@ -677,8 +698,9 @@ class WebApplicationManager(SoftwareManager):
|
||||
if comps_to_update and not self._ask_update_permission(comps_to_update, watcher):
|
||||
return TransactionResult(success=False, installed=[], removed=[])
|
||||
|
||||
if not self.env_updater.update(components=comps_to_update, handler=handler):
|
||||
watcher.show_message(title=self.i18n['error'], body=self.i18n['web.env.error'].format(bold(pkg.name)), type_=MessageType.ERROR)
|
||||
if not self.env_updater.update(components=comps_to_update, handler=handler):
|
||||
watcher.show_message(title=self.i18n['error'], body=self.i18n['web.env.error'].format(bold(pkg.name)),
|
||||
type_=MessageType.ERROR)
|
||||
return TransactionResult(success=False, installed=[], removed=[])
|
||||
|
||||
Path(INSTALLED_PATH).mkdir(parents=True, exist_ok=True)
|
||||
@@ -737,11 +759,13 @@ class WebApplicationManager(SoftwareManager):
|
||||
if hasattr(pkg, prop):
|
||||
try:
|
||||
setattr(pkg, prop, val)
|
||||
self.logger.info(f"Using custom installation property '{prop}' ({val if val else '<null>'}) for '{url_domain}' "
|
||||
f"(Electron: {electron_version})")
|
||||
self.logger.info(
|
||||
f"Using custom installation property '{prop}' ({val if val else '<null>'}) for '{url_domain}' "
|
||||
f"(Electron: {electron_version})")
|
||||
except:
|
||||
self.logger.error(f"Could not set the custom installation property '{prop}' ({val if val else '<null>'}) "
|
||||
f"for '{url_domain}' (Electron: {electron_version})")
|
||||
self.logger.error(
|
||||
f"Could not set the custom installation property '{prop}' ({val if val else '<null>'}) "
|
||||
f"for '{url_domain}' (Electron: {electron_version})")
|
||||
|
||||
watcher.change_substatus(self.i18n['web.install.substatus.call_nativefier'].format(bold('nativefier')))
|
||||
|
||||
@@ -754,7 +778,8 @@ class WebApplicationManager(SoftwareManager):
|
||||
|
||||
if not installed:
|
||||
msg = '{}.{}.'.format(self.i18n['wen.install.error'].format(bold(pkg.name)),
|
||||
self.i18n['web.install.nativefier.error.unknown'].format(bold(self.i18n['details'].capitalize())))
|
||||
self.i18n['web.install.nativefier.error.unknown'].format(
|
||||
bold(self.i18n['details'].capitalize())))
|
||||
watcher.show_message(title=self.i18n['error'], body=msg, type_=MessageType.ERROR)
|
||||
return TransactionResult(success=False, installed=[], removed=[])
|
||||
|
||||
@@ -825,6 +850,27 @@ class WebApplicationManager(SoftwareManager):
|
||||
|
||||
return TransactionResult(success=True, installed=[pkg], removed=[])
|
||||
|
||||
def install(self, pkg: WebApplication, root_password: str, disk_loader: DiskCacheLoader, watcher: ProcessWatcher) -> TransactionResult:
|
||||
continue_install, install_options = self._ask_install_options(pkg, watcher, pre_validated=True)
|
||||
|
||||
if not continue_install:
|
||||
return TransactionResult(success=False, installed=[], removed=[])
|
||||
|
||||
return self._install(pkg, install_options, watcher)
|
||||
|
||||
def install_app(self, root_password: str, watcher: ProcessWatcher) -> bool:
|
||||
pkg = WebApplication()
|
||||
continue_install, install_options = self._ask_install_options(pkg, watcher, pre_validated=False)
|
||||
|
||||
if not continue_install:
|
||||
return False
|
||||
|
||||
if self._install(pkg, install_options, watcher).success:
|
||||
self.serialize_to_disk(pkg, icon_bytes=None, only_icon=False)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _gen_desktop_entry_content(self, pkg: WebApplication) -> str:
|
||||
return """
|
||||
[Desktop Entry]
|
||||
|
||||
@@ -4,6 +4,9 @@ web.custom_action.clean_env.failed=An error occurred during the installation env
|
||||
web.custom_action.clean_env.status=Cleaning the installation environment
|
||||
web.custom_action.clean_env.success=Installation environment cleaned
|
||||
web.custom_action.clean_env=Clean installation environment
|
||||
web.custom_action.install_app=Install Web application
|
||||
web.custom_action.install_app.invalid_url=The address {url} could not be found. It is not possible to finish the installation.
|
||||
web.custom_action.install_app.status=Installing Web application
|
||||
web.env.checking=Checking the Web installation environment
|
||||
web.env.error=It seems there are issues with the Web installation environment. It wil not be possible to install {}.
|
||||
web.environment.install=Installing {}
|
||||
|
||||
@@ -4,6 +4,9 @@ web.custom_action.clean_env.failed=An error occurred during the installation env
|
||||
web.custom_action.clean_env.status=Cleaning the installation environment
|
||||
web.custom_action.clean_env.success=Installation environment cleaned
|
||||
web.custom_action.clean_env=Clean installation environment
|
||||
web.custom_action.install_app=Install Web application
|
||||
web.custom_action.install_app.invalid_url=The address {url} could not be found. It is not possible to finish the installation.
|
||||
web.custom_action.install_app.status=Installing Web application
|
||||
web.env.checking=Checking the Web installation environment
|
||||
web.env.error=It seems there are issues with the Web installation environment. It wil not be possible to install {}.
|
||||
web.environment.install=Installing {}
|
||||
|
||||
@@ -4,6 +4,9 @@ web.custom_action.clean_env.failed=Se produjo un error durante la limpieza del a
|
||||
web.custom_action.clean_env.status=Limpiando el ambiente de instalación
|
||||
web.custom_action.clean_env.success=Ambiente de instalación limpio
|
||||
web.custom_action.clean_env=Limpiar ambiente de instalación
|
||||
web.custom_action.install_app=Instalar aplicación Web
|
||||
web.custom_action.install_app.invalid_url=No se pudo encontrar la dirección {url}. No es posible finalizar la instalación.
|
||||
web.custom_action.install_app.status=Instalando aplicación Web
|
||||
web.env.checking=Verificando el ambiente de instalación web
|
||||
web.env.error=Parece que hay problemas con el ambiente de instalación web. No será posible instalar {}.
|
||||
web.environment.install=Instalando {}
|
||||
|
||||
@@ -4,6 +4,9 @@ web.custom_action.clean_env.failed=Une erreur est survenue lors du nettoyage de
|
||||
web.custom_action.clean_env.status=Nettoyage de l'environnement d'installation
|
||||
web.custom_action.clean_env.success=Environnement d'installation nettoyé
|
||||
web.custom_action.clean_env=Nettoyage de l'environnement d'installation Web.
|
||||
web.custom_action.install_app=Install Web application
|
||||
web.custom_action.install_app.invalid_url=The address {url} could not be found. It is not possible to finish the installation.
|
||||
web.custom_action.install_app.status=Installing Web application
|
||||
web.env.checking=Verification de l'environnement d'installation Web.
|
||||
web.env.error=Il y a des problèmes avec l'environnement d'installation Web. {} ne pourra pas être installé.
|
||||
web.environment.install=Intallation de {}
|
||||
|
||||
@@ -4,6 +4,9 @@ web.custom_action.clean_env.failed=An error occurred during the installation env
|
||||
web.custom_action.clean_env.status=Cleaning the installation environment
|
||||
web.custom_action.clean_env.success=Installation environment cleaned
|
||||
web.custom_action.clean_env=Clean installation environment
|
||||
web.custom_action.install_app=Install Web application
|
||||
web.custom_action.install_app.invalid_url=The address {url} could not be found. It is not possible to finish the installation.
|
||||
web.custom_action.install_app.status=Installing Web application
|
||||
web.env.checking=Checking the Web installation environment
|
||||
web.env.error=It seems there are issues with the Web installation environment. It wil not be possible to install {}.
|
||||
web.environment.install=Installing {}
|
||||
|
||||
@@ -4,6 +4,9 @@ web.custom_action.clean_env.failed=Ocorreu um problema durante a limpeza do ambi
|
||||
web.custom_action.clean_env.status=Limpando ambiente de instalação
|
||||
web.custom_action.clean_env.success=Ambiente de instalação limpo
|
||||
web.custom_action.clean_env=Limpar ambiente de instalação
|
||||
web.custom_action.install_app=Instalar aplicação Web
|
||||
web.custom_action.install_app.invalid_url=O endereço {url} não foi encontrado. Não é possível finalizar a instalação.
|
||||
web.custom_action.install_app.status=Instalando aplicação Web
|
||||
web.env.checking=Verificando o ambiente de instalação Web
|
||||
web.env.error=Parce que existem problemas com o ambiente de instalação Web. Não será possível instalar {}.
|
||||
web.environment.nativefier=Instalando {}
|
||||
|
||||
@@ -4,6 +4,9 @@ web.custom_action.clean_env=Очистка среды установки
|
||||
web.custom_action.clean_env.failed=Произошла ошибка при очистке среды установки
|
||||
web.custom_action.clean_env.status=Среда установки будет очищена
|
||||
web.custom_action.clean_env.success=Среда установки очищена!
|
||||
web.custom_action.install_app=Install Web application
|
||||
web.custom_action.install_app.invalid_url=The address {url} could not be found. It is not possible to finish the installation.
|
||||
web.custom_action.install_app.status=Installing Web application
|
||||
web.env.checking=Проверка Веб-среды
|
||||
web.env.error=Проблемы с Веб-средой. Невозможно установить {}.
|
||||
web.environment.install=Устанавливается {}
|
||||
|
||||
@@ -4,6 +4,9 @@ web.custom_action.clean_env.failed=Kurulum ortamı temizliği sırasında bir ha
|
||||
web.custom_action.clean_env.status=Kurulum ortamını temizleme
|
||||
web.custom_action.clean_env.success=Kurulum ortamı temizlendi
|
||||
web.custom_action.clean_env=Temiz kurulum ortamı
|
||||
web.custom_action.install_app=Install Web application
|
||||
web.custom_action.install_app.invalid_url=The address {url} could not be found. It is not possible to finish the installation.
|
||||
web.custom_action.install_app.status=Installing Web application
|
||||
web.env.checking=Web kurulum ortamını kontrol et
|
||||
web.env.error=Görünüşe göre Web kurulum ortamıyla ilgili sorunlar var. {} kurmak mümkün olmayacak.
|
||||
web.environment.install={} yükleniyor
|
||||
|
||||
Reference in New Issue
Block a user