def _register_branch_station(caller_store, station_name): import gtk from stoqlib.lib.parameters import sysparam if not sysparam.get_bool('DEMO_MODE'): fmt = _(u"The computer '%s' is not registered to the Stoq " u"server at %s.\n\n" u"Do you want to register it " u"(requires administrator access) ?") if not yesno(fmt % (station_name, db_settings.address), gtk.RESPONSE_YES, _(u"Register computer"), _(u"Quit")): raise SystemExit from stoqlib.gui.utils.login import LoginHelper h = LoginHelper(username="******") try: user = h.validate_user() except LoginError as e: error(str(e)) if not user: error(_("Must login as 'admin'")) from stoqlib.domain.station import BranchStation with new_store() as store: branch = sysparam.get_object(store, 'MAIN_COMPANY') station = BranchStation.create(store, branch=branch, name=station_name) return caller_store.fetch(station)
def _register_branch_station(caller_store, station_name, confirm=True): from gi.repository import Gtk from stoqlib.lib.parameters import sysparam if not sysparam.get_bool('DEMO_MODE'): fmt = _(u"The computer '%s' is not registered to the Stoq " u"server at %s.\n\n" u"Do you want to register it " u"(requires administrator access) ?") if confirm and not yesno(fmt % (station_name, db_settings.address), Gtk.ResponseType.YES, _(u"Register computer"), _(u"Quit")): raise SystemExit from stoqlib.gui.utils.login import LoginHelper h = LoginHelper() try: user = h.validate_user() except LoginError as e: error(str(e)) if not user: error(_("Must login as 'admin'")) from stoqlib.domain.station import BranchStation with new_store() as store: branch = sysparam.get_object(store, 'MAIN_COMPANY') station = BranchStation.create(store, branch=branch, name=station_name) return caller_store.fetch(station)
def _register_branch(caller_store, station_name): import gtk from stoqlib.lib.parameters import sysparam if not sysparam(caller_store).DEMO_MODE: fmt = _(u"The computer '%s' is not registered to the Stoq " u"server at %s.\n\n" u"Do you want to register it " u"(requires administrator access) ?") if not yesno(fmt % (station_name, db_settings.address), gtk.RESPONSE_YES, _(u"Register computer"), _(u"Quit")): raise SystemExit from stoqlib.gui.utils.login import LoginHelper h = LoginHelper(username="******") try: user = h.validate_user() except LoginError as e: error(str(e)) if not user: error(_("Must login as 'admin'")) from stoqlib.domain.person import Branch from stoqlib.domain.station import BranchStation branches = caller_store.find(Branch) if branches.is_empty(): error(_("Schema error, no branches found")) # TODO # Always select the first branch as the main branch, until we # support multiple branches properly. And then, provide a way to the # user choose which one will be the main branch. branch = branches[0] store = new_store() try: station = BranchStation.create(store, branch=store.fetch(branch), name=station_name) except StoqlibError as e: error(_("ERROR: %s") % e) station_id = station.id store.commit(close=True) return caller_store.find(BranchStation, id=station_id).one()
def _do_login(self): from stoqlib.exceptions import LoginError from stoqlib.gui.utils.login import LoginHelper from stoqlib.lib.message import error self._login = LoginHelper(username=self._options.login_username) try: if not self.login(): return False except LoginError as e: error(str(e)) return False self._check_param_online_services() self._maybe_show_welcome_dialog() return True
class Shell(object): """The main application shell - bootstraps via ShellBootstrap - connects to the database via ShellDatabaseConnection - handles login - runs applications """ def __init__(self, bootstrap, options, initial=True): global _shell _shell = self self._appname = None self._bootstrap = bootstrap self._dbconn = ShellDatabaseConnection(options=options) self._blocked_apps = [] self._hidden_apps = [] self._login = None self._options = options self._user = None app = Gtk.Application.get_default() if not app: app = Gtk.Application() Gtk.Application.set_default(app) self._app = app self._app.connect('activate', self._on_app__activate) self.windows = [] # # Private # def _do_login(self): from stoqlib.exceptions import LoginError from stoqlib.gui.utils.login import LoginHelper from stoqlib.lib.message import error self._login = LoginHelper(username=self._options.login_username) try: if not self.login(): return False except LoginError as e: error(str(e)) return False self._check_param_online_services() self._maybe_show_welcome_dialog() return True def _check_param_online_services(self): from stoqlib.database.runtime import new_store from stoqlib.lib.parameters import sysparam from gi.repository import Gtk if sysparam.get_bool('ONLINE_SERVICES') is None: from kiwi.ui.dialogs import HIGAlertDialog # FIXME: All of this is to avoid having to set markup as the default # in kiwi/ui/dialogs:HIGAlertDialog.set_details, after 1.0 # this can be simplified when we fix so that all descriptions # sent to these dialogs are properly escaped dialog = HIGAlertDialog( parent=None, flags=Gtk.DialogFlags.MODAL, type=Gtk.MessageType.WARNING) dialog.add_button(_("Not right now"), Gtk.ResponseType.NO) dialog.add_button(_("Enable online services"), Gtk.ResponseType.YES) dialog.set_primary(_('Do you want to enable Stoq online services?')) dialog.set_details(PRIVACY_STRING, use_markup=True) dialog.set_default_response(Gtk.ResponseType.YES) response = dialog.run() dialog.destroy() store = new_store() sysparam.set_bool(store, 'ONLINE_SERVICES', response == Gtk.ResponseType.YES) store.commit() store.close() def _maybe_show_welcome_dialog(self): from stoqlib.api import api if not api.user_settings.get('show-welcome-dialog', True): return api.user_settings.set('show-welcome-dialog', False) from stoq.gui.welcomedialog import WelcomeDialog from stoqlib.gui.base.dialogs import run_dialog run_dialog(WelcomeDialog) def _maybe_correct_demo_position(self, shell_window): # Possibly correct window position (livecd workaround for small # screens) from stoqlib.lib.parameters import sysparam from stoqlib.lib.pluginmanager import get_plugin_manager manager = get_plugin_manager() if (sysparam.get_bool('DEMO_MODE') and manager.is_active(u'ecf')): pos = shell_window.toplevel.get_position() if pos[0] < 220: shell_window.toplevel.move(220, pos[1]) def _maybe_schedule_idle_logout(self): # Verify if the user will use automatic logout. from stoqlib.lib.parameters import sysparam minutes = sysparam.get_int('AUTOMATIC_LOGOUT') # If user defined 0 minutes, ignore automatic logout. if minutes != 0: seconds = minutes * 60 GLib.timeout_add_seconds(5, self._verify_idle_logout, seconds) def _verify_idle_logout(self, seconds): # This is called once every 10 seconds from stoqlib.gui.utils.idle import get_idle_seconds if get_idle_seconds() > seconds: return self._idle_logout() # Call us again in 10 seconds return True def _idle_logout(self): # Before performing logout, verify that the currently opened window # is modal. from kiwi.component import get_utility from stoqlib.gui.base.dialogs import has_modal_window from stoqlib.lib.interfaces import ICookieFile # If not a modal window, logout. # Otherwise returns True to continue checking the automatic logout. if not has_modal_window(): log.debug('Automatic logout') get_utility(ICookieFile).clear() self.quit(restart=True) return True def _logout(self): from stoqlib.database.runtime import (get_current_user, get_default_store) log.debug('Logging out the current user') try: user = get_current_user(get_default_store()) if user: user.logout() except StoqlibError: pass def _terminate(self, restart=False, app=None): log.info("Terminating Stoq") # This removes all temporary files created when calling # get_resource_filename() that extract files to the file system import pkg_resources pkg_resources.cleanup_resources() log.debug('Stopping deamon') from stoqlib.lib.daemonutils import stop_daemon stop_daemon() # Finally, go out of the reactor and show possible crash reports log.debug("Show some crash reports") self._show_crash_reports() # Make sure that no connection is left open (specially on Windows) try: from stoqlib.database.runtime import get_default_store get_default_store().close() except Exception: pass if restart: from stoqlib.lib.process import Process log.info('Restarting Stoq') args = [sys.argv[0], '--no-splash-screen'] if app is not None: args.append(app) Process(args) # os._exit() forces a quit without running atexit handlers # and does not block on any running threads # FIXME: This is the wrong solution, we should figure out why there # are any running threads/processes at this point log.debug("Terminating by calling os._exit()") os._exit(0) raise AssertionError("Should never happen") def _show_crash_reports(self): from stoqlib.lib.crashreport import has_tracebacks if not has_tracebacks(): return if 'STOQ_DISABLE_CRASHREPORT' in os.environ: return from gi.repository import Gtk from stoqlib.gui.dialogs.crashreportdialog import show_dialog show_dialog(Gtk.main_quit) Gtk.main() # # Public API # def login(self): """ Do a login @param try_cookie: Try to use a cookie if one is available @returns: True if login succeed, otherwise false """ from stoqlib.exceptions import LoginError from stoqlib.lib.message import info user = self._login.cookie_login() if not user: try: user = self._login.validate_user() except LoginError as e: info(str(e)) if user: self._user = user return bool(user) def get_current_app_name(self): """ Get the name of the currently running application @returns: the name @rtype: str """ if not self.windows: return '' app = self.windows[0].current_app if not app: return '' return app.app_name def create_window(self): """ Creates a new shell window. Note that it will not contain any applications and it will be hidden. :returns: the shell_window """ from stoq.gui.shell.shellwindow import ShellWindow from stoqlib.database.runtime import get_default_store shell_window = ShellWindow(self._options, shell=self, store=get_default_store(), app=self._app) self._app.add_window(shell_window.toplevel) self.windows.append(shell_window) self._maybe_correct_demo_position(shell_window) return shell_window def close_window(self, shell_window): """ Close a currently open window :param ShellWindow shell_window: the shell_window """ shell_window.close() self.windows.remove(shell_window) def main(self, appname, action_name=None): """ Start the shell. This will: - connect to the database - login the current user - create a new window - run the launcher/application selector app - run a mainloop This will only exit when the complete stoq application is shutdown. :param appname: name of the application to run :param action_name: action to activate or ``None`` """ self._appname = appname self._action_name = action_name self._bootstrap.entered_main = True log.debug("Entering main loop") self._app.run() log.info("Leaving main loop") def quit(self, restart=False, app=None): """ Quit the shell and exit the application. This will save user settings and then forcefully terminate the application :param restart: if ``True`` restart after terminating :param str app: if not ``None``, name of the application to restart """ from stoqlib.api import api self._logout() # Write user settings to disk, this obviously only happens when # termination the complete stoq application log.debug("Flushing user settings") api.user_settings.flush() self._terminate(restart=restart, app=app) # # Callbacks # def _on_app__activate(self, app): appname = self._appname action_name = self._action_name self._dbconn.connect() if not self._do_login(): raise SystemExit if appname is None: appname = u'launcher' shell_window = self.create_window() app = shell_window.run_application(str(appname)) shell_window.show() if action_name is not None: action = getattr(app, action_name, None) if action is not None: action.activate() self._maybe_schedule_idle_logout()
class Shell(object): """The main application shell - bootstraps via ShellBootstrap - connects to the database via ShellDatabaseConnection - handles login - runs applications """ def __init__(self, bootstrap, options, initial=True): global _shell _shell = self self._appname = None self._bootstrap = bootstrap self._dbconn = ShellDatabaseConnection(options=options) self._blocked_apps = [] self._hidden_apps = [] self._login = None self._options = options self._user = None self.windows = [] # # Private # def _do_login(self): from stoqlib.exceptions import LoginError from stoqlib.gui.utils.login import LoginHelper from stoqlib.lib.message import error self._login = LoginHelper(username=self._options.login_username) try: if not self.login(): return False except LoginError as e: error(str(e)) return False self._check_param_online_services() self._maybe_show_welcome_dialog() return True def _check_param_online_services(self): from stoqlib.database.runtime import get_default_store, new_store from stoqlib.lib.parameters import sysparam import gtk sparam = sysparam(get_default_store()) if sparam.ONLINE_SERVICES is None: from kiwi.ui.dialogs import HIGAlertDialog # FIXME: All of this is to avoid having to set markup as the default # in kiwi/ui/dialogs:HIGAlertDialog.set_details, after 1.0 # this can be simplified when we fix so that all descriptions # sent to these dialogs are properly escaped dialog = HIGAlertDialog( parent=None, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_WARNING) dialog.add_button(_("Not right now"), gtk.RESPONSE_NO) dialog.add_button(_("Enable online services"), gtk.RESPONSE_YES) dialog.set_primary(_('Do you want to enable Stoq online services?')) dialog.set_details(PRIVACY_STRING, use_markup=True) dialog.set_default_response(gtk.RESPONSE_YES) response = dialog.run() dialog.destroy() store = new_store() sysparam(store).ONLINE_SERVICES = int(bool(response == gtk.RESPONSE_YES)) store.commit() store.close() def _maybe_show_welcome_dialog(self): from stoqlib.api import api if not api.user_settings.get('show-welcome-dialog', True): return api.user_settings.set('show-welcome-dialog', False) from stoq.gui.welcomedialog import WelcomeDialog from stoqlib.gui.base.dialogs import run_dialog run_dialog(WelcomeDialog) def _maybe_correct_demo_position(self, shell_window): # Possibly correct window position (livecd workaround for small # screens) from stoqlib.database.runtime import get_default_store from stoqlib.lib.parameters import sysparam from stoqlib.lib.pluginmanager import get_plugin_manager manager = get_plugin_manager() if (sysparam(get_default_store()).DEMO_MODE and manager.is_active(u'ecf')): pos = shell_window.toplevel.get_position() if pos[0] < 220: shell_window.toplevel.move(220, pos[1]) def _logout(self): from stoqlib.database.runtime import (get_current_user, get_default_store) log.debug('Logging out the current user') try: user = get_current_user(get_default_store()) if user: user.logout() except StoqlibError: pass @inlineCallbacks def _terminate(self, restart=False, app=None): log.info("Terminating Stoq") # This removes all temporary files created when calling # get_resource_filename() that extract files to the file system import pkg_resources pkg_resources.cleanup_resources() log.debug('Stopping deamon') from stoqlib.lib.daemonutils import stop_daemon stop_daemon() # Finally, go out of the reactor and show possible crash reports yield self._quit_reactor_and_maybe_show_crashreports() if restart: from stoqlib.lib.process import Process log.info('Restarting Stoq') args = [sys.argv[0], '--no-splash-screen'] if app is not None: args.append(app) Process(args) # os._exit() forces a quit without running atexit handlers # and does not block on any running threads # FIXME: This is the wrong solution, we should figure out why there # are any running threads/processes at this point log.debug("Terminating by calling os._exit()") os._exit(0) raise AssertionError("Should never happen") def _show_crash_reports(self): from stoqlib.lib.crashreport import has_tracebacks if not has_tracebacks(): return succeed(None) if 'STOQ_DISABLE_CRASHREPORT' in os.environ: return succeed(None) from stoqlib.gui.dialogs.crashreportdialog import show_dialog return show_dialog() @inlineCallbacks def _quit_reactor_and_maybe_show_crashreports(self): log.debug("Show some crash reports") yield self._show_crash_reports() log.debug("Shutdown reactor") from twisted.internet import reactor reactor.stop() # # Public API # def login(self): """ Do a login @param try_cookie: Try to use a cookie if one is available @returns: True if login succeed, otherwise false """ from stoqlib.exceptions import LoginError from stoqlib.lib.message import info user = self._login.cookie_login() if not user: try: user = self._login.validate_user() except LoginError as e: info(str(e)) if user: self._user = user return bool(user) def get_current_app_name(self): """ Get the name of the currently running application @returns: the name @rtype: str """ if not self.windows: return '' return self.windows[0].current_app.app_name def create_window(self): """ Creates a new shell window. Note that it will not contain any applications and it will be hidden. :returns: the shell_window """ from stoq.gui.shell.shellwindow import ShellWindow from stoqlib.database.runtime import get_default_store shell_window = ShellWindow(self._options, shell=self, store=get_default_store()) self.windows.append(shell_window) self._maybe_correct_demo_position(shell_window) return shell_window def close_window(self, shell_window): """ Close a currently open window :param ShellWindow shell_window: the shell_window """ shell_window.close() self.windows.remove(shell_window) def main(self, appname): """ Start the shell. This will: - connect to the database - login the current user - create a new window - run the launcher/application selector app - run a mainloop This will only exit when the complete stoq application is shutdown. :param appname: name of the application to run """ self._dbconn.connect() if not self._do_login(): raise SystemExit if appname is None: appname = u'launcher' shell_window = self.create_window() shell_window.run_application(unicode(appname)) shell_window.show() log.debug("Entering reactor") self._bootstrap.entered_main = True from twisted.internet import reactor reactor.run() log.info("Leaving reactor") def quit(self, restart=False, app=None): """ Quit the shell and exit the application. This will save user settings and then forcefully terminate the application :param restart: if ``True`` restart after terminating :param str app: if not ``None``, name of the application to restart """ from stoqlib.api import api self._logout() # Write user settings to disk, this obviously only happens when # termination the complete stoq application log.debug("Flushing user settings") api.user_settings.flush() self._terminate(restart=restart, app=app)