def __call__(self, *args, **kwargs): if self._call_mode == CallMode.transparent: mainlog.debug( "JsoncCallableDecorator : transparent call transfer") mainlog.debug("args = {}".format(args)) return self.call_decorated(*args, **kwargs) elif self._call_mode == CallMode.http: assert self._call_handler, "Call handler not set for http mode" mainlog.debug("JsoncCallableDecorator : making http call") rpc_request = self._call_handler.build_client_side_rpc_request( self, *args) jsonable_res = self._call_handler.call_json_rpc_over_http( rpc_request) mainlog.debug( "JsoncCallableDecorator : making http call, result is {}". format(jsonable_res)) func_sig = signature(self._decorated_func) return self._call_handler.jsonable_to_return_values( func_sig, self.out_recursive_set, jsonable_res['result']) # return self._call_handler.jsonable_to_return_values( jsonable_res) elif self._call_mode == CallMode.in_process: assert self._call_handler, "Call handler not set for in process mode" mainlog.debug( "JsoncCallableDecorator : making in process call, params are {}" .format(args)) return self._call_handler.in_process_call( self, *args, **kwargs) else: mainlog.error("Unsupported call mode {}, {}".format( self._call_mode, self._call_mode == CallMode.in_process))
def init_configuration(): p = path_to_config("server.cfg") if not os.path.exists(p): ps = os.path.join(resource_dir, "server_config_check.cfg") if os.path.exists(ps): make_empty_configuration_file(p, ps) load_configuration_server(p, ps) configuration.set_server_network_address( ip_or_host=guess_server_url(), port=8079, overwrite=True) set_default_document_root(configuration) configuration.save() mainlog.info("Configuration file created at {}".format(p)) return True else: mainlog.error( "Can't find the specification configuration file, there : {}". format(ps)) return False else: mainlog.error( "Can't initialize configuration file because it already exists, there : {}" .format(p)) return False
def send_mail(subject, content, cfg): # typical values for text_subtype are plain, html, xml text_subtype = 'plain' msg = MIMEText(content, text_subtype) msg['Subject'] = subject msg['From'] = cfg.get( 'Mail', 'sender') # some SMTP servers will do this automatically, not all if not cfg.get('Mail', 'SMTPServer'): mainlog.error("Mail configuration seems broken. Can't send email.") # Since this is backup, failing sending a mail should not stop # the execution => no exception thrown return conn = SMTP(cfg.get('Mail', 'SMTPServer')) conn.set_debuglevel(False) # conn.login(cfg.get('Mail','SMTPUser'), cfg.get('Mail','SMTPPassword')) try: conn.sendmail(cfg.get('Mail', 'sender'), cfg.get('Mail', 'destination'), msg.as_string()) except Exception as ex: mainlog.error("Unable to send mail") finally: conn.close() mainlog.info("Mail sent")
def alter_data(): # For the moment I skip this because I think that adding a role that is not # supported by the user session might lock people out of Horse # return import os import shutil q = session().query(Document).order_by(Document.document_id).all() for document in q: path, filename = os.path.split(document.server_location) new_path = documents_service._make_path_to_document( document.document_id, document.filename) mainlog.debug(u"Document {} -> filename:{} -- new_name:{}".format( document.document_id, document.filename, new_path)) try: shutil.copy(document.server_location, new_path) document.server_location = new_path except Exception as ex: mainlog.error("Unable to copy !") mainlog.exception(ex) session().rollback() return session().commit()
def delete_filter_action_slot(self): try: fq_id = None if self.filter_name.currentIndex() >= 0: fq_id = self.filter_name.itemData(self.filter_name.currentIndex()) if not fq_id: showWarningBox(_("The filter you want to delete was never saved"),None,parent=self,object_name="no_need_to_delete_filter") return fq = dao.filters_dao.find_by_id(fq_id) if fq.owner_id != user_session.user_id: showWarningBox(_("You can't delete the filter because it doesn't belong to you."),None,parent=self,object_name="not_my_filter") return dao.filters_dao.delete_by_id(fq_id,user_session.user_id) self.filter_name.reload() self.filter_name.preselect(None) except Exception as e: mainlog.error("Can't delete fq_id = {}".format(fq_id)) showErrorBox(_("There was a problem while deleting the filter."),None,e,object_name="delete_filter_fatal") self.filter_name.reload() self.filter_name.preselect(None)
def file(self): file_path = configuration.get("DownloadSite", "client_path") if not file_path or not os.path.exists(file_path): msg = "I can't serve the file {} because it doesn't exist.".format( file_path) mainlog.error(msg) raise cherrypy.HTTPError(404, message=msg) # Won't create an exception # I don't inject at update time because if one copies # a delivery_slips in, then that delivery_slips must be injected as well. public_ip = configuration.get("DEFAULT", "public_ip") if not public_ip: public_ip = guess_server_public_ip() mainlog.warn( "Server configuration is borken : missing DEFAULT/public_ip. I'll default to what I guessed instead : {}" .format(public_ip)) inject_public_ip_in_client(public_ip) return cherrypy.lib.static.serve_download( file_path, name=configuration.get("Globals", "codename") + '.zip')
def exception(self, ex): log_stacktrace() if isinstance(ex, ServerException): mainlog.error(u"MemLog {}".format(str(ex))) self.error(ex.code, ex.translated_message) else: self.error(-1, str(ex))
def find_by_id(self, employee_id: int) -> Employee: try: return session().query(Employee).filter( Employee.employee_id == employee_id).one() except NoResultFound as ex: mainlog.error( "EmployeeDAO.find_by_id: Failed to find with id {} of type {}". format(identifier, type(identifier))) raise ServerException(ServerErrors.unknown_employee_id, employee_id)
def load_version(self): try: f = open(os.path.join(resource_dir, "package_version")) v = f.read().strip() f.close() self.this_version = StrictVersion(v) mainlog.debug("Located version file in {}, version is {}".format( resource_dir, self.this_version)) except: mainlog.error( "Could not find the package_version file in {}".format( resource_dir)) self.this_version = StrictVersion("1.0.0")
def find_by_id_frozen(self, identifier): # FIXME replace by cache access try: mainlog.debug("find_by_id_frozen-1") emp = session().query(Employee).filter( Employee.employee_id == identifier).one() mainlog.debug("find_by_id_frozen-3") f = freeze(session(), emp) mainlog.debug("find_by_id_frozen-2") session().commit() return f except NoResultFound as ex: mainlog.error( "EmployeeDAO.find_by_id: Failed to find with id {} of type {}". format(identifier, type(identifier))) raise ex
def check_postgres_connection(db_url): """ Make sure we can connect to the server. We use the template1 schema for that, because it exists on any postgresql server. """ # I need DB url because I didn't find a way to get that information # from the session(), connection()... db_url, params_from_url = parse_db_url(db_url) parsed_url = urlparse(db_url) t1_url = parsed_url.scheme + "://" + parsed_url.netloc + "/template1" # Rage hard, maxi vinyl with spoken words (super rare) mainlog.info("Trying to connect to PostgreSQL server...") engine = create_engine(t1_url) c = None try: c = engine.connect() c.execute("SELECT count(*) from pg_stats") return True except exc.OperationalError as ex: mainlog.exception(ex) mainlog.error("Can't query the database !!! Is it connected ?") finally: # This one is rather tricky. Somehow, I have # the impression that the select above opens # a connection and don't close it. # Because of that, in some cases, PostgreSQL # is cannot proceed with some operations. # For example, if one stays connected to template1 # he cannot do a "drop table". So it is very important # that the connection, transaction, whatever is # actually closed when leaving this function. mainlog.debug("Closing conenction") if c: c.close() # I think this helps to better close the connection # although SQLA's documentation is a bit unclear. engine.dispose() del engine return False
def check_db_connection(db_url): # I need DB url because I didn't find a way to get that information # from the session(), connection()... import subprocess import re mainlog.info("check_db_connection : Trying to connect to the database") try: session().connection().execute( "SELECT count(*) from {}.employees".format(DATABASE_SCHEMA)) session().commit() return True except Exception as ex: mainlog.error("Can't query the database !!! Is it connected ?") ret = str(ex) # mainlog.exception(ex) mainlog.info("I'll try a ping") server_host = re.search("(@.*:)", db_url).groups()[0].replace("@", "").replace( ":", "") try: r = subprocess.Popen("\\Windows\\System32\\ping -n 1 " + server_host, stdout=PIPE, shell=False).stdout.read() mainlog.info("Ping to {} result is : {}".format(server_host, r)) ret += "<br/><br/>" if "Reply" in r: mainlog.info( "Ping was successful, the DB server machine seems up") ret += _( " A ping was successful (so host is up, database is down)") else: ret += _(" A ping was not successful (so host is down)") return ret except Exception as ex: #mainlog.error(str(ex,'ASCII','replace')) return _("Ping failed, the host is down.")
def backup_procedure(configuration): if not configuration.get('Backup', 'backup_directory'): raise Exception( "Missing Backup/backup_directory in configuration file") backup_dir = configuration.get('Backup', 'backup_directory') try: if not os.path.exists(backup_dir): os.mkdir(backup_dir) mainlog.info("Created backup directory because it was missing") mainlog.debug("Backup directory is {}".format(backup_dir)) # We default to backup behaviour because when # this program is run as a scheduled task, we cannot # give parameters to it mainlog.info("Backing up the database") filename, bytes = dump_and_zip_database(configuration) mainlog.info("Backing up the documents") total_files, total_bytes, scanned_files = documents_copy_recurring( configuration.get('DocumentsDatabase', 'documents_root'), configuration.get('Backup', 'backup_directory'), configuration) mainlog.info( "Documents copy done. {} files copied ({} bytes), {} files scanned." .format(total_files, size_to_str(total_bytes), scanned_files)) mainlog.info("Syncing the back up remotely") rsync_export_files(filename, mainlog) send_mail( "Backup SUCCESS", "The backup of was done correctly DB:{}, files: {} / {} bytes.". format(size_to_str(bytes), total_files, total_bytes), configuration) except Exception as ex: mainlog.error("Failed to complete backup") mainlog.exception(ex) send_mail("Backup FAILURE", "The backup of was *not* done correctly.", configuration)
def get(self, section, tag): # Pay attention ! If the key is not found in the configuration, configobj will # look at the default value in the spec. if section in self.base_configuration and tag in self.base_configuration[ section] and self.base_configuration[section][tag]: # mainlog.debug(u"Found tag {}/{} in config file -> {}".format(section,tag,self.base_configuration[section][tag])) return self.base_configuration[section][tag] else: mainlog.warning( "Could not find tag {}/{} in config file (or it has dubious empty value). Trying embedded config file." .format(section, tag)) if self.backup_configuration and section in self.backup_configuration and tag in self.backup_configuration[ section]: return self.backup_configuration[section][tag] else: mainlog.error( "Could not find tag {}/{} in config file nor in embedded config file. Defaulting to None" .format(section, tag)) return None
def _untabify_panel(self,ndx,panel): """ Remove a panel from the tabs and unregister it. The tab manager actually forgets the tab. """ mainlog.debug("Untabifying {} {}".format(ndx,panel)) if 0 <= ndx < len(self._registered_panels): if self._registered_panels[ndx] == panel: mainlog.debug("Untabified {} {}".format(ndx,panel)) del self._registered_panels[ndx] if ndx > 0: self.setCurrentIndex(ndx-1) self.removeTab(ndx) # QTabWidget has no ownership on the widget panel.close() # Important if we detach the panel from a tab to a window return mainlog.error("Unable to properly unregister panel")
def load(self, config_path, config_spec): self._config_file = config_path self._config_spec = config_spec config_path = os.path.normpath(os.path.join(os.getcwd(), config_path)) mainlog.info("Reading configuration file -> {}".format(config_path)) mainlog.debug( "Reading configuration spec file -> {}".format(config_spec)) if not os.path.exists(config_path): mainlog.error( "Configuration file not found at {}".format(config_path)) raise Exception( "Configuration file not found at {}".format(config_path)) try: self.base_configuration = configobj.ConfigObj( infile=config_path, configspec=config_spec, encoding='utf-8') except UnicodeDecodeError: mainlog.warn( "The encoding of the config file is not UTF-8. I'll try {}". format(locale.getpreferredencoding())) self.base_configuration = configobj.ConfigObj( infile=config_path, configspec=config_spec, encoding=locale.getpreferredencoding()) self.base_configuration.validate(validate.Validator()) if 'Programs' not in self.base_configuration or 'pdf_viewer' not in self.base_configuration[ 'Programs'] or not self.base_configuration['Programs'][ 'pdf_viewer'] or not os.path.exists( self.base_configuration['Programs']['pdf_viewer']): if platform.system() == 'Linux': self.base_configuration['Programs']['pdf_viewer'] = 'xpdf' else: self.base_configuration['Programs'][ 'pdf_viewer'] = os.path.join(resource_dir, 'SumatraPDF.exe')
def extend_enumeration(db_engine, enumeration : DeclEnum, symbol : EnumSymbol): # The following statement really wants to run outside of a transaction. # SO I have to use the raw_connection stuff to escape SQLA's autoamted # transaction management. # See enumeration type information # select enumtypid, typname, enumlabel from pg_enum join pg_type on pg_type.oid = pg_enum.enumtypid order by enumtypid, enumlabel; c = db_engine().raw_connection() cursor = c.cursor() cursor.execute("COMMIT") # Leave any pending transaction try: # Will fail on duplicates sql = "ALTER TYPE {} ADD VALUE '{}'".format(enumeration.db_type().impl.name, symbol.value) cursor.execute(sql) except Exception as ex: mainlog.info("Tried " + sql) mainlog.error(ex) cursor.close() c.close()
def check_active_postgres_connections(): # I need DB url because I didn't find a way to get that information # from the session(), connection()... # Rage hard, maxi vinyl with spoken words (super rare) mainlog.info( "check_active_postgres_connections : Trying to connect to the database" ) try: r = session().connection().execute( "SELECT count(*) from pg_stat_activity").scalar() mainlog.debug("Trying to connect to the database - 2") session().commit() mainlog.debug("Trying to connect to the database - 3") return r except exc.OperationalError as ex: mainlog.exception(ex) mainlog.error("Can't query the database !!! Is it connected ?") return False
def _panel_is_shown_in_tab(self,ndx): # When a tab is shown, we know it. But what we # don't know is what tab is hidden because of that. # QTabWidget doesn't say it. Therefore, I have # to mark all "other" tabs as inivisble (that's # a poor man solution, but tracking wich tab is # closed is a bit difficult) # mainlog.debug("_panel_is_shown_in_tab : ndx={}".format(ndx)) for i in range(len(self._registered_panels)): widget = self._registered_panels[i] if i != ndx and widget._panel_visible: widget.set_visibility(False) if 0 <= ndx < len(self._registered_panels): widget = self._registered_panels[ndx] # mainlog.debug("_panel_is_shown_in_tab : widget appears : {}".format(widget)) widget.set_visibility(True) else: mainlog.error("Could not show a tabbed panel (ndx={} of {})".format(ndx, len(self._registered_panels)))
def drop_entity( db_engine, session, entity): if isinstance(entity, DeclarativeMeta): drop_entity(db_engine, session, entity.__table__) elif isinstance(entity, Table): entity.drop(db_engine(), checkfirst=True) session().commit() elif isinstance(entity, DeclEnumMeta): entity.db_type().drop( bind=db_engine(), checkfirst=True) try: session().connection().execute("DROP TYPE IF EXISTS {}".format(entity.db_name())) session().commit() except Exception as ex: mainlog.exception(ex) mainlog.error("Could not : DROP TYPE {}".format(entity.db_name())) session().rollback() else: raise Exception("Unrecognized entity type : {}".format(type(entity))) session().commit()
def show_panel(self, panel): i = 0 for w in self._registered_panels: if w == panel: self._panel_is_shown_in_tab(i) self.setCurrentIndex(i) return w else: i += 1 # Check if the panel doesn't belong to a currently # detached window i = 0 for win in self.detached_windows: w = win.centralWidget() if w == panel: return w else: i += 1 mainlog.error("Trying to show a panel that is not managed")
def dump_and_zip_database(base_configuration): # login, password, dbname, host, port = _extract_db_params_from_url(base_configuration.get("Backup","db_url")) error = False if not base_configuration.get('Commands', 'pg_dump_cmd'): mainlog.error("Missing Commands/pg_dump_cmd in configuration file") error = True if not base_configuration.get('Backup', 'db_url'): mainlog.error("Missing Backup/db_url in configuration file") error = True if not base_configuration.get('Backup', 'prefix'): mainlog.error("Missing Backup/prefix in configuration file") error = True if not base_configuration.get('Backup', 'backup_directory'): mainlog.error("Missing Backup/backup_directory in configuration file") error = True if error: raise Exception("Too many errors, I stop here") filename = base_configuration.get("Backup", "prefix") + "_" + str( datetime.date.today()) + ".pgbackup" final_destination = os.path.join( base_configuration.get('Backup', 'backup_directory'), filename) # custom format will store more and is compressed command1 = [ base_configuration.get('Commands', 'pg_dump_cmd'), '--format=custom', '--file={}'.format(final_destination), base_configuration.get("Backup", "db_url") ] mainlog.info("Creating backup : {}".format(" ".join(command1))) p1 = subprocess.Popen(command1) p1.communicate() p1.wait() if p1.returncode != 0: raise Exception("Unable to run the backup command") else: mainlog.info("Backup seems fine") bytes = os.path.getsize(final_destination) mainlog.info("Backup complete, {} bytes saved".format(bytes)) return final_destination, bytes
def upgrade_file(path): global configuration re_file = re.compile(r'koi-delivery_slips-([0-9]+\.[0-9]+\.[0-9]+)\.zip') exe_filename = "{}/{}.exe".format(configuration.get("Globals", "codename"), configuration.get("Globals", "codename")) if os.path.exists(path): match = re_file.match(os.path.basename(path)) if match: version = match.groups()[0] candidates = [] exe_correct = False with zipfile.ZipFile(path, 'r') as zin: for item in zin.infolist(): if item.filename == exe_filename: exe_correct = True break elif ".exe" in item.filename: candidates.append(item.filename) if exe_correct: configuration.set("DownloadSite", "current_version", str(version)) configuration.set("DownloadSite", "client_path", path) configuration.save() mainlog.info( "Configuration successfully updated with delivery_slips version {}." .format(version)) mainlog.warning( "Don't forget to restart the server to take it into account !" ) return True else: mainlog.error( "Didn't find {} inside the file you've given. Possible candidates {}" .format(exe_filename, ", ".join(candidates))) else: mainlog.error( "I don't recognize the filename. It should be 'koi-delivery_slips-a.b.c.zip'." ) else: mainlog.error("The file {} was not found.".format(path)) return False
def json_rpc2(self): chrono_start() try: mainlog.debug("Dispatching JSON call {}".format( cherrypy.request.json)) result = json_rpc_dispatcher(cherrypy.request.json) # mainlog.debug("... success! Result is {}".format(str(result))) # Normally, exception handling is worked ou in the JsonRpc handler and # not in cherrypy except ServerException as ex: mainlog.error("Intercepted error ?") mainlog.error(cherrypy.request.json) mainlog.exception(u"[{}] {}".format(ex.code, ex.msg)) raise ex except Exception as ex: mainlog.error(cherrypy.request.json) mainlog.exception(ex) raise ex chrono_click() return result
def _draw_x_axis_dates(self, painter, l): def months_between(a,b): """ Nb of months, inclusive. """ if a > b: a,b = b,a if a.year == b.year: return b.month - a.month + 1 else: m = (12 - a.month + 1) + (b.month + 1) my = (b.year - a.year - 1) * 12 return m + my if not l or len(l) <= 2: return l fm = painter.fontMetrics() char_width = fm.boundingRect("9").width() nbchars = self.total_width / char_width nb_days = (l[-1] - l[0]).days if nb_days <= 10 and not self.x_axis_as_months: return l # mainlog.debug("Too many days") nb_months = months_between(l[0], l[-1]) if nb_months < (nbchars / len("MM/YY")): old_d = l[0] nl = [short_my(old_d)] # Will have the same length as l # print l[1:-1] for d in l[1:len(l)]: if d.month != old_d.month: if d.year != old_d.year: nl.append(short_my(d)) else: nl.append(str(d.month)) old_d = d else: nl.append("") if len(l) != len(nl): mainlog.error("something is wrong") return nl mainlog.debug("Too many months") nb_years = l[-1].year - l[0].year + 1 old_d = l[0] nl = [short_my(old_d)] # Will have the same length as l for d in l[1:len(l)]: if d.year != old_d.year: nl.append(short_my(d)) old_d = d else: nl.append("") return nl
parser.add_argument('--psql', default='psql.exe', help='Full path to psql') parser.add_argument('--configure-zip', help='Path to zip file') parser.add_argument('--host', help='Host') if __name__ == "__main__": args = parser.parse_args() if args.configure_zip: if args.host: mainlog.info("Configuring zip at {} with host {}".format( args.configure_zip, args.host)) configure_zip(args.configure_zip, args.host) sys.exit(0) else: mainlog.error("Missing host") sys.exit(1) app = QApplication(sys.argv) window = MainWindow() mainlog.addHandler(LoggerHandler(window)) # d = AskWindowsShare(None) # d.exec_() if args.reset_database: window.create_database() sys.exit(0) if args.create_root_account: window.create_root_account() sys.exit(0)
# p.fillRect(0,0,self.width(),self.height(), QColor(255,255,255,self.alpha)) pixmap = QPixmap(os.path.join(resource_dir,"client_splash.png")) splash = QSplashScreen(pixmap) splash.setMask(pixmap.mask()) # splash.setWindowFlags(Qt.WindowStaysOnTopHint) splash.show() splash_msg( u"{} - ".format(configuration.this_version) + _("Contacting updates server")) splash_msg( _("Loading database URL")) try: configuration.load_database_param() except Exception as e: mainlog.error(e) mainlog.error( "I was unable to get the DB URL from the server {}, so I'll continue with the file configuration".format( configuration.database_url_source)) showErrorBox( _("Can't connect to the main server"), _("I was unable to contact the main server (located here : {}). It is not 100% necessary to do so but that's not normal either. You should tell your administrator about that. I will now allow you to change the network address of the server I know in the preferences panel.").format( configuration.database_url_source)) splash.repaint() from datetime import datetime from PySide.QtCore import * from PySide.QtGui import * # from PySide.QtGui import QDesktopServices # from PySide.QtCore import QUrl # from PySide.QtTest import QTest
mainlog.setLevel(logging.DEBUG) else: mainlog.setLevel(logging.INFO) if args.make_config: if init_configuration(): exit(0) else: exit(-1) p = path_to_config("server.cfg") if os.path.exists(p): load_configuration_server(p, "server_config_check.cfg") else: mainlog.error( "Configuration file not found (looked here : {}). You should use --make-config." .format(p)) exit(-1) if args.demo_database: mainlog.warn( "Creating a demonstration database with {} orders ! This will destroy the current database." .format(args.demo_database)) create_demo_database(args.demo_database) exit(0) if args.reset_database: try: create_blank_database(configuration.get("Database", "admin_url"), configuration.get("Database", "url")) exit(0)