def collect_traceback(tb, output=True, submit=False): """Collects traceback which might be submitted @output: if it is to be printed @submit: if it is to be submitted immediately """ _tracebacks.append(tb) if output: traceback.print_exception(*tb) if has_raven and not is_developer_mode(): # pragma no cover extra = collect_report() extra.pop("tracebacks") sentry_url = os.environ.get( "STOQ_SENTRY_URL", ("https://*****:*****@sentry.stoq.com.br/4"), ) client = raven.Client(sentry_url, release=stoq.version) # Don't sent logs to sentry if "log" in extra: del extra["log"] if "log_name" in extra: del extra["log_name"] tags = {} for name in [ "architecture", "cnpj", "system", "app_name", "bdist_type", "app_version", "distribution", "python_version", "psycopg_version", "pygtk_version", "gtk_version", "kiwi_version", "reportlab_version", "stoqdrivers_version", "postgresql_version", ]: value = extra.pop(name, None) if value is None: continue tags[name] = value client.captureException(tb, tags=tags, extra=extra) if is_developer_mode() and submit: rs = ReportSubmitter() r = rs.submit() r.get_response()
def collect_traceback(tb, output=True, submit=False): """Collects traceback which might be submitted @output: if it is to be printed @submit: if it is to be submitted immediately """ _tracebacks.append(tb) if output: traceback.print_exception(*tb) if has_raven and not is_developer_mode(): # pragma no cover extra = collect_report() extra.pop('tracebacks') sentry_url = os.environ.get( 'STOQ_SENTRY_URL', ('http://*****:*****@sentry.stoq.com.br/4')) sentry_args = {} if 'app_version' in sentry_args: sentry_args['release'] = sentry_args['app_version'] client = raven.Client(sentry_url, **sentry_args) # Don't sent logs to sentry if 'log' in extra: del extra['log'] if 'log_name' in extra: del extra['log_name'] tags = {} for name in ['architecture', 'cnpj', 'system', 'app_name', 'bdist_type', 'app_version', 'distribution', 'python_version', 'psycopg_version', 'pygtk_version', 'gtk_version', 'kiwi_version', 'reportlab_version', 'stoqdrivers_version', 'postgresql_version']: value = extra.pop(name, None) if value is None: continue if isinstance(value, (tuple, list)): chr_ = '.' if name.endswith('_version') else ' ' value = chr_.join(str(v) for v in value) tags[name] = value client.captureException(tb, tags=tags, extra=extra) if is_developer_mode() and submit: report()
def _prepare_logfiles(self): from stoqlib.lib.osutils import get_application_dir stoqdir = get_application_dir("stoq") log_dir = os.path.join(stoqdir, 'logs', time.strftime('%Y'), time.strftime('%m')) if not os.path.exists(log_dir): os.makedirs(log_dir) filename = 'stoq_%s.%s.log' % (time.strftime('%Y-%m-%d_%H-%M-%S'), os.getpid()) self._log_filename = os.path.join(log_dir, filename) from kiwi.log import set_log_file self._stream = set_log_file(self._log_filename, 'stoq*') if platform.system() != 'Windows': link_file = os.path.join(stoqdir, 'stoq.log') if os.path.exists(link_file): os.unlink(link_file) os.symlink(self._log_filename, link_file) # We want developers to see deprecation warnings. from stoqlib.lib.environment import is_developer_mode if is_developer_mode() and not self._options.quiet: import warnings if self._options.non_fatal_warnings: action = "default" else: action = "error" warnings.filterwarnings( action, category=DeprecationWarning, module="^(stoq|kiwi)")
def version(self, store, app_version): """Fetches the latest version :param store: a store :param app_version: application version :returns: a deferred with the version_string as a parameter """ try: bdist_type = library.bdist_type except Exception: bdist_type = None if os.path.exists(os.path.join('etc', 'init.d', 'stoq-bootstrap')): source = 'livecd' elif bdist_type in ['egg', 'wheel']: source = 'pypi' elif is_developer_mode(): source = 'devel' else: source = 'ppa' params = { 'hash': sysparam.get_string('USER_HASH'), 'demo': sysparam.get_bool('DEMO_MODE'), 'dist': platform.dist(), 'cnpj': get_main_cnpj(store), 'plugins': InstalledPlugin.get_plugin_names(store), 'product_key': get_product_key(), 'time': datetime.datetime.today().isoformat(), 'uname': platform.uname(), 'version': app_version, 'source': source, } params.update(self._get_company_details(store)) params.update(self._get_usage_stats(store)) return self._do_request('GET', 'version.json', **params)
def _prepare_logfiles(self): from stoqlib.lib.osutils import get_application_dir stoqdir = get_application_dir("stoq") log_dir = os.path.join(stoqdir, 'logs', time.strftime('%Y'), time.strftime('%m')) if not os.path.exists(log_dir): os.makedirs(log_dir) self._log_filename = os.path.join(log_dir, 'stoq_%s.log' % time.strftime('%Y-%m-%d_%H-%M-%S')) from kiwi.log import set_log_file self._stream = set_log_file(self._log_filename, 'stoq*') if hasattr(os, 'symlink'): link_file = os.path.join(stoqdir, 'stoq.log') if os.path.exists(link_file): os.unlink(link_file) os.symlink(self._log_filename, link_file) # We want developers to see deprecation warnings. from stoqlib.lib.environment import is_developer_mode if is_developer_mode(): import warnings warnings.filterwarnings( "default", category=DeprecationWarning, module="^(stoq|kiwi)")
def _prepare_logfiles(self): from stoqlib.lib.osutils import get_application_dir stoqdir = get_application_dir("stoq") log_dir = os.path.join(stoqdir, 'logs', time.strftime('%Y'), time.strftime('%m')) if not os.path.exists(log_dir): os.makedirs(log_dir) filename = 'stoq_%s.%s.log' % (time.strftime('%Y-%m-%d_%H-%M-%S'), os.getpid()) self._log_filename = os.path.join(log_dir, filename) from kiwi.log import set_log_file self._stream = set_log_file(self._log_filename, 'stoq*') if hasattr(os, 'symlink'): link_file = os.path.join(stoqdir, 'stoq.log') if os.path.exists(link_file): os.unlink(link_file) os.symlink(self._log_filename, link_file) # We want developers to see deprecation warnings. from stoqlib.lib.environment import is_developer_mode if is_developer_mode(): import warnings if self._options.non_fatal_warnings: action = "default" else: action = "error" warnings.filterwarnings(action, category=DeprecationWarning, module="^(stoq|kiwi)")
def _setup_widgets(self): self.set_ok_label(_(u'Activate'), gtk.STOCK_APPLY) self.ok_button.set_sensitive(False) plugins = [] for name in sorted(self._manager.available_plugins_names): # FIXME: Remove when magento plugin is functional for end users if not is_developer_mode() and name == 'magento': continue if platform.system() == 'Windows': if name in ['ecf', 'tef']: continue desc = self._manager.get_description_by_name(name) plugins.append( _PluginModel(name, name in self._manager.installed_plugins_names, desc)) self.klist = ObjectList(self._get_columns(), plugins, gtk.SELECTION_BROWSE) self.klist.set_headers_visible(False) self.klist.connect("selection-changed", self._on_klist__selection_changed) self.main.remove(self.main.get_child()) self.main.add(self.klist) self.klist.show()
def cmd_updateschema(self, options): """Update the database schema""" from stoqlib.database.migration import StoqlibSchemaMigration from stoqlib.lib.environment import is_developer_mode from stoqlib.net.server import ServerProxy self._read_config(options, check_schema=False, load_plugins=False, register_station=False) # This is a little bit tricky to be able to apply the initial # plugin infrastructure migration = StoqlibSchemaMigration() if is_developer_mode(): backup = False else: backup = options.disable_backup server = ServerProxy() running = server.check_running() if running: server.call('pause_tasks') try: retval = migration.update(backup=backup) finally: # The schema was upgraded. If it was running before, # restart it so it can load the new code if running: server.call('restart') return 0 if retval else 1
def _setup_widgets(self): self.set_ok_label(_(u'Activate'), gtk.STOCK_APPLY) self.ok_button.set_sensitive(False) plugins = [] for name in sorted(self._manager.available_plugins_names): # FIXME: Remove when magento plugin is functional for end users if not is_developer_mode() and name == 'magento': continue if platform.system() == 'Windows': if name in ['ecf', 'tef']: continue desc = self._manager.get_description_by_name(name) plugins.append(_PluginModel(name, name in self._manager.installed_plugins_names, desc)) self.klist = ObjectList(self._get_columns(), plugins, gtk.SELECTION_BROWSE) self.klist.set_headers_visible(False) self.klist.connect("selection-changed", self._on_klist__selection_changed) self.main.remove(self.main.get_child()) self.main.add(self.klist) self.klist.show()
def create_actions(self): group = get_accels('app.maintenance') actions = [ # File ("OrderMenu", None, _(u"Order")), ("NewOrder", None, _(u"Work order..."), group.get("new_order")), ("SendOrders", None, _(u"Send orders...")), ("ReceiveOrders", None, _(u"Receive orders...")), # Search ("Products", None, _(u"Products..."), group.get("search_products") ), ("Services", None, _(u"Services..."), group.get("search_services")), ("Categories", None, _(u"Categories..."), group.get("search_categories")), ("Clients", STOQ_CLIENTS, _(u"Clients..."), group.get("search_clients")), # Order ("Edit", gtk.STOCK_EDIT, _(u"Edit..."), group.get('order_edit'), _(u"Edit the selected order")), ("Finish", gtk.STOCK_APPLY, _(u"Finish..."), group.get('order_finish'), _(u"Finish the selected order")), ("Cancel", gtk.STOCK_CANCEL, _(u"Cancel..."), group.get('order_cancel'), _(u"Cancel the selected order")), ("Details", gtk.STOCK_INFO, _(u"Details..."), group.get('order_details'), _(u"Show details of the selected order")), ("PrintQuote", None, _(u"Print quote..."), group.get('order_print_quote'), _(u"Print a quote report of the selected order")), ("PrintReceipt", None, _(u"Print receipt..."), group.get('order_print_receipt'), _(u"Print a receipt of the selected order")), ] self.maintenance_ui = self.add_ui_actions("", actions, filename="maintenance.xml") radio_actions = [ ('ViewKanban', '', _("View as Kanban"), '', _("Show in Kanban mode")), ('ViewList', '', _("View as List"), '', _("Show in list mode")), ] self.add_ui_actions('', radio_actions, 'RadioActions', 'radio') if is_developer_mode(): self.ViewList.props.active = True else: self.ViewList.props.visible = False self.ViewKanban.props.visible = False self.Edit.set_short_label(_(u"Edit")) self.Finish.set_short_label(_(u"Finish")) self.Edit.props.is_important = True self.Finish.props.is_important = True self.set_help_section(_(u"Maintenance help"), 'app-maintenance') self.popup = self.uimanager.get_widget('/MaintenanceSelection')
def setup_device_port_combo(self): items = [(_("Choose..."), None)] items.extend([(unicode(device.device_name), unicode(device.device_name)) for device in self._device_manager.get_serial_devices()]) if is_developer_mode(): # Include virtual port for virtual printer items.append(('Virtual device', u'/dev/null')) self.device_combo.prefill(items)
def collect_traceback(tb, output=True, submit=False): """Collects traceback which might be submitted @output: if it is to be printed @submit: if it is to be submitted immediately """ _tracebacks.append(tb) if output: traceback.print_exception(*tb) if has_raven and not is_developer_mode(): # pragma no cover extra = collect_report() extra.pop('tracebacks') sentry_url = os.environ.get( 'STOQ_SENTRY_URL', ('https://*****:*****@sentry.stoq.com.br/4')) client = raven.Client(sentry_url, release=stoq.version) if hasattr(client, 'user_context'): client.user_context({'id': extra.get('hash', None), 'username': extra.get('cnpj', None)}) # Don't sent logs to sentry if 'log' in extra: del extra['log'] if 'log_name' in extra: del extra['log_name'] tags = {} for name in ['architecture', 'cnpj', 'system', 'app_name', 'bdist_type', 'app_version', 'distribution', 'python_version', 'psycopg_version', 'pygtk_version', 'gtk_version', 'kiwi_version', 'reportlab_version', 'stoqdrivers_version', 'postgresql_version']: value = extra.pop(name, None) if value is None: continue tags[name] = value client.captureException(tb, tags=tags, extra=extra) if is_developer_mode() and submit: rs = ReportSubmitter() r = rs.submit() r.get_response()
def collect_traceback(tb, output=True, submit=False): """Collects traceback which might be submitted @output: if it is to be printed @submit: if it is to be submitted immediately """ _tracebacks.append(tb) if output: traceback.print_exception(*tb) if has_raven and not is_developer_mode(): # pragma no cover sentry_url = os.environ.get( 'STOQ_SENTRY_URL', ('http://*****:*****@sentry.stoq.com.br/4')) client = raven.Client(sentry_url) extra = collect_report() extra.pop('tracebacks') # Don't sent logs to sentry if 'log' in extra: del extra['log'] if 'log_name' in extra: del extra['log_name'] tags = {} for name in ['architecture', 'cnpj', 'system', 'app_name', 'app_version', 'distribution', 'python_version', 'psycopg_version', 'pygtk_version', 'gtk_version', 'kiwi_version', 'reportlab_version', 'stoqdrivers_version', 'postgresql_version']: value = extra.pop(name, None) if value is None: continue if isinstance(value, (tuple, list)): chr_ = '.' if name.endswith('_version') else ' ' value = chr_.join(str(v) for v in value) tags[name] = value client.captureException(tb, tags=tags, extra=extra) if is_developer_mode() and submit: report()
def _try_show_html(self, data): if not data: return if not '<html>' in data: return if not is_developer_mode(): return from stoqlib.gui.widgets.webview import show_html show_html(data)
def __eq__(self, other): if type(self) is not type(other): return False from stoqlib.lib.environment import is_developer_mode if is_developer_mode(): # Check this only in develper mode to get as many potential errors # as possible. assert Store.of(self) is Store.of(other) return self.id == other.id
def _populate_serial_ports(self): values = [] for device in DeviceManager.get_serial_devices(): values.append(device.device_name) if not self.model.device_name in values: values.append(self.model.device_name) if sysparam.get_bool('DEMO_MODE') or is_developer_mode(): values.append(u'/dev/null') self.device_name.prefill(values)
def _get_supported_types(self): if self.model.type == DeviceSettings.SCALE_DEVICE: supported_types = get_supported_scales() #elif self.model.type == DeviceSettings.CHEQUE_PRINTER_DEVICE: # supported_types = get_supported_printers_by_iface(IChequePrinter) elif self.model.type == DeviceSettings.NON_FISCAL_PRINTER_DEVICE: supported_types = get_supported_printers_by_iface(INonFiscalPrinter, include_virtual=is_developer_mode()) else: raise TypeError("The selected device type isn't supported") return supported_types
def __init__(self, port=None): threading.Thread.__init__(self) self.port = port if self.port is None and is_developer_mode(): self.port = 8080 # Indicate that this Thread is a daemon. Accordingly to the # documentation, the entire python program exits when no alive # non-daemon threads are left. self.daemon = True self.running = False
def run_flaskserver(port, debug=False, multiclient=False): from stoqlib.lib.environment import configure_locale # Force pt_BR for now. configure_locale('pt_BR') global is_multiclient is_multiclient = multiclient from .workers import WORKERS # For now we're disabling workers when stoqserver is serving multiple clients (multiclient mode) # FIXME: a proper solution would be to modify the workflow so that the clients ask the server # about devices health, the till status, etc. instead of the other way around. if not is_multiclient: for function in WORKERS: gevent.spawn(function, get_current_station(api.get_default_store())) try: from stoqserver.lib import stacktracer stacktracer.start_trace("/tmp/trace-stoqserver-flask.txt", interval=5, auto=True) except ImportError: pass app = bootstrap_app() app.debug = debug if not is_developer_mode(): sentry.raven_client = Sentry(app, dsn=SENTRY_URL, client=raven_client) @app.after_request def after_request(response): # Add all the CORS headers the POS needs to have its ajax requests # accepted by the browser origin = request.headers.get('origin') if not origin: origin = request.args.get('origin', request.form.get('origin', '*')) response.headers['Access-Control-Allow-Origin'] = origin response.headers['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS, DELETE' response.headers['Access-Control-Allow-Headers'] = 'Authorization, Content-Type' response.headers['Access-Control-Allow-Credentials'] = 'true' return response from stoqserver.lib.restful import has_sat, has_nfe logger.info('Starting wsgi server (has_sat=%s, has_nfe=%s)', has_sat, has_nfe) http_server = WSGIServer(('0.0.0.0', port), app, spawn=gevent.spawn_raw, log=logger, error_log=logger) if debug: gevent.spawn(_gtk_main_loop) @run_with_reloader def run_server(): http_server.serve_forever() run_server() else: http_server.serve_forever()
def _prepare_logfiles(self): from stoq.lib.logging import setup_logging self._log_filename, self.stream = setup_logging("stoq") from stoqlib.lib.environment import is_developer_mode # We want developers to see deprecation warnings. if is_developer_mode(): import warnings warnings.filterwarnings( "default", category=DeprecationWarning, module="^(stoq|kiwi)")
def test_api(): store = api.get_default_store() assert store is get_default_store() assert api.get_current_user(store) is get_current_user(store) assert api.db_settings is db_settings assert api.user_settings is get_settings() assert isinstance(api.device_manager, DeviceManager) with pytest.raises(NotImplementedError): assert isinstance(api.config, IStoqConfig) assert api.is_developer_mode() is is_developer_mode() assert api.get_l10n_field('CPF') is get_l10n_field('CPF')
def __init__(self, port=None): super(Daemon, self).__init__() self.port = port if self.port is None and is_developer_mode(): self.port = 8080 elif self.port is None: self.port = get_random_port() # Indicate that this Thread is a daemon. Accordingly to the # documentation, the entire python program exits when no alive # non-daemon threads are left. self.daemon = True
def collect_traceback(tb, output=True, submit=False): """Collects traceback which might be submitted @output: if it is to be printed @submit: if it is to be submitted immediately """ _tracebacks.append(tb) if output: traceback.print_exception(*tb) if is_developer_mode() and submit: report()
def _check_parent_running(self): # When developing, we usually kill stoq a lot with something that # will not allow it to stop the daemon (e.g. ctrl+q, ctrl+4) so # it is better to do the check every 1 second. On production this # shouldn't happen often, but if it happens, it is ok to have it # running for another 5 seconds. sleep_time = 1 if is_developer_mode() else 5 while self.is_alive(): # If the parent dies, ppid will change. In this case, # finalize this process. It shouldn't be running anymore. if os.getppid() != self._ppid: os._exit(0) time.sleep(sleep_time)
def setup_device_port_combo(self): items = [(_("Choose..."), None)] items.extend([(str(device.device_name), str(device.device_name)) for device in DeviceManager.get_serial_devices()]) items.extend(self._get_usb_devices()) if is_developer_mode(): # Include virtual port for virtual printer items.append(('Virtual device', u'/dev/null')) devices = [i[1] for i in items] if self.model.device_name not in devices: items.append(('Unkown device (%s)' % self.model.device_name, self.model.device_name)) self.device_combo.prefill(items)
def _populate_printers(self): supported_ifaces = get_supported_printers_by_iface(ICouponPrinter).items() printers = [] for brand, printer_classes in supported_ifaces: for printer_class in printer_classes: printer = _PrinterModel(brand, printer_class) printers.append((printer.get_description(), printer)) # Allow to use virtual printer for both demo mode and developer mode # so it's easier for testers and developers to test ecf functionality if sysparam.get_bool('DEMO_MODE') or is_developer_mode(): from stoqdrivers.printers.virtual.Simple import Simple printer = _PrinterModel('virtual', Simple) printers.append((printer.get_description(), printer)) self.printer.prefill(locale_sorted( printers, key=operator.itemgetter(0)))
def _populate_printers(self): supported_ifaces = get_supported_printers_by_iface(ICouponPrinter).items() printers = [] for brand, printer_classes in supported_ifaces: for printer_class in printer_classes: printer = _PrinterModel(brand, printer_class) printers.append((printer.get_description(), printer)) # Allow to use virtual printer for both demo mode and developer mode # so it's easier for testers and developers to test ecf functionality if sysparam(self.store).DEMO_MODE or is_developer_mode(): from stoqdrivers.printers.virtual.Simple import Simple printer = _PrinterModel('virtual', Simple) printers.append((printer.get_description(), printer)) self.printer.prefill(locale_sorted( printers, key=operator.itemgetter(0)))
def cmd_updateschema(self, options): """Update the database schema""" from stoqlib.api import api from stoqlib.database.migration import StoqlibSchemaMigration from stoqlib.lib.environment import is_developer_mode from stoqlib.net.server import ServerProxy from twisted.internet import reactor self._read_config(options, check_schema=False, load_plugins=False, register_station=False) # This is a little bit tricky to be able to apply the initial # plugin infrastructure migration = StoqlibSchemaMigration() if is_developer_mode(): backup = False else: backup = options.disable_backup @api. async def migrate(retval): server = ServerProxy() running = yield server.check_running() if running: yield server.call('pause_tasks') try: retval[0] = yield migration.update_async(backup=backup) finally: # The schema was upgraded. If it was running before, # restart it so it can load the new code if running: yield server.call('restart') if reactor.running: reactor.stop() retval = [False] reactor.callWhenRunning(migrate, retval) reactor.run() return 0 if retval[0] else 1
def cmd_updateschema(self, options): """Update the database schema""" from stoqlib.database.migration import StoqlibSchemaMigration from stoqlib.lib.environment import is_developer_mode self._read_config(options, check_schema=False, load_plugins=False, register_station=False) # This is a little bit tricky to be able to apply the initial # plugin infrastructure migration = StoqlibSchemaMigration() if is_developer_mode(): backup = False else: backup = options.disable_backup if not migration.update(backup=backup): return 1
def _setup_gtk(self): from gi.repository import Gtk, Gdk from kiwi.environ import environ from stoqlib.lib.template import render_template_string # Total madness to make sure we can draw treeview lines, # this affects the GtkTreeView::grid-line-pattern style property # # Two bytes are sent in, see gtk_tree_view_set_grid_lines in gtktreeview.c # Byte 1 should be as high as possible, gtk+ 0x7F appears to be # the highest allowed for Gtk+ 2.22 while 0xFF worked in # earlier versions # Byte 2 should ideally be allowed to be 0, but neither C nor Python # allows that. # data = environ.get_resource_string("stoq", "misc", "stoq.css") data = render_template_string(data) style_provider = Gtk.CssProvider() style_provider.load_from_data(data) Gtk.StyleContext.add_provider_for_screen( Gdk.Screen.get_default(), style_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) settings = Gtk.Settings.get_default() settings.props.gtk_button_images = True from stoqlib.lib.environment import is_developer_mode if is_developer_mode(): # Install a Control-Q handler that forcefully exits # the program without saving any kind of state def event_handler(event): state = event.get_state() if isinstance(state, tuple): state = state[1] if (event.type == Gdk.EventType.KEY_PRESS and state & Gdk.ModifierType.CONTROL_MASK and event.keyval == Gdk.KEY_q): os._exit(0) Gtk.main_do_event(event) Gdk.event_handler_set(event_handler)
def version(self, store, app_version, **kwargs): """Fetches the latest version :param store: a store :param app_version: application version """ import stoq try: bdist_type = library.bdist_type except Exception: bdist_type = None # We should use absolute paths when looking for /etc if os.path.exists( os.path.join(os.sep, 'etc', 'init.d', 'stoq-bootstrap')): source = 'livecd' elif stoq.trial_mode: source = 'trial' elif bdist_type in ['egg', 'wheel']: source = 'pypi' elif is_developer_mode(): source = 'devel' else: source = 'ppa' params = { 'demo': sysparam.get_bool('DEMO_MODE'), 'dist': ' '.join(platform.dist()), 'cnpj': get_main_cnpj(store), 'plugins': ' '.join(InstalledPlugin.get_plugin_names(store)), 'product_key': get_product_key(), 'uname': ' '.join(platform.uname()), 'version': app_version, 'source': source, } params.update(self._get_company_details(store)) params.update(self._get_usage_stats(store)) endpoint = 'api/stoq/v1/version/%s' % ( sysparam.get_string('USER_HASH'), ) return self._do_request('POST', endpoint, json=params, **kwargs)
def _check_version_policy(self): # No need to bother version checking when not running in developer mode from stoqlib.lib.environment import is_developer_mode if not is_developer_mode(): return import stoq # # Policies for stoq/stoqlib versions, # All these policies here are made so that stoqlib version is tightly # tied to the stoq versioning # # We reserve the first 89 for the stable series. FIRST_UNSTABLE_MICRO_VERSION = 90 # Stable series of Stoq must: # 1) have extra_version set to < 90 # 2) Depend on a stoqlib version with extra_version < 90 # if stoq.stable: if (stoq.micro_version >= FIRST_UNSTABLE_MICRO_VERSION and not 'rc' in stoq.extra_version): # FIXME: Reenable this check for 1.13 series pass #raise SystemExit( # "Stable stoq release should set micro_version to " # "%d or lower" % (FIRST_UNSTABLE_MICRO_VERSION, )) # Unstable series of Stoq must have: # 1) have extra_version set to >= 90 # 2) Must depend stoqlib version with extra_version >= 90 # else: if stoq.micro_version < FIRST_UNSTABLE_MICRO_VERSION: raise SystemExit( "Unstable stoq (%s) must set micro_version to %d or higher, " "or did you forget to set stoq.stable to True?" % ( stoq.version, FIRST_UNSTABLE_MICRO_VERSION))
def version(self, store, app_version, **kwargs): """Fetches the latest version :param store: a store :param app_version: application version """ import stoq try: bdist_type = library.bdist_type except Exception: bdist_type = None # We should use absolute paths when looking for /etc if os.path.exists(os.path.join(os.sep, 'etc', 'init.d', 'stoq-bootstrap')): source = 'livecd' elif stoq.trial_mode: source = 'trial' elif bdist_type in ['egg', 'wheel']: source = 'pypi' elif is_developer_mode(): source = 'devel' else: source = 'ppa' params = { 'demo': sysparam.get_bool('DEMO_MODE'), 'dist': ' '.join(platform.dist()), 'cnpj': get_main_cnpj(store), 'plugins': ' '.join(InstalledPlugin.get_plugin_names(store)), 'product_key': get_product_key(), 'uname': ' '.join(platform.uname()), 'version': app_version, 'source': source, } params.update(self._get_company_details(store)) params.update(self._get_usage_stats(store)) endpoint = 'api/stoq/v1/version/%s' % (sysparam.get_string('USER_HASH'), ) return self._do_request('POST', endpoint, json=params, **kwargs)
def _setup_gtk(self): import gtk from kiwi.environ import environ gtk.gdk.threads_init() # Total madness to make sure we can draw treeview lines, # this affects the GtkTreeView::grid-line-pattern style property # # Two bytes are sent in, see gtk_tree_view_set_grid_lines in gtktreeview.c # Byte 1 should be as high as possible, gtk+ 0x7F appears to be # the highest allowed for Gtk+ 2.22 while 0xFF worked in # earlier versions # Byte 2 should ideally be allowed to be 0, but neither C nor Python # allows that. # data = environ.get_resource_string("stoq", "misc", "stoq.gtkrc") data = data.replace('\\x7f\\x01', '\x7f\x01') gtk.rc_parse_string(data) # Creating a button as a temporary workaround for bug # https://bugzilla.gnome.org/show_bug.cgi?id=632538, until gtk 3.0 gtk.Button() settings = gtk.settings_get_default() settings.props.gtk_button_images = True from stoqlib.lib.environment import is_developer_mode if is_developer_mode() and gtk.gtk_version[0] == 2: from gtk import gdk # Install a Control-Q handler that forcefully exits # the program without saving any kind of state def event_handler(event): if (event.type == gdk.KEY_PRESS and event.state & gdk.CONTROL_MASK and event.keyval == gtk.keysyms.q): os._exit(0) gtk.main_do_event(event) gdk.event_handler_set(event_handler)
def _check_version_policy(self): # No need to bother version checking when not running in developer mode from stoqlib.lib.environment import is_developer_mode if not is_developer_mode(): return import stoq # # Policies for stoq/stoqlib versions, # All these policies here are made so that stoqlib version is tightly # tied to the stoq versioning # # We reserve the first 89 for the stable series. FIRST_UNSTABLE_MICRO_VERSION = 90 # Stable series of Stoq must: # 1) have extra_version set to < 90 # 2) Depend on a stoqlib version with extra_version < 90 # if stoq.stable: if (stoq.micro_version >= FIRST_UNSTABLE_MICRO_VERSION and not 'rc' in stoq.extra_version): # FIXME: Reenable this check for 1.13 series pass #raise SystemExit( # "Stable stoq release should set micro_version to " # "%d or lower" % (FIRST_UNSTABLE_MICRO_VERSION, )) # Unstable series of Stoq must have: # 1) have extra_version set to >= 90 # 2) Must depend stoqlib version with extra_version >= 90 # else: if stoq.micro_version < FIRST_UNSTABLE_MICRO_VERSION: raise SystemExit( "Unstable stoq (%s) must set micro_version to %d or higher, " "or did you forget to set stoq.stable to True?" % (stoq.version, FIRST_UNSTABLE_MICRO_VERSION))
def _setup_gtk(self): import gtk from kiwi.environ import environ # Total madness to make sure we can draw treeview lines, # this affects the GtkTreeView::grid-line-pattern style property # # Two bytes are sent in, see gtk_tree_view_set_grid_lines in gtktreeview.c # Byte 1 should be as high as possible, gtk+ 0x7F appears to be # the highest allowed for Gtk+ 2.22 while 0xFF worked in # earlier versions # Byte 2 should ideally be allowed to be 0, but neither C nor Python # allows that. # data = environ.get_resource_string("stoq", "misc", "stoq.gtkrc") data = data.replace('\\x7f\\x01', '\x7f\x01') gtk.rc_parse_string(data) # Creating a button as a temporary workaround for bug # https://bugzilla.gnome.org/show_bug.cgi?id=632538, until gtk 3.0 gtk.Button() settings = gtk.settings_get_default() settings.props.gtk_button_images = True from stoqlib.lib.environment import is_developer_mode if is_developer_mode() and gtk.gtk_version[0] == 2: from gtk import gdk # Install a Control-Q handler that forcefully exits # the program without saving any kind of state def event_handler(event): if (event.type == gdk.KEY_PRESS and event.state & gdk.CONTROL_MASK and event.keyval == gtk.keysyms.q): os._exit(0) gtk.main_do_event(event) gdk.event_handler_set(event_handler)
def collect_traceback(tb, output=True, submit=False): """Collects traceback which might be submitted @output: if it is to be printed @submit: if it is to be submitted immediately """ _tracebacks.append(tb) if output: traceback.print_exception(*tb) if "STOQ_SENTRY_URL" in os.environ: try: from raven import Client has_raven = True except ImportError: has_raven = False if has_raven: client = Client(os.environ["STOQ_SENTRY_URL"]) client.captureException(tb) if is_developer_mode() and submit: report()
logger = logging.getLogger(__name__) _SENTRY_URL = ('http://*****:*****@sentry.stoq.com.br/11') _LOGGING_FORMAT = '%(asctime)-15s %(name)-35s %(levelname)-8s %(message)s' _LOGGING_DATE_FORMAT = '%y-%m-%d %H:%M:%S' try: import raven _raven_client = raven.Client(_SENTRY_URL) except ImportError: _raven_client = None # Disable send sentry log if its is_developer_mode if is_developer_mode(): _raven_client = None # Do this as soon as possible so we can log any early traceback if _raven_client is not None: def _excepthook(exctype, value, tb): tags = { 'version': ".".join(str(i) for i in stoqserver.__version__), 'stoq_version': stoq.version, 'architecture': platform.architecture(), 'distribution': platform.dist(), 'python_version': tuple(sys.version_info), 'system': platform.system(), 'uname': platform.uname(), } # Those are inside a try/except because thy require database access.
def run(self): port = 8080 if is_developer_mode() else None self._xmlrpc = XMLRPCService(port) self._xmlrpc.serve() self.port = self._xmlrpc.port
def _start_xmlrpc(self): port = None if is_developer_mode(): port = 8080 self._xmlrpc = XMLRPCService(port) self._xmlrpc.serve()
def is_developer_mode(self): return is_developer_mode()
def bootstrap_app(debug=False, multiclient=False): app = Flask(__name__) app.debug = debug app.multiclient = multiclient # Indexing some session data by the USER_HASH will help to avoid maintaining # sessions between two different databases. This could lead to some errors in # the POS in which the user making the sale does not exist. app.config['SECRET_KEY'] = get_user_hash() app.config['PROPAGATE_EXCEPTIONS'] = True app.config['RESTFUL_JSON'] = { 'cls': JsonEncoder, } flask_api = Api(app) if RequestID: RequestID(app) register_routes(flask_api) signal('StoqTouchStartupEvent').send() @app.errorhandler(Exception) def unhandled_exception(e): traceback_info = "\n".join(traceback.format_tb(e.__traceback__)) traceback_hash = hashlib.sha1( traceback_info.encode('utf-8')).hexdigest()[:8] traceback_exception = traceback.format_exception_only(type(e), e)[-1] timestamp = localnow().strftime('%Y%m%d-%H%M%S') logger.exception( 'Unhandled Exception: {timestamp} {error} {traceback_hash}'.format( timestamp=timestamp, error=e, traceback_hash=traceback_hash)) sentry_report(type(e), e, e.__traceback__, traceback_hash=traceback_hash) return Response(json.dumps({ 'error': _('bad request!'), 'timestamp': timestamp, 'exception': traceback_exception, 'traceback_hash': traceback_hash }), 500, mimetype='application/json') if not is_developer_mode(): sentry.raven_client = Sentry(app, dsn=SENTRY_URL, client=raven_client) @app.after_request def after_request(response): # Add all the CORS headers the POS needs to have its ajax requests # accepted by the browser origin = request.headers.get('origin') if not origin: origin = request.args.get('origin', request.form.get('origin', '*')) response.headers['Access-Control-Allow-Origin'] = origin response.headers[ 'Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS, DELETE' response.headers[ 'Access-Control-Allow-Headers'] = 'Authorization, Content-Type' response.headers['Access-Control-Allow-Credentials'] = 'true' return response return app
def post_ping_request(station): if is_developer_mode(): return from .lib.restful import PDV_VERSION target = 'https://app.stoq.link:9000/api/ping' time_format = '%d-%m-%Y %H:%M:%S%Z' store = api.get_default_store() plugin_manager = get_plugin_manager() boot_time = datetime.datetime.fromtimestamp( psutil.boot_time()).strftime(time_format) def get_stoq_conf(): with open(get_config().get_filename(), 'r') as fh: return fh.read().encode() def get_clisitef_ini(): try: with open('CliSiTef.ini', 'r') as fh: return fh.read().encode() except FileNotFoundError: return ''.encode() while True: try: dpkg_list = subprocess.check_output('dpkg -l \\*stoq\\*', shell=True).decode() except subprocess.CalledProcessError: dpkg_list = "" stoq_packages = re.findall(r'ii\s*(\S*)\s*(\S*)', dpkg_list) if PDV_VERSION: logger.info('Running stoq_pdv {}'.format(PDV_VERSION)) logger.info('Running stoq {}'.format(stoq_version)) logger.info('Running stoq-server {}'.format(stoqserver_version)) logger.info('Running stoqdrivers {}'.format(stoqdrivers_version)) local_time = tzlocal.get_localzone().localize(datetime.datetime.now()) response = requests.post( target, headers={ 'Stoq-Backend': '{}-portal'.format(api.sysparam.get_string('USER_HASH')) }, data={ 'station_id': station.id, 'data': json.dumps({ 'platform': { 'architecture': platform.architecture(), 'distribution': platform.dist(), 'system': platform.system(), 'uname': platform.uname(), 'python_version': platform.python_version_tuple(), 'postgresql_version': get_database_version(store) }, 'system': { 'boot_time': boot_time, 'cpu_times': psutil.cpu_times(), 'load_average': os.getloadavg(), 'disk_usage': psutil.disk_usage('/'), 'virtual_memory': psutil.virtual_memory(), 'swap_memory': psutil.swap_memory() }, 'plugins': { 'available': plugin_manager.available_plugins_names, 'installed': plugin_manager.installed_plugins_names, 'active': plugin_manager.active_plugins_names, 'versions': getattr(plugin_manager, 'available_plugins_versions', None) }, 'running_versions': { 'pdv': PDV_VERSION, 'stoq': stoq_version, 'stoqserver': stoqserver_version, 'stoqdrivers': stoqdrivers_version }, 'stoq_packages': dict(stoq_packages), 'local_time': local_time.strftime(time_format), 'stoq_conf_md5': md5(get_stoq_conf()).hexdigest(), 'clisitef_ini_md5': md5(get_clisitef_ini()).hexdigest() }) }) logger.info("POST {} {} {}".format(target, response.status_code, response.elapsed.total_seconds())) gevent.sleep(3600)
def create_actions(self): group = get_accels('app.maintenance') actions = [ # File ("OrderMenu", None, _(u"Order")), ("NewOrder", None, _(u"Work order..."), group.get("new_order")), ("SendOrders", None, _(u"Send orders...")), ("ReceiveOrders", None, _(u"Receive orders...")), # Search ("Products", None, _(u"Products..."), group.get("search_products")), ("Services", None, _(u"Services..."), group.get("search_services")), ("Categories", None, _(u"Categories..."), group.get("search_categories")), ("Clients", STOQ_CLIENTS, _(u"Clients..."), group.get("search_clients")), # Order ("Edit", gtk.STOCK_EDIT, _(u"Edit..."), group.get('order_edit'), _(u"Edit the selected order")), ("Finish", gtk.STOCK_APPLY, _(u"Finish..."), group.get('order_finish'), _(u"Finish the selected order")), ("Cancel", gtk.STOCK_CANCEL, _(u"Cancel..."), group.get('order_cancel'), _(u"Cancel the selected order")), ("DeliverOrder", None, _(u"Delivered...")), ("Details", gtk.STOCK_INFO, _(u"Details..."), group.get('order_details'), _(u"Show details of the selected order")), ("PrintQuote", None, _(u"Print quote..."), group.get('order_print_quote'), _(u"Print a quote report of the selected order")), ("PrintReceipt", None, _(u"Print receipt..."), group.get('order_print_receipt'), _(u"Print a receipt of the selected order")), ("Approve", None, _(u"Approve...")), ("Pause", None, _(u"Pause the work...")), ("Work", None, _(u"Start the work...")), ("Reject", None, _(u"Reject order...")), ("UndoRejection", None, _(u"Undo order rejection...")), ("Reopen", None, _(u"Reopen order...")), ] self.maintenance_ui = self.add_ui_actions("", actions, filename="maintenance.xml") radio_actions = [ ('ViewKanban', '', _("View as Kanban"), '', _("Show in Kanban mode")), ('ViewList', '', _("View as List"), '', _("Show in list mode")), ] self.add_ui_actions('', radio_actions, 'RadioActions', 'radio') if is_developer_mode(): self.ViewList.props.active = True else: self.ViewList.props.visible = False self.ViewKanban.props.visible = False self.Edit.set_short_label(_(u"Edit")) self.Finish.set_short_label(_(u"Finish")) self.Edit.props.is_important = True self.Finish.props.is_important = True self.set_help_section(_(u"Maintenance help"), 'app-maintenance') self.popup = self.uimanager.get_widget('/MaintenanceSelection')