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 run(self, appdesc=None, appname=None): if not self._do_login(): raise SystemExit from stoq.gui.launcher import Launcher from stoqlib.gui.events import StartApplicationEvent from stoqlib.lib.message import error import gtk app_window = Launcher(self._options, self) app_window.show() app = app_window.app StartApplicationEvent.emit(app.name, app) # A GtkWindowGroup controls grabs (blocking mouse/keyboard interaction), # by default all windows are added to the same window group. # We want to avoid setting modallity on other windows # when running a dialog using gtk_dialog_run/run_dialog. window_group = gtk.WindowGroup() window_group.add_window(app_window.get_toplevel()) if appname is not None: appdesc = self.get_app_by_name(appname) if not appdesc: return if (appdesc.name != 'launcher' and not self._user.profile.check_app_permission(appdesc.name)): error(_("This user lacks credentials \nfor application %s") % appdesc.name) return self.run_embedded(appdesc, app_window)
def install_plugin(self, plugin_name): """Install and enable a plugin @important: Calling this makes a plugin installed, but, it's your responsability to activate it! :param plugin: the :class:`IPlugin` implementation of the plugin """ # Try to get the plugin first. If it was't registered yet, # PluginError will be raised. plugin = self.get_plugin(plugin_name) if plugin_name in self.installed_plugins_names: raise PluginError("Plugin %s is already enabled." % (plugin_name, )) store = new_store() InstalledPlugin(store=store, plugin_name=plugin_name, plugin_version=0) store.commit(close=True) migration = plugin.get_migration() if migration: try: migration.apply_all_patches() except SQLError: # This means a lock could not be obtained. Warn user about this # and let stoq restart, that the schema will be upgraded # correctly error('Não foi possível terminar a instalação do plugin. ' 'Por favor reinicie todas as instancias do Stoq que ' 'estiver executando')
def _check_database(self): try: log.info("Locking database") self.default_store.lock_database() except DatabaseError: msg = _( 'Could not lock database. This means there are other clients ' 'connected. Make sure to close every Stoq client ' 'before updating the database') error(msg) # Database migration is actually run in subprocesses, We need to unlock # the tables again and let the upgrade continue log.info("Releasing database lock") self.default_store.unlock_database() sucess = db_settings.test_connection() if not sucess: # FIXME: Improve this message after 1.5 is released msg = _(u'Could not connect to the database using command line ' 'tool! Aborting.') + ' ' msg += _(u'Please, check if you can connect to the database ' 'using:') + ' ' msg += _(u'psql -l -h <server> -p <port> -U <username>') error(msg) return return True
def set_current_branch_station(store, station_name): """Registers the current station and the branch of the station as the current branch for the system :param store: a store :param station_name: name of the station to register """ # This is called from stoq-daemon, which doesn't know about Branch yet from stoqlib.domain.person import Branch Branch # pylint: disable=W0104 if station_name is None: station_name = get_hostname() station_name = unicode(station_name) from stoqlib.domain.station import BranchStation station = store.find(BranchStation, name=station_name).one() if station is None: station = _register_branch(store, station_name) if not station.is_active: error(_("The computer <u>%s</u> is not active in Stoq") % station_name, _("To solve this, open the administrator application " "and re-activate this computer.")) provide_utility(ICurrentBranchStation, station, replace=True) # The station may still not be associated with a branch when creating an # empty database if station.branch: provide_utility(ICurrentBranch, station.branch, replace=True)
def _check_database(self): try: log.info("Locking database") self.default_store.lock_database() except DatabaseError: msg = _('Could not lock database. This means there are other clients ' 'connected. Make sure to close every Stoq client ' 'before updating the database') error(msg) # Database migration is actually run in subprocesses, We need to unlock # the tables again and let the upgrade continue log.info("Releasing database lock") self.default_store.unlock_database() sucess = db_settings.test_connection() if not sucess: # FIXME: Improve this message after 1.5 is released msg = _(u'Could not connect to the database using command line ' 'tool! Aborting.') + ' ' msg += _(u'Please, check if you can connect to the database ' 'using:') + ' ' msg += _(u'psql -l -h <server> -p <port> -U <username>') error(msg) return return True
def _maybe_create_database(self): logger.info( '_maybe_create_database (db_is_local=%s, enable_production=%s)' % (self.wizard.db_is_local, self.wizard.enable_production)) if self.wizard.db_is_local: self._launch_stoqdbadmin() return elif self.wizard.enable_production: self._launch_stoqdbadmin() return self.wizard.write_pgpass() settings = self.wizard.settings self.wizard.config.load_settings(settings) store = settings.create_super_store() version = get_database_version(store) if version < (9, 1): store.close() error( _("Stoq requires PostgresSQL 9.1 or later, but %s found") % (".".join(map(str, version)))) try: check_extensions(store=store) except ValueError: store.close() error( _("Missing PostgreSQL extension on the server, " "please install postgresql-contrib on it")) store.close() self.process_view.feed("** Creating database\r\n") self._launch_stoqdbadmin()
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 _maybe_create_database(self): logger.info('_maybe_create_database (db_is_local=%s, enable_production=%s)' % (self.wizard.db_is_local, self.wizard.enable_production)) if self.wizard.db_is_local: self._launch_stoqdbadmin() return elif self.wizard.enable_production: self._launch_stoqdbadmin() return self.wizard.write_pgpass() settings = self.wizard.settings self.wizard.config.load_settings(settings) store = settings.create_super_store() version = get_database_version(store) if version < (9, 1): store.close() error(_("Stoq requires PostgresSQL 9.1 or later, but %s found") % ( ".".join(map(str, version)))) try: check_extensions(store=store) except ValueError: store.close() error(_("Missing PostgreSQL extension on the server, " "please install postgresql-contrib on it")) store.close() self.process_view.feed("** Creating database\r\n") self._launch_stoqdbadmin()
def _try_connect(self): from stoqlib.lib.message import error try: store_dsn = self._config.get_settings().get_store_dsn() except: type, value, trace = sys.exc_info() error( _("Could not open the database config file"), _("Invalid config file settings, got error '%s', " "of type '%s'") % (value, type)) from stoqlib.database.exceptions import PostgreSQLError from stoq.lib.startup import setup # XXX: progress dialog for connecting (if it takes more than # 2 seconds) or creating the database log.debug('calling setup()') try: setup(self._config, self._options, register_station=False, check_schema=False, load_plugins=False) except (StoqlibError, PostgreSQLError) as e: error(_('Could not connect to the database'), 'error=%s uri=%s' % (str(e), store_dsn))
def create_database_functions(): """Create some functions we define on the database This will simply read data/sql/functions.sql and execute it """ with tempfile.NamedTemporaryFile(suffix='stoqfunctions-') as tmp_f: with open(environ.find_resource('sql', 'functions.sql')) as f: tmp_f.write(render_template_string(f.read())) tmp_f.flush() if db_settings.execute_sql(tmp_f.name) != 0: error(u'Failed to create functions')
def create_database_functions(): """Create some functions we define on the database This will simply read data/sql/functions.sql and execute it """ with tempfile.NamedTemporaryFile(suffix='stoqfunctions-') as tmp_f: functions = environ.get_resource_string('stoq', 'sql', 'functions.sql') tmp_f.write(render_template_string(functions)) tmp_f.flush() if db_settings.execute_sql(tmp_f.name) != 0: error(u'Failed to create functions')
def _do_login(self): from stoqlib.exceptions import LoginError from stoqlib.gui.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, e: error(str(e)) return False
def install_plugin(self, store, plugin_name): """Install and enable a plugin @important: Calling this makes a plugin installed, but, it's your responsability to activate it! :param plugin: the :class:`IPlugin` implementation of the plugin """ # Try to get the plugin first. If it was't registered yet, # PluginError will be raised. plugin = self.get_plugin(plugin_name) if plugin_name in self.installed_plugins_names: raise PluginError("Plugin %s is already enabled." % (plugin_name, )) dependencies = self._plugin_descriptions[plugin_name].dependencies for dependency in dependencies: if not self.is_installed(dependency): self.install_plugin(store, dependency) InstalledPlugin.create(store, plugin_name) # FIXME: We should not be doing this commit here, but by not doing so, # ``` # migration = plugin.get_migration() # ``` # Would not find any plugin (as it uses the default store), to allow # `plugin.get_migration()` to accept a custom store, we would have to # change all the plugins `get_migration` method. # # An alternate solution to this would be to manually set the correct # plugin for `migration`: # # migration._plugin = store.find(InstalledPlugin, # plugin_name=plugin_name).one() # # Along with passing the store to `migration.apply_all_patches()` # # But it will be dirty and will probably be removed once the definitive # solution (change `plugin.get_migration()`) is implemented store.commit(close=False) migration = plugin.get_migration() if migration: try: migration.apply_all_patches() except SQLError as e: # This means a lock could not be obtained. Warn user about this # and let stoq restart, that the schema will be upgraded # correctly error('Não foi possível terminar a instalação do plugin. ' 'Por favor reinicie todas as instancias do Stoq que ' 'estiver executando (%s)' % (e, ))
def needs_schema_update(): try: migration = StoqlibSchemaMigration() except StoqlibError: error(_("Update Error"), _("You need to call setup() before checking the database " "schema.")) try: update = not (migration.check_uptodate() and migration.check_plugins()) except DatabaseInconsistency, e: error(str(e))
def populate_initial_data(store): from stoqlib.domain.system import SystemTable generation = store.find(SystemTable).max(SystemTable.generation) if generation < 4: # FIXME: Initial data can (and needs to) only be sourced on schemas # greater or equal than 4. Remove this in the future. return log.info('Populating initial data') initial_data = pkg_resources.resource_filename('stoq', 'sql/initial.sql') if db_settings.execute_sql(initial_data) != 0: error(u'Failed to populate initial data')
def create_database_functions(): """Create some functions we define on the database This will simply read data/sql/functions.sql and execute it """ # We cant remove the file, otherwise it will fail on windows. with tempfile.NamedTemporaryFile(prefix='stoqfunctions-', delete=False) as tmp_f: functions = pkg_resources.resource_string('stoq', 'sql/functions.sql') tmp_f.write(render_template_string(functions)) tmp_f.flush() if db_settings.execute_sql(tmp_f.name) != 0: error(u'Failed to create functions')
def populate_initial_data(store): from stoqlib.domain.system import SystemTable generation = store.find(SystemTable).max(SystemTable.generation) if generation < 4: # FIXME: Initial data can (and needs to) only be sourced on schemas # greater or equal than 4. Remove this in the future. return log.info('Populating initial data') initial_data = environ.find_resource('sql', 'initial.sql') if db_settings.execute_sql(initial_data) != 0: error(u'Failed to populate initial data')
def create_database_functions(): """Create some functions we define on the database This will simply read data/sql/functions.sql and execute it """ # We cant remove the file, otherwise it will fail on windows. with tempfile.NamedTemporaryFile(prefix='stoqfunctions-', delete=False) as tmp_f: functions = environ.get_resource_string('stoq', 'sql', 'functions.sql') tmp_f.write(render_template_string(functions)) tmp_f.flush() if db_settings.execute_sql(tmp_f.name) != 0: error(u'Failed to create functions')
def apply(self, store): """Apply the patch :param store: a store """ # Dont lock the database here, since StoqlibSchemaMigration.update has # already did that before starting to apply the patches # SQL statement to update the system_table sql = self._migration.generate_sql_for_patch(self) if self.filename.endswith('.sql'): # Create a temporary file used for writing SQL statements temporary = tempfile.mktemp(prefix="patch-%d-%d-" % self.get_version()) # Overwrite the temporary file with the sql patch we want to apply shutil.copy(self.filename, temporary) # After successfully executing the SQL statements, we need to # make sure that the system_table is updated with the correct # schema generation and patchlevel open(temporary, 'a').write(sql) retcode = db_settings.execute_sql(temporary) if retcode != 0: error('Failed to apply %s, psql returned error code: %d' % (os.path.basename(self.filename), retcode)) os.unlink(temporary) elif self.filename.endswith('.py'): # Execute the patch, we cannot use __import__() since there are # hyphens in the filename and data/sql lacks an __init__.py ns = {} exec(compile(open(self.filename).read(), self.filename, 'exec'), ns, ns) function = ns['apply_patch'] # Create a new store that will be used to apply the patch and # to update the system tables after the patch has been successfully # applied patch_store = new_store() # Apply the patch itself function(patch_store) # After applying the patch, update the system_table within the same # transaction patch_store.execute(sql) patch_store.commit(close=True) else: raise AssertionError("Unknown filename: %s" % (self.filename, ))
def check(self, check_plugins=True): # always check if schema is up to date and optionally (depending on check_plugins flag) # check if plugins are up to date as well if self.check_uptodate() and (not check_plugins or self.check_plugins()): return True error( _("Database schema error"), _("The database schema has changed, but the database has " "not been updated. Run 'stoqdbadmin updateschema` to " "update the schema to the latest available version.")) return False
def create_base_schema(): log.info('Creating base schema') create_log.info("SCHEMA") create_database_functions() # A Base schema shared between all RDBMS implementations schema = _get_latest_schema() if db_settings.execute_sql(schema) != 0: error(u'Failed to create base schema') migration = StoqlibSchemaMigration() migration.apply_all_patches()
def load_config_and_call_setup(self): dbargs = self.settings.get_command_line_arguments() parser = get_option_parser() db_options, unused_args = parser.parse_args(dbargs) self.config.set_from_options(db_options) try: setup(self.config, options=self.options, check_schema=True, register_station=False, load_plugins=False) except DatabaseInconsistency as err: error(_('The database version differs from your installed ' 'version.'), str(err))
def _check_schema_migration(self): from stoqlib.lib.message import error from stoqlib.database.migration import needs_schema_update from stoqlib.exceptions import DatabaseInconsistency if needs_schema_update(): self._run_update_wizard() from stoqlib.database.migration import StoqlibSchemaMigration migration = StoqlibSchemaMigration() try: migration.check() except DatabaseInconsistency as e: error(_('The database version differs from your installed ' 'version.'), str(e))
def apply(self, store): """Apply the patch :param store: a store """ # Dont lock the database here, since StoqlibSchemaMigration.update has # already did that before starting to apply the patches # SQL statement to update the system_table sql = self._migration.generate_sql_for_patch(self) if self.filename.endswith('.sql'): # Create a temporary file used for writing SQL statements temporary = tempfile.mktemp(prefix="patch-%d-%d-" % self.get_version()) # Overwrite the temporary file with the sql patch we want to apply shutil.copy(self.filename, temporary) # After successfully executing the SQL statements, we need to # make sure that the system_table is updated with the correct # schema generation and patchlevel open(temporary, 'a').write(sql) retcode = db_settings.execute_sql(temporary) if retcode != 0: error('Failed to apply %s, psql returned error code: %d' % ( os.path.basename(self.filename), retcode)) os.unlink(temporary) elif self.filename.endswith('.py'): # Execute the patch, we cannot use __import__() since there are # hyphens in the filename and data/sql lacks an __init__.py ns = {} execfile(self.filename, ns, ns) function = ns['apply_patch'] # Create a new store that will be used to apply the patch and # to update the system tables after the patch has been successfully # applied patch_store = new_store() # Apply the patch itself function(patch_store) # After applying the patch, update the system_table within the same # transaction patch_store.execute(sql) patch_store.commit(close=True) else: raise AssertionError("Unknown filename: %s" % (self.filename, ))
def main(args): parser = get_option_parser() group = optparse.OptionGroup(parser, 'Daemon') group.add_option('', '--daemon-id', action="store", dest="daemon_id", help='Daemon Identifier') parser.add_option_group(group) options, args = parser.parse_args(args) if not options.daemon_id: raise SystemExit("Need a daemon id") from stoqlib.lib.message import error from stoqlib.lib.configparser import StoqConfig log.debug('reading configuration') config = StoqConfig() if options.filename: config.load(options.filename) else: config.load_default() settings = config.get_settings() try: store_dsn = settings.get_store_dsn() except: type, value, trace = sys.exc_info() error( _("Could not open the database config file"), _("Invalid config file settings, got error '%s', " "of type '%s'") % (value, type)) from stoqlib.exceptions import StoqlibError from stoqlib.database.exceptions import PostgreSQLError from stoq.lib.startup import setup log.debug('calling setup()') # XXX: progress dialog for connecting (if it takes more than # 2 seconds) or creating the database try: setup(config, options, register_station=True, check_schema=False) except (StoqlibError, PostgreSQLError) as e: error(_('Could not connect to the database'), 'error=%s dsn=%s' % (str(e), store_dsn)) raise SystemExit("Error: bad connection settings provided") daemon = Daemon(options.daemon_id) daemon.run()
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(self, check_plugins=True): if self.check_uptodate(): return True if not check_plugins: return True if self.check_plugins(): return True error(_("Database schema error"), _("The database schema has changed, but the database has " "not been updated. Run 'stoqdbadmin updateschema` to " "update the schema to the latest available version.")) return False
def main(args): parser = get_option_parser() group = optparse.OptionGroup(parser, 'Daemon') group.add_option('', '--daemon-id', action="store", dest="daemon_id", help='Daemon Identifier') parser.add_option_group(group) options, args = parser.parse_args(args) if not options.daemon_id: raise SystemExit("Need a daemon id") from stoqlib.lib.message import error from stoqlib.lib.configparser import StoqConfig log.debug('reading configuration') config = StoqConfig() if options.filename: config.load(options.filename) else: config.load_default() settings = config.get_settings() try: store_dsn = settings.get_store_dsn() except: type, value, trace = sys.exc_info() error(_("Could not open the database config file"), _("Invalid config file settings, got error '%s', " "of type '%s'") % (value, type)) from stoqlib.exceptions import StoqlibError from stoqlib.database.exceptions import PostgreSQLError from stoq.lib.startup import setup log.debug('calling setup()') # XXX: progress dialog for connecting (if it takes more than # 2 seconds) or creating the database try: setup(config, options, register_station=True, check_schema=False) except (StoqlibError, PostgreSQLError) as e: error(_('Could not connect to the database'), 'error=%s dsn=%s' % (str(e), store_dsn)) raise SystemExit("Error: bad connection settings provided") daemon = Daemon(options.daemon_id) daemon.run()
def __init__(self): if self.patch_resource is None: raise ValueError( _("%s needs to have the patch_resource class variable set") % ( self.__class__.__name__)) if self.patch_patterns is None: raise ValueError( _("%s needs to have the patch_patterns class variable set") % ( self.__class__.__name__)) self.default_store = get_default_store() try: check_extensions(store=self.default_store) except ValueError: error("Missing PostgreSQL extension on the server, " "please install postgresql-contrib")
def __init__(self): if self.patch_resource is None: raise ValueError( _("%s needs to have the patch_resource class variable set") % (self.__class__.__name__)) if self.patch_patterns is None: raise ValueError( _("%s needs to have the patch_patterns class variable set") % (self.__class__.__name__)) self.default_store = get_default_store() try: check_extensions(store=self.default_store) except ValueError: error("Missing PostgreSQL extension on the server, " "please install postgresql-contrib")
def _load_shell_app(self, app_name): user = api.get_current_user(self.store) # FIXME: Move over to domain if app_name != "launcher" and not user.profile.check_app_permission(app_name): error(_("This user lacks credentials \nfor application %s") % app_name) return None module = __import__("stoq.gui.%s" % (app_name,), globals(), locals(), [""]) attribute = app_name.capitalize() + "App" shell_app_class = getattr(module, attribute, None) if shell_app_class is None: raise SystemExit("%s app misses a %r attribute" % (app_name, attribute)) shell_app = shell_app_class(window=self, store=self.store) shell_app.app_name = app_name return shell_app
def _maybe_create_database(self): logger.info( '_maybe_create_database (db_is_local=%s, enable_production=%s)' % (self.wizard.db_is_local, self.wizard.enable_production)) if self.wizard.db_is_local: self._launch_stoqdbadmin() return elif self.wizard.enable_production: self._launch_stoqdbadmin() return self.wizard.write_pgpass() settings = self.wizard.settings self.wizard.config.load_settings(settings) store = settings.create_super_store() version = get_database_version(store) if version < (9, 1): store.close() error( _("Stoq requires PostgresSQL 9.1 or later, but %s found") % (".".join(map(str, version)))) try: check_extensions(store=store) except ValueError: store.close() error( _("Missing PostgreSQL extension on the server, " "please install postgresql-contrib on it")) store.close() # Secondly, ask the user if he really wants to create the database, dbname = settings.dbname if yesno( _(u"The specified database '%s' does not exist.\n" u"Do you want to create it?") % dbname, gtk.RESPONSE_YES, _(u"Create database"), _(u"Don't create")): self.process_view.feed("** Creating database\r\n") self._launch_stoqdbadmin() else: self.process_view.feed("** Not creating database\r\n") self.wizard.disable_next()
def needs_schema_update(): try: migration = StoqlibSchemaMigration() except StoqlibError: error(_("Update Error"), _("You need to call setup() before checking the database " "schema.")) try: update = not (migration.check_uptodate() and migration.check_plugins()) except DatabaseInconsistency as e: error(str(e)) # If we need to update the database, we need to close the connection, # otherwise the locking of the database will fail, since this connection has # already queried a few tables if update: migration.default_store.commit() return update
def _update_schema(self): """Check the current version of database and update the schema if it's needed """ log.info("Updating schema") if self.check_uptodate(): log.info("Schema is already up to date") return patches = self._get_patches() latest_available = patches[-1].get_version() current_version = self.get_current_version() last_level = None if current_version != latest_available: patches_to_apply = [] for patch in patches: if patch.get_version() <= current_version: continue patches_to_apply.append(patch) functions = environ.get_resource_filename('stoq', 'sql', 'functions.sql') if db_settings.execute_sql(functions) != 0: error('Failed to create functions') log.info("Applying %d patches" % (len(patches_to_apply), )) create_log.info("PATCHES:%d" % (len(patches_to_apply), )) for patch in patches_to_apply: create_log.info("PATCH:%d.%d" % (patch.generation, patch.level)) patch.apply(self.default_store) assert patches_to_apply log.info("All patches (%s) applied." % (', '.join(str(p.level) for p in patches_to_apply))) last_level = patches_to_apply[-1].get_version() self.after_update() return current_version, last_level
def _write_exception_hook(self, exctype, value, tb): # NOTE: This exception hook depends on gtk, kiwi, twisted being present # In the future we might want it to run without some of these # dependencies, so we can crash reports that happens really # really early on for users with weird environments. if not self.entered_main: self._setup_twisted(raise_=False) try: from psycopg2 import OperationalError if exctype == OperationalError: from stoqlib.lib.message import error from stoqlib.lib.translation import stoqlib_gettext as _ return error(_('There was an error quering the database'), str(value)) except ImportError: pass appname = 'unknown' try: from stoq.gui.shell.shell import get_shell shell = get_shell() if shell: appname = shell.get_current_app_name() except ImportError: pass window_name = 'unknown' try: from stoqlib.gui.base.dialogs import get_current_toplevel window = get_current_toplevel() if window: window_name = window.get_name() except ImportError: pass log.info('An error occurred in application "%s", toplevel window=%s' % (appname, window_name)) exc_lines = traceback.format_exception(exctype, value, tb) for line in ''.join(exc_lines).split('\n')[:-1]: log.error(line) from stoqlib.lib.crashreport import collect_traceback collect_traceback((exctype, value, tb)) if self.entered_main: return from stoqlib.gui.dialogs.crashreportdialog import show_dialog d = show_dialog() from twisted.internet import reactor d.addCallback(lambda *x: reactor.stop()) reactor.run() raise SystemExit
def _write_exception_hook(self, exctype, value, tb): # NOTE: This exception hook depends on gtk, kiwi, twisted being present # In the future we might want it to run without some of these # dependencies, so we can crash reports that happens really # really early on for users with weird environments. if not self.entered_main: self._setup_twisted(raise_=False) try: from psycopg2 import OperationalError if exctype == OperationalError: from stoqlib.lib.message import error from stoqlib.lib.translation import stoqlib_gettext as _ return error(_('There was an error quering the database'), str(value)) except ImportError: pass appname = 'unknown' try: from stoq.gui.shell.shell import get_shell shell = get_shell() if shell: appname = shell.get_current_app_name() except ImportError: pass window_name = 'unknown' try: from stoqlib.gui.base.dialogs import get_current_toplevel window = get_current_toplevel() if window: window_name = window.get_name() except ImportError: pass log.info('An error occurred in application "%s", toplevel window=%s' % ( appname, window_name)) exc_lines = traceback.format_exception(exctype, value, tb) for line in ''.join(exc_lines).split('\n')[:-1]: log.error(line) from stoqlib.lib.crashreport import collect_traceback collect_traceback((exctype, value, tb)) if self.entered_main: return from stoqlib.gui.dialogs.crashreportdialog import show_dialog d = show_dialog() from twisted.internet import reactor d.addCallback(lambda *x: reactor.stop()) reactor.run() raise SystemExit
def set_current_branch_station(store, station_name, confirm=True): """Registers the current station and the branch of the station as the current branch for the system :param store: a store :param station_name: name of the station to register """ # This is called from stoq-daemon, which doesn't know about Branch yet from stoqlib.lib.parameters import sysparam from stoqlib.domain.person import Branch Branch # pylint: disable=W0104 if station_name is None: station_name = get_hostname() station_name = str(station_name) from stoqlib.domain.station import BranchStation station = store.find(BranchStation, name=station_name).one() if station is None: station = _register_branch_station(store, station_name, confirm=confirm) if not station.is_active: error( _("The computer <u>%s</u> is not active in Stoq") % station_name, _("To solve this, open the administrator application " "and re-activate this computer.")) provide_utility(ICurrentBranchStation, station, replace=True) main_company = sysparam.get_object(store, 'MAIN_COMPANY') if not station.branch and main_company: with new_store() as commit_store: commit_station = commit_store.fetch(station) commit_station.branch = commit_store.fetch(main_company) # The station may still not be associated with a branch when creating an # empty database if station.branch: provide_utility(ICurrentBranch, station.branch, replace=True) return station
def _update_schema(self): """Check the current version of database and update the schema if it's needed """ log.info("Updating schema") if self.check_uptodate(): log.info("Schema is already up to date") return patches = self._get_patches() latest_available = patches[-1].get_version() current_version = self.get_current_version() last_level = None if current_version != latest_available: patches_to_apply = [] for patch in patches: if patch.get_version() <= current_version: continue patches_to_apply.append(patch) functions = environ.get_resource_filename('stoq', 'sql', 'functions.sql') if db_settings.execute_sql(functions) != 0: error('Failed to create functions') log.info("Applying %d patches" % (len(patches_to_apply), )) create_log.info("PATCHES:%d" % (len(patches_to_apply), )) for patch in patches_to_apply: create_log.info("PATCH:%d.%d" % (patch.generation, patch.level)) patch.apply(self.default_store) assert patches_to_apply log.info("All patches (%s) applied." % ( ', '.join(str(p.level) for p in patches_to_apply))) last_level = patches_to_apply[-1].get_version() self.after_update() return current_version, last_level
def create_base_schema(): log.info('Creating base schema') create_log.info("SCHEMA") create_database_functions() # A Base schema shared between all RDBMS implementations schema = _get_latest_schema() if db_settings.execute_sql(schema) != 0: error(u'Failed to create base schema') try: schema = environ.find_resource('sql', '%s-schema.sql' % db_settings.rdbms) if db_settings.execute_sql(schema) != 0: error(u'Failed to create %s specific schema' % (db_settings.rdbms, )) except EnvironmentError: pass migration = StoqlibSchemaMigration() migration.apply_all_patches()
def load_config_and_call_setup(self): dbargs = self.settings.get_command_line_arguments() parser = get_option_parser() db_options, unused_args = parser.parse_args(dbargs) self.config.set_from_options(db_options) if needs_schema_update(): retval = run_dialog(SchemaUpdateWizard, None) if not retval: raise SystemExit() try: setup(self.config, options=self.options, check_schema=True, register_station=False, load_plugins=False) except DatabaseInconsistency as err: error(_('The database version differs from your installed ' 'version.'), str(err))
def _maybe_create_database(self): logger.info('_maybe_create_database (db_is_local=%s, enable_production=%s)' % (self.wizard.db_is_local, self.wizard.enable_production)) if self.wizard.db_is_local: self._launch_stoqdbadmin() return elif self.wizard.enable_production: self._launch_stoqdbadmin() return self.wizard.write_pgpass() settings = self.wizard.settings self.wizard.config.load_settings(settings) store = settings.create_super_store() version = get_database_version(store) if version < (9, 1): store.close() error(_("Stoq requires PostgresSQL 9.1 or later, but %s found") % ( ".".join(map(str, version)))) try: check_extensions(store=store) except ValueError: store.close() error(_("Missing PostgreSQL extension on the server, " "please install postgresql-contrib on it")) store.close() # Secondly, ask the user if he really wants to create the database, dbname = settings.dbname if yesno(_(u"The specified database '%s' does not exist.\n" u"Do you want to create it?") % dbname, gtk.RESPONSE_YES, _(u"Create database"), _(u"Don't create")): self.process_view.feed("** Creating database\r\n") self._launch_stoqdbadmin() else: self.process_view.feed("** Not creating database\r\n") self.wizard.disable_next()
def _load_shell_app(self, app_name): user = api.get_current_user(self.store) # FIXME: Move over to domain if (app_name != 'launcher' and not user.profile.check_app_permission(app_name)): error( _("This user lacks credentials \nfor application %s") % app_name) return None module = __import__("stoq.gui.%s" % (app_name, ), globals(), locals(), ['']) attribute = app_name.capitalize() + 'App' shell_app_class = getattr(module, attribute, None) if shell_app_class is None: raise SystemExit("%s app misses a %r attribute" % (app_name, attribute)) shell_app = shell_app_class(window=self, store=self.store) shell_app.app_name = app_name return shell_app
def _register_branch(caller_store, station_name): import gtk from stoqlib.lib.parameters import sysparam if not sysparam(caller_store).DEMO_MODE: if not yesno( _(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) ?") % (station_name, db_settings.address), gtk.RESPONSE_YES, _(u"Register computer"), _(u"Quit")): raise SystemExit from stoqlib.gui.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 set_current_branch_station(store, station_name): """Registers the current station and the branch of the station as the current branch for the system :param store: a store :param station_name: name of the station to register """ # This might be called early, so make sure SQLObject # knows about Branch which might not have # been imported yet from stoqlib.domain.person import Branch Branch # pylint: disable=W0104 if station_name is None: # For LTSP systems we cannot use the hostname as stoq is run # on a shared serve system. Instead the ip of the client system # is available in the LTSP_CLIENT environment variable station_name = os.environ.get("LTSP_CLIENT_HOSTNAME", None) if station_name is None: station_name = get_hostname() station_name = unicode(station_name) from stoqlib.domain.station import BranchStation station = store.find(BranchStation, name=station_name).one() if station is None: station = _register_branch(store, station_name) if not station.is_active: error( _("The computer <u>%s</u> is not active in Stoq") % station_name, _("To solve this, open the administrator application " "and re-activate this computer."), ) provide_utility(ICurrentBranchStation, station, replace=True) if station.branch: provide_utility(ICurrentBranch, station.branch, replace=True)
def _register_branch(caller_store, station_name): import gtk from stoqlib.lib.parameters import sysparam if not sysparam(caller_store).DEMO_MODE: if yesno(_("The computer '%s' is not registered to the Stoq " "server at %s.\n\n" "Do you want to register it " "(requires administrator access) ?") % (station_name, db_settings.address), gtk.RESPONSE_NO, _("Quit"), _("Register computer")): raise SystemExit from stoqlib.gui.login import LoginHelper h = LoginHelper(username="******") try: user = h.validate_user() except LoginError, e: error(str(e)) if not user: error(_("Must login as 'admin'"))
def _try_connect(self): from stoqlib.lib.message import error try: store_dsn = self._config.get_settings().get_store_dsn() except: type, value, trace = sys.exc_info() error(_("Could not open the database config file"), _("Invalid config file settings, got error '%s', " "of type '%s'") % (value, type)) from stoqlib.database.exceptions import PostgreSQLError from stoq.lib.startup import setup # XXX: progress dialog for connecting (if it takes more than # 2 seconds) or creating the database log.debug('calling setup()') try: setup(self._config, self._options, register_station=False, check_schema=False, load_plugins=False) except (StoqlibError, PostgreSQLError) as e: error(_('Could not connect to the database'), 'error=%s uri=%s' % (str(e), store_dsn))
def set_current_branch_station(store, station_name): """Registers the current station and the branch of the station as the current branch for the system :param store: a store :param station_name: name of the station to register """ # This might be called early, so make sure SQLObject # knows about Branch which might not have # been imported yet from stoqlib.domain.person import Branch Branch # pyflakes if station_name is None: # For LTSP systems we cannot use the hostname as stoq is run # on a shared serve system. Instead the ip of the client system # is available in the LTSP_CLIENT environment variable station_name = os.environ.get('LTSP_CLIENT_HOSTNAME', None) if station_name is None: station_name = get_hostname() station_name = unicode(station_name) from stoqlib.domain.station import BranchStation station = store.find(BranchStation, name=station_name).one() if station is None: station = _register_branch(store, station_name) if not station.is_active: error( _("The computer <u>%s</u> is not active in Stoq") % station_name, _("To solve this, open the administrator application " "and re-activate this computer.")) provide_utility(ICurrentBranchStation, station, replace=True) if station.branch: provide_utility(ICurrentBranch, station.branch, replace=True)
def _write_exception_hook(self, exctype, value, tb): try: from psycopg2 import OperationalError if exctype == OperationalError: from stoqlib.lib.message import error from stoqlib.lib.translation import stoqlib_gettext as _ return error(_('There was an error quering the database'), str(value)) except ImportError: pass appname = 'unknown' try: from stoq.gui.shell.shell import get_shell shell = get_shell() if shell: appname = shell.get_current_app_name() except ImportError: pass window_name = 'unknown' try: from stoqlib.gui.base.dialogs import get_current_toplevel window = get_current_toplevel() if window: window_name = window.get_name() except ImportError: pass log.info('An error occurred in application "%s", toplevel window=%s' % (appname, window_name)) exc_lines = traceback.format_exception(exctype, value, tb) for line in ''.join(exc_lines).split('\n')[:-1]: log.error(line) from stoqlib.lib.crashreport import collect_traceback collect_traceback((exctype, value, tb)) if self.entered_main: return from gi.repository import Gtk from stoqlib.gui.dialogs.crashreportdialog import show_dialog show_dialog(callback=Gtk.main_quit) Gtk.main() raise SystemExit
def _try_connect(self): from stoqlib.lib.message import error try: store_uri = self._config.get_settings().get_store_uri() except: type, value, trace = sys.exc_info() error( _("Could not open the database config file"), _("Invalid config file settings, got error '%s', " "of type '%s'") % (value, type)) from stoqlib.database.exceptions import PostgreSQLError from stoqlib.database.runtime import get_default_store from stoqlib.exceptions import DatabaseError from stoqlib.lib.pgpass import write_pg_pass from stoq.lib.startup import setup # XXX: progress dialog for connecting (if it takes more than # 2 seconds) or creating the database log.debug('calling setup()') try: setup(self._config, self._options, register_station=False, check_schema=False, load_plugins=False) # the setup call above is not really trying to connect (since # register_station, check_schema and load_plugins are all False). # Try to really connect here. get_default_store() except (StoqlibError, PostgreSQLError) as e: log.debug('Connection failed.') error(_('Could not connect to the database'), 'error=%s uri=%s' % (str(e), store_uri)) except DatabaseError: log.debug('Connection failed. Tring to setup .pgpass') # This is probably a missing password configuration. Setup the # pgpass file and try again. try: password = self._get_password() if not password: # There is no password stored in data file. Abort raise from stoqlib.database.settings import db_settings write_pg_pass(db_settings.dbname, db_settings.address, db_settings.port, db_settings.username, password) # Now that there is a pg_pass file, try to connect again get_default_store() except DatabaseError as e: log.debug('Connection failed again.') error(_('Could not connect to the database'), 'error=%s uri=%s' % (str(e), store_uri))