Mercurial > libervia-backend
view libervia/frontends/quick_frontend/quick_profile_manager.py @ 4326:5fd6a4dc2122
cli (output/std): use `rich` to output JSON.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 20 Nov 2024 11:38:44 +0100 |
parents | 0d7bb4df2343 |
children |
line wrap: on
line source
#!/usr/bin/env python3 # helper class for making a SAT frontend # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from libervia.backend.core.i18n import _ from libervia.backend.core import log as logging log = logging.getLogger(__name__) from libervia.tui.constants import Const as C class ProfileRecord(object): """Class which manage data for one profile""" def __init__(self, profile=None, login=None, password=None): self._profile = profile self._login = login self._password = password @property def profile(self): return self._profile @profile.setter def profile(self, value): self._profile = value # if we change the profile, # we must have no login/password until backend give them self._login = self._password = None @property def login(self): return self._login @login.setter def login(self, value): self._login = value @property def password(self): return self._password @password.setter def password(self, value): self._password = value class QuickProfileManager(object): """Class with manage profiles creation/deletion/connection""" def __init__(self, host, autoconnect=None): """Create the manager @param host: %(doc_host)s @param autoconnect(iterable): list of profiles to connect automatically """ self.host = host self._autoconnect = bool(autoconnect) self.current = ProfileRecord() def go(self, autoconnect): if self._autoconnect: self.autoconnect(autoconnect) def autoconnect(self, profile_keys): """Automatically connect profiles @param profile_keys(iterable): list of profile keys to connect """ if not profile_keys: log.warning("No profile given to autoconnect") return self._autoconnect = True self._autoconnect_profiles = [] self._do_autoconnect(profile_keys) def _do_autoconnect(self, profile_keys): """Connect automatically given profiles @param profile_kes(iterable): profiles to connect """ assert self._autoconnect def authenticate_cb(data, cb_id, profile): if C.bool(data.pop("validated", C.BOOL_FALSE)): self._autoconnect_profiles.append(profile) if len(self._autoconnect_profiles) == len(profile_keys): # all the profiles have been validated self.host.plug_profiles(self._autoconnect_profiles) else: # a profile is not validated, we go to manual mode self._autoconnect = False self.host.action_manager(data, callback=authenticate_cb, profile=profile) def get_profile_name_cb(profile): if not profile: # FIXME: this method is not handling manual mode correclty anymore # must be thought to be handled asynchronously self._autoconnect = False # manual mode msg = _("Trying to plug an unknown profile key ({})".format(profile_key)) log.warning(msg) self.host.show_dialog(_("Profile plugging in error"), msg, "error") else: self.host.action_launch( C.AUTHENTICATE_PROFILE_ID, callback=authenticate_cb, profile=profile ) def get_profile_name_eb(failure): log.error("Can't retrieve profile name: {}".format(failure)) for profile_key in profile_keys: self.host.bridge.profile_name_get( profile_key, callback=get_profile_name_cb, errback=get_profile_name_eb ) def get_param_error(self, __): self.host.show_dialog(_("Error"), _("Can't get profile parameter"), "error") ## Helping methods ## def _get_error_message(self, reason): """Return an error message corresponding to profile creation error @param reason (str): reason as returned by profile_create @return (unicode): human readable error message """ if reason == "ConflictError": message = _("A profile with this name already exists") elif reason == "CancelError": message = _("Profile creation cancelled by backend") elif reason == "ValueError": message = _( "You profile name is not valid" ) # TODO: print a more informative message (empty name, name starting with '@') else: message = _("Can't create profile ({})").format(reason) return message def _delete_profile(self): """Delete the currently selected profile""" if self.current.profile: self.host.bridge.profile_delete_async( self.current.profile, callback=self.refill_profiles ) self.reset_fields() ## workflow methods (events occuring during the profiles selection) ## # These methods must be called by the frontend at some point def _on_connect_profiles(self): """Connect the profiles and start the main widget""" if self._autoconnect: self.host.show_dialog( _("Internal error"), _("You can't connect manually and automatically at the same time"), "error", ) return self.update_connection_params() profiles = self.get_profiles() if not profiles: self.host.show_dialog( _("No profile selected"), _("You need to create and select at least one profile before connecting"), "error", ) else: # All profiles in the list are already validated, so we can plug them directly self.host.plug_profiles(profiles) def get_connection_params(self, profile): """Get login and password and display them @param profile: %(doc_profile)s """ self.host.bridge.param_get_a_async( "JabberID", "Connection", profile_key=profile, callback=self.set_jid, errback=self.get_param_error, ) self.host.bridge.param_get_a_async( "Password", "Connection", profile_key=profile, callback=self.set_password, errback=self.get_param_error, ) def update_connection_params(self): """Check if connection parameters have changed, and update them if so""" if self.current.profile: login = self.get_jid() password = self.getPassword() if login != self.current.login and self.current.login is not None: self.current.login = login self.host.bridge.param_set( "JabberID", login, "Connection", profile_key=self.current.profile ) log.info("login updated for profile [{}]".format(self.current.profile)) if password != self.current.password and self.current.password is not None: self.current.password = password self.host.bridge.param_set( "Password", password, "Connection", profile_key=self.current.profile ) log.info("password updated for profile [{}]".format(self.current.profile)) ## graphic updates (should probably be overriden in frontends) ## def reset_fields(self): """Set profile to None, and reset fields""" self.current.profile = None self.set_jid("") self.set_password("") def refill_profiles(self): """Rebuild the list of profiles""" profiles = self.host.bridge.profiles_list_get() profiles.sort() self.set_profiles(profiles) ## Method which must be implemented by frontends ## # get/set data def get_profiles(self): """Return list of selected profiles Must be implemented by frontends @return (list): list of profiles """ raise NotImplementedError def set_profiles(self, profiles): """Update the list of profiles""" raise NotImplementedError def get_jid(self): """Get current jid Must be implemented by frontends @return (unicode): current jabber id """ raise NotImplementedError def getPassword(self): """Get current password Must be implemented by frontends @return (unicode): current password """ raise NotImplementedError def set_jid(self, jid_): """Set current jid Must be implemented by frontends @param jid_(unicode): jabber id to set """ raise NotImplementedError def set_password(self, password): """Set current password Must be implemented by frontends """ raise NotImplementedError # dialogs # Note: a method which check profiles change must be implemented too