def init_db(): logger.warning("Database will be created from scratch") db.drop_all() db.create_all() with app.app_context(): super_admin_role = Role(name='superadmin') admin_role = Role(name='admin') db.session.add(super_admin_role) db.session.add(admin_role) db.session.commit() test_user = admins_store.create_user( first_name='admin', last_name='hermes', email='hermes@localhost', password=hash_password('admin'), roles=[super_admin_role, admin_role]) db.session.add(test_user) db.session.commit() logger.info("Database has been created") return
def export_automates(): if 'file' not in request.files: return jsonify({'message': 'Aucun fichier envoyé'}), 400 mon_fichier = request.files['file'] # type: FileStorage if mon_fichier.content_type != 'application/json' or mon_fichier.filename.endswith( '.json') is False: return jsonify( {'message': _('Fichier message invalide, fichier JSON requis !')}), 400 def rec_(at, act): """ :param Automate at: :param ActionNoeud act: :return: """ act.automate_id = at.id if act.action_reussite is not None: rec_(at, act.action_reussite) if act.action_echec is not None: rec_(at, act.action_echec) db.session.query(ActionNoeudExecution).delete() db.session.query(RechercheInteretExecution).delete() db.session.query(AutomateExecution).delete() for sb in ActionNoeud.__subclasses__(): db.session.query(sb).delete() db.session.query(ActionNoeud).delete() db.session.query(Automate).delete() db.session.query(LienDetecteurRechercheInteret).delete() db.session.query(LienSousRegleOperationLogique).delete() for sb in RechercheInteret.__subclasses__(): db.session.query(sb).delete() db.session.query(RechercheInteret).delete() db.session.query(Detecteur).delete() db.session.commit() db.session.flush() try: from json import loads automates = AutomateLegacySchema(many=True).load( loads(mon_fichier.stream.read().decode( 'ascii'))) # type: list[Automate] except MarshmallowError as e: return jsonify({ 'message': _("Impossible d'importer votre fichier '{fname}' car votre fichier ne respecte pas la structure JSON obligatoire ! '{msg_err}'." ).format(fname=mon_fichier.filename, msg_err=str(e)) }), 409 for automate in automates: try: act_r = deepcopy(automate.action_racine) automate.action_racine = None automate.createur = current_user automate.responsable_derniere_modification = current_user automate.detecteur.createur = current_user automate.detecteur.responsable_derniere_modification = current_user for rg in automate.detecteur.regles: ri_ex = db.session.query(RechercheInteret).filter_by( designation=rg.designation, mapped_class_child=rg.mapped_class_child).first() if ri_ex is not None: automate.detecteur.regles[automate.detecteur.regles.index( rg)] = ri_ex db.session.add(automate) db.session.commit() if act_r is not None: rec_(automate, act_r) automate.action_racine = act_r db.session.commit() except SQLAlchemyError as e: logger.error(_( "Impossible d'importer votre automate '{automate_nom}' car une erreur de transposition en base de données est survenue '{msg_err}'." ), automate_nom=automate.designation, msg_err=str(e)) continue try: db.session.flush() except SQLAlchemyError as e: logger.warning(_("Erreur SQL '{err_msg}'."), err_msg=str(e)) return jsonify({ 'message': _('Erreur de transaction SQL : {err_msg}').format(err_msg=str(e)) }), 409 return jsonify({}), 204
test_user = admins_store.create_user( first_name='admin', last_name='hermes', email='hermes@localhost', password=hash_password('admin'), roles=[super_admin_role, admin_role]) db.session.add(test_user) db.session.commit() return try: db.session.query(Role).all() except NoReferencedTableError as e: init_db() except NoSuchTableError as e: init_db() except OperationalError as e: init_db() except ProgrammingError as e: init_db() except Exception as e: logger.warning(_( 'Exception générique attrapée lors de la requête de test schéma. "{msg_err}"' ), msg_err=str(e)) init_db()
def thread(): logger.info(_("Chargement des variables globales passées en base de données")) configurations = db.session.query(Configuration).all() # type: list[Configuration] for configuration in configurations: logger.info(_("Chargement de la configuration <'{conf_nom}'::{conf_format}>"), conf_nom=configuration.designation, conf_format=configuration.format) try: Session.charger_input( configuration.designation, configuration.valeur, configuration.format ) except TypeError as e: logger.error(_("Impossible de charger la configuration <'{conf_nom}'::{conf_format}> car '{error_msg}'"), conf_nom=configuration.designation, conf_format=configuration.format, error_msg=str(e)) logger.info(_("Démarrage de la boucle de surveillance des automates sur les boîtes IMAP4")) InstanceInteroperabilite.liste_attente_test_lock.acquire() est_une_sequence_test = len(InstanceInteroperabilite.liste_attente_test) > 0 if not est_une_sequence_test: InstanceInteroperabilite.liste_attente_test_lock.release() while InstanceInteroperabilite.stop_instruction is None: boites_aux_lettres = db.session.query(BoiteAuxLettresImap).all() # type: list[BoiteAuxLettresImap] mail_factories = [] for el in boites_aux_lettres: try: mail_factories.append( el.get_mailtoolbox() ) except LoginError as e: logger.error(_("Impossible de démarrer l'usine " "à production de source '{designation}' car '{msg_err}'"), designation=el.designation, msg_err=str(e)) except Exception as e: logger.error(_("Impossible de démarrer l'usine " "à production de source '{designation}' car '{msg_err}'"), designation=el.designation, msg_err=str(e)) if len(mail_factories) == 0: logger.warning(_("Aucune usine à production de source n'est active, impossible de continuer")) break logger.debug(_("{n} usine(s) à production de source sont actives"), n=len(mail_factories)) if est_une_sequence_test: models_automates = db.session.query(Automate).filter_by(production=False).all() # type: list[Automate] else: models_automates = db.session.query(Automate).filter_by(production=True).all() # type: list[Automate] models_automates.sort(key=lambda x: x.priorite, reverse=True) if len(models_automates) == 0: logger.warning( _("Aucune automate à traitement de source n'est actif, impossible de continuer")) break logger.debug(_("{n} automates en production sont actifs"), n=len(models_automates)) for mail_factory in mail_factories: logger.debug(_("Ouverture de la BAL '{nom_utilisateur}'@'{hote_imap}'"), nom_utilisateur=mail_factory.nom_utilisateur, hote_imap=mail_factory.hote_imap) if InstanceInteroperabilite.stop_instruction is not None: logger.info(_("Arrêt de la surveillance continue des BAL")) return sources = mail_factory.extraire() logger.debug(_("{n} sources ont été extraites de l'usine à production '{usine}'"), n=len(sources), usine=str(mail_factory)) for source in sources: logger.debug(_("Vérification du message électronique '{source_nom}'"), source_nom=source.titre) for model in models_automates: automate = model.transcription() if InstanceInteroperabilite.stop_instruction is not None: logger.info(_("Arrêt de la surveillance continue des BAL")) return if est_une_sequence_test and model.id not in InstanceInteroperabilite.liste_attente_test: logger.debug(_("Séquence de test ne conserne pas '{automate_nom}'."), automate_nom=model.designation) continue date_depart_automate = datetime.now() # On vérifie les conditions pour anti-spam nb_execution_heure = db.session.query(AutomateExecution).filter( AutomateExecution.automate == model, AutomateExecution.sujet == source.titre, AutomateExecution.corps == source.corps, # AutomateExecution.validation_automate == False, AutomateExecution.date_creation >= (date_depart_automate - timedelta(hours=1)) ).count() if nb_execution_heure >= (model.limite_par_heure if model.limite_par_heure is not None else 100): logger.warning( _("L'automate '{automate_nom}' ne va pas traiter la source '{source_nom}' car celle ci " "dépasse la limite de {n} lancement(s) par heure."), automate_nom=automate.designation, source_nom=source.titre, n=(model.limite_par_heure if model.limite_par_heure is not None else 100) ) continue nb_execution_echec_heure = db.session.query(AutomateExecution).filter( AutomateExecution.automate == model, AutomateExecution.sujet == source.titre, AutomateExecution.corps == source.corps, AutomateExecution.validation_automate == False, AutomateExecution.date_creation >= (date_depart_automate - timedelta(hours=1)) ).count() if nb_execution_echec_heure >= (model.limite_echec_par_heure if model.limite_echec_par_heure is not None else 10): logger.warning( _("L'automate '{automate_nom}' ne va pas traiter la source '{source_nom}' car celle ci " "dépasse la limite en échec de {n} lancement(s) par heure."), automate_nom=automate.designation, source_nom=source.titre, n=(model.limite_echec_par_heure if model.limite_echec_par_heure is not None else 10) ) continue try: etat_final_automate = automate.lance_toi(source) if etat_final_automate is True: logger.info( _("L'automate '{automate_nom}' vient de traiter avec succès la source '{source_nom}'"), automate_nom=automate.designation, source_nom=source.titre ) elif etat_final_automate is False and automate.detecteur.est_accomplis is True: logger.warning( _("L'automate '{automate_nom}' vient de traiter avec au moins une erreur la source '{source_nom}'"), automate_nom=automate.designation, source_nom=source.titre ) if model.notifiable is True: NotificationIncident.prevenir( model, source, _("L'automate '{automate_nom}' n'a pas réussi à aboutir, au moins une action est en échec").format(automate_nom=automate.designation), _("Vous recevez ce message car votre automate '{automate_nom}' est configurée " "pour émettre une notification dans ce cas. \n\n" "En PJ les élements nécessaires à l'analyse des évènements. " "L'automate est toujours actif. \n\n").format( automate_nom=automate.designation, ) ) except AucuneObligationInteretException as e: logger.error( _("L'automate '{automate_nom}' ne dispose pas d'un détecteur contraignant, " "il est nécessaire d'avoir au moins une règle avec obligation. " "Désactivation de l'automate."), automate_nom=automate.designation ) model.production = False db.session.commit() db.session.flush() continue except KeyError as e: logger.error( _("L'automate '{automate_nom}' est en erreur grave, " "une variable est non résolue: '{err_msg}'"), automate_nom=automate.designation, err_msg=str(e) ) NotificationIncident.prevenir( model, source, _("L'automate '{automate_nom}' est en erreur grave, une variable est non résolue !").format( automate_nom=automate.designation), _("Vous recevez ce message car votre automate '{automate_nom}' n'est pas en mesure d'aboutir. \n\n" "Une variable est non résolue. Veuillez revenir en conception. " "L'automate <b>a été désactivé</b> par précaution. \n\n" "Information technique: \n\n" "<pre class='code code-html'><label></label><code>{msg_err}</code></pre>").format( automate_nom=automate.designation, msg_err=str(e) ) ) model.production = False db.session.commit() db.session.flush() continue except Exception as e: from sys import exc_info from os import path import traceback exc_type, exc_obj, exc_tb = exc_info() logger.critical( _("L'automate '{automate_nom}' est en erreur critique, " "une exception est soulevée: '{msg_err}'"), automate_nom=automate.designation, msg_err=str(e) ) fname = path.split(exc_tb.tb_frame.f_code.co_filename)[1] logger.critical( _("Informations complémentaires '{exc_type}', '{fname}' à la ligne {lineno}."), exc_type=str(exc_type), fname=str(fname), lineno=str(exc_tb.tb_lineno) ) logger.critical( traceback.format_exc() ) NotificationIncident.prevenir( model, source, _("L'automate '{automate_nom}' est en erreur critique, une exception est soulevée !").format(automate_nom=automate.designation), _("Vous recevez ce message car votre automate '{automate_nom}' n'est pas en mesure d'aboutir. \n\n" "Une exception est non résolue. Veuillez revenir en conception. " "L'automate a été désactivé par précaution. \n\n" "Information technique: \n\n" "<pre class='code code-html'><label>Logs</label><code>{msg_err}</code></pre>").format(automate_nom=automate.designation, msg_err=traceback.format_exc()) ) model.production = False db.session.commit() db.session.flush() continue if automate.detecteur.est_accomplis is True: automate_execution = AutomateExecution( automate=model, sujet=source.titre if len(source.titre) < 255 else source.titre[1:250]+'..', corps=source.corps, date_creation=date_depart_automate, detecteur=model.detecteur, validation_detecteur=automate.detecteur.est_accomplis, validation_automate=etat_final_automate, explications_detecteur=automate.detecteur.explain(), date_finalisation=datetime.now(), logs=automate.logs ) for action_lancee in automate.actions_lancees: action_noeud_execution = ActionNoeudExecution( automate_execution=automate_execution, action_noeud=db.session.query(ActionNoeud).filter_by(designation=action_lancee.designation, automate_id=model.id).one(), validation_action_noeud=action_lancee.est_reussite, payload=str(action_lancee.payload), args_payload=dumps(action_lancee.snapshot) ) db.session.add(action_noeud_execution) db.session.add(automate_execution) db.session.commit() break # La source a été traitée. Pas besoin d'y appliquer un autre automate. db.session.flush() if est_une_sequence_test: InstanceInteroperabilite.liste_attente_test.clear() InstanceInteroperabilite.liste_attente_test_lock.release() break sleep(1 if len(mail_factories) > 0 else 10) logger.info(_("Fin de surveillance continue des automates sur les boîtes IMAP4")) InstanceInteroperabilite.current_thread = None