Exemple #1
0
 def __repr__(self):
     if self.focus_cle and self.focus_cle != '':
         return _('<Recherche Information Balisée \'{expr}\' DANS "{loc}">'
                  ).format(expr=self.expression_recherchee,
                           loc=self.focus_cle)
     return _('<Recherche Information Balisée \'{expr}\' PARTOUT>').format(
         expr=self.expression_recherchee)
Exemple #2
0
class RechercheInteretView(BaseAdminView):
    column_editable_list = ['est_obligatoire']
    column_filters = ['est_obligatoire']
    column_exclude_list = [
        'detecteurs', 'createur', 'responsable_derniere_modification'
    ]
    can_export = True
    can_view_details = False
    can_create = False
    can_edit = False
    can_delete = True
    edit_modal = False
    create_modal = False
    details_modal = True
    column_labels = dict(mapped_class_child='Type',
                         friendly_name='Résultat dans variable',
                         focus_cle='Recherche ciblée')
    column_formatters = dict(mapped_class_child=lambda a, b, c, d: str(c))
    column_display_pk = False

    column_descriptions = {
        'friendly_name':
        _('Si vous souhaitez conserver et exploiter le résultat de la règle dans votre automate, '
          'spécifiez un nom simple ici'),
        'mapped_class_child':
        _('Nom du type de la règle'),
        'focus_cle':
        _('Force le moteur à effectuer la recherche sur une partie restreinte de la source, laissez vide '
          'pour laisser le moteur rechercher PARTOUT.')
    }
Exemple #3
0
 def __repr__(self):
     if self.focus_cle and self.focus_cle != '':
         return _(
             '<Recherche Exactement \'{expr}\' DANS \'{loc}\'>').format(
                 expr=self.expression_cle, loc=self.focus_cle)
     return _('<Recherche Exactement \'{expr}\' PARTOUT>').format(
         expr=self.expression_cle)
Exemple #4
0
 def __repr__(self):
     if self.focus_cle and self.focus_cle != '':
         return _(
             '<Recherche Identifiant Préfixé \'{identifiant_prefixe}\' DANS \'{focus_cle}\'>'
         ).format(identifiant_prefixe=self.prefixe,
                  focus_cle=self.focus_cle)
     return _(
         '<Recherche Identifiant Préfixé \'{identifiant_prefixe}\' PARTOUT>'
     ).format(identifiant_prefixe=self.prefixe)
Exemple #5
0
def supprimer_action(automate_id, action_noeud_id):
    automate = db.session.query(Automate).get(automate_id)  # type: Automate
    action_noeud = db.session.query(ActionNoeud).filter_by(
        automate_id=automate_id, id=action_noeud_id).one()  # type: ActionNoeud

    if automate is None:
        return jsonify({
            'message':
            _('Aucun automate ne correspond à ID {id}').format(id=automate_id)
        }), 404
    if action_noeud is None:
        return jsonify({
            'message':
            _('Aucun action noeud ne correspond à ID {action_id} pour l\'automate ID {automate_id}'
              ).format(action_id=action_noeud_id, automate_id=automate_id)
        }), 404

    cascade_delete = request.form.get('cascade', default=0, type=int)

    if automate.action_racine_id == action_noeud.id:
        automate.action_racine_id = None
        automate.action_racine = None

    if cascade_delete > 0:
        db.session.delete(action_noeud)
    else:
        try:
            noeud_a_mettre_niveau_r = db.session.query(ActionNoeud).filter_by(
                automate_id=automate_id,
                action_reussite=action_noeud).one()  # type: ActionNoeud
        except NoResultFound:
            noeud_a_mettre_niveau_r = None

        try:
            noeud_a_mettre_niveau_f = db.session.query(ActionNoeud).filter_by(
                automate_id=automate_id,
                action_echec=action_noeud).one()  # type: ActionNoeud
        except NoResultFound:
            noeud_a_mettre_niveau_f = None

        if noeud_a_mettre_niveau_r is not None:
            noeud_a_mettre_niveau_r.action_reussite = action_noeud.action_reussite
            action_noeud.action_reussite = None

        if noeud_a_mettre_niveau_f is not None:
            noeud_a_mettre_niveau_f.action_echec = action_noeud.action_echec
            action_noeud.action_echec = None

        if noeud_a_mettre_niveau_r is None and noeud_a_mettre_niveau_f is None:
            automate.action_racine = action_noeud.action_reussite or action_noeud.action_echec

        db.session.delete(action_noeud)

    db.session.commit()
    db.session.flush()

    return jsonify({}), 204
Exemple #6
0
    def __repr__(self):
        if self.expression_gauche and self.expression_droite and self.expression_gauche != '' and self.expression_droite != '':
            return _('<Recherche Expression ENTRE \'{expr_gauche}\' ET \'{expr_droite}\' {loc}>').format(expr_gauche=self.expression_gauche, expr_droite=self.expression_droite, loc=_('PARTOUT') if self.focus_cle and self.focus_cle != '' else _('DANS \'{}\'').format(self.focus_cle))
        if self.expression_gauche and self.expression_gauche != '':
            return _('<Recherche Expression À DROITE DE \'{expr_gauche}\' {loc}>').format(expr_gauche=self.expression_gauche, loc=_('PARTOUT') if self.focus_cle and self.focus_cle != '' else _('DANS \'{}\'').format(self.focus_cle))
        if self.expression_droite and self.expression_droite != '':
            return _('<Recherche Expression À GAUCHE DE \'{expr_droite}\' {loc}>').format(expr_droite=self.expression_droite, loc=_('PARTOUT') if self.focus_cle and self.focus_cle != '' else _('DANS \'{}\'').format(self.focus_cle))

        return _('<Recherche Expression ENTRE \'{expr_gauche}\' ET \'{expr_droite}\' {loc}>').format(expr_gauche=self.expression_gauche, expr_droite=self.expression_droite, loc=_('PARTOUT') if self.focus_cle and self.focus_cle != '' else _('DANS \'{}\'').format(self.focus_cle))
Exemple #7
0
class AutomateView(BaseAdminView):
    column_editable_list = ['production', 'notifiable']
    column_searchable_list = ['designation', 'production']
    column_exclude_list = [
        'action_racine', 'date_creation', 'createur',
        'responsable_derniere_modification'
    ]
    column_details_exclude_list = None
    column_filters = ['designation']
    form_excluded_columns = [
        'actions', 'action_racine', 'createur', 'date_creation',
        'date_modification', 'responsable_derniere_modification'
    ]
    can_export = True
    can_view_details = False
    can_create = True
    can_edit = True
    can_delete = True
    edit_modal = True
    create_modal = True
    details_modal = True

    column_descriptions = {
        'detecteur':
        _('Associe un détecteur, qui si résolu avec une source permet de lancer votre suite d\'action'
          ),
        'designation':
        _('Description courte de ce que réalise votre automate, un objectif'),
        'production':
        _('Si cette case est cochée, votre automate sera executé en production'
          ),
        'priorite':
        _('Un entier à partir de 0 (Zéro) permettant de priviligier une execution '
          'd\'automate par rapport à un autre sur une source. De plus la priorité est proche de 0 (Zéro), '
          'de plus il est prioritaire'),
        'notifiable':
        _('Active les notifications en cas d\'échec d\'au moins une des actions de votre automate'
          )
    }

    def on_model_change(self, form, model, is_created):
        """
        :param form:
        :param hermes_ui.models.automate.Automate model:
        :param bool is_created:
        :return:
        """
        if is_created is True:
            model.createur = current_user
            model.date_creation = datetime.now()

        model.date_modification = datetime.now()
        model.responsable_derniere_modification = current_user
Exemple #8
0
def simulation_detecteur():

    detecteur_id = request.form.get('detecteur_id', type=int, default=None)

    sujet = request.form.get('sujet', type=str, default=None)
    corps = request.form.get('corps', type=str, default=None)

    if sujet is None:
        return jsonify({
            'message':
            _('Formulaire incomplet, manque le sujet de la source')
        }), 400
    if corps is None:
        return jsonify({
            'message':
            _('Formulaire incomplet, manque le corps de la source')
        }), 400

    if detecteur_id is None:
        return jsonify({
            'message':
            _('Formulaire incomplet, manque l\'identifiant du detecteur cible à tester'
              )
        }), 400

    detecteur = db.session.query(Detecteur).get(
        detecteur_id)  # type: Detecteur

    if detecteur is None:
        return jsonify({
            'message':
            _('Impossible de trouver le detecteur n°{n}').format(
                n=str(detecteur_id))
        }), 404

    from hermes.source import Source as SourceNatif

    k = detecteur.transcription()

    d = SourceNatif(sujet, corps)

    k.lance_toi(d)

    return jsonify({
        'explications': k.explain(),
        'interets': d.extraction_interet.interets
    }), 200 if k.est_accomplis is True else 409
Exemple #9
0
def lecture_automate(automate_id):
    automate = db.session.query(Automate).get(automate_id)  # type: Automate
    if automate is None:
        return jsonify({
            'message':
            _('Aucun automate ne correspond à ID {id}').format(id=automate_id)
        }), 404
    return AutomateSchema().jsonify(automate), 200
Exemple #10
0
class ExpressionDansCleRechercheInteretView(BaseAdminView):
    column_editable_list = ['est_obligatoire']
    column_searchable_list = [
        'designation', 'expression_recherchee', 'est_obligatoire'
    ]
    column_exclude_list = ['mapped_class_child', 'focus_cle']
    column_details_exclude_list = None
    column_filters = [
        'designation', 'expression_recherchee', 'est_obligatoire'
    ]
    form_excluded_columns = [
        'createur', 'date_creation', 'focus_cle', 'date_modification',
        'responsable_derniere_modification', 'mapped_class_child'
    ]
    can_export = True
    can_view_details = False
    can_create = True
    can_edit = True
    can_delete = True
    edit_modal = True
    create_modal = True
    details_modal = True
    column_labels = dict(friendly_name=_('Résultat dans variable'))

    column_descriptions = {
        'friendly_name':
        _('Si vous souhaitez conserver et exploiter le résultat de la règle dans votre automate, '
          'spécifiez un nom simple ici')
    }

    def on_model_change(self, form, model, is_created):
        """

        :param form:
        :param hermes_ui.models.configuration.Configuration model:
        :param bool is_created:
        :return:
        """
        if is_created is True:
            model.createur = current_user
            model.date_creation = datetime.now()
            model.mapped_class_child = str(model.__class__)

        model.date_modification = datetime.now()
        model.responsable_derniere_modification = current_user
Exemple #11
0
def simulation_extraction_interet():
    sujet = request.form.get('sujet', type=str, default=None)
    corps = request.form.get('corps', type=str, default=None)

    if sujet is None:
        return jsonify({
            'message':
            _('Formulaire incomplet, manque le sujet de la source')
        }), 409
    if corps is None:
        return jsonify({
            'message':
            _('Formulaire incomplet, manque le corps de la source')
        }), 409

    mon_extraction_interet = ExtractionInteret(sujet, corps)

    return jsonify(mon_extraction_interet.interets), 201
Exemple #12
0
def creation_test_service():
    automate_id = request.form.get('automate_id', type=int, default=None)

    if automate_id is None:
        return jsonify({}), 400

    if InstanceInteroperabilite.current_thread is not None:
        return jsonify({
            'message':
            _("L'environnement de test nécessite que le traitement des flux soit désactivé."
              )
        }), 409

    automate = db.session.query(Automate).get(automate_id)  # type: Automate

    if automate is None:
        return jsonify({
            'message':
            _('Aucun automate ne correspond à ID {id}').format(id=automate_id)
        }), 404

    if automate.production is True:
        return jsonify({
            'message':
            _('Votre automate ne doit pas être en mode production.')
        }), 409

    InstanceInteroperabilite.liste_attente_test_lock.acquire(blocking=True)

    if automate_id in InstanceInteroperabilite.liste_attente_test:
        InstanceInteroperabilite.liste_attente_test_lock.release()
        return jsonify({
            'message':
            _("Votre automate est toujours en attente d'être testé. Veuillez patienter."
              )
        }), 409

    InstanceInteroperabilite.liste_attente_test.append(automate_id)
    InstanceInteroperabilite.liste_attente_test_lock.release()

    demarrage = InstanceInteroperabilite.demarrer()

    return jsonify({}), 201 if demarrage is True else 409
Exemple #13
0
def lecture_action_automate(automate_id, action_noeud_id):
    action = db.session.query(ActionNoeud).filter_by(
        automate_id=automate_id, id=action_noeud_id).one()  # type: ActionNoeud

    if action is None:
        return jsonify({}), 404

    decompose_type_action = action.mapped_class_child.split(
        "'")  # type: list[str]

    if len(decompose_type_action) != 3 or not decompose_type_action[
            -2].startswith('hermes_ui.models.'):
        return jsonify({
            'message':
            _('Type d\'action illégale à la création: "{action_type}"').format(
                action_type=decompose_type_action[-2])
        }), 409

    target_module = modules['.'.join(
        decompose_type_action[-2].split('.')[0:-1])]

    try:
        target_model_class = getattr(target_module,
                                     decompose_type_action[-2].split('.')[-1])
    except AttributeError as e:
        return jsonify({
            'message':
            _('Le type d\'action demandé à la création est inexistant: {action_type}'
              ).format(action_type=decompose_type_action[-2].split('.')[-1])
        }), 400

    target_sub_action = db.session.query(target_model_class).filter_by(
        automate_id=automate_id, id=action_noeud_id).one()  # type: ActionNoeud

    for schema_action_noeud_class in ActionNoeudSchema.__subclasses__():

        if str(schema_action_noeud_class).split('.')[-1][0:-2].startswith(
                str(target_model_class).split('.')[-1][0:-2]):
            return schema_action_noeud_class().jsonify(target_sub_action), 200

    return ActionNoeudSchema().jsonify(target_sub_action), 200
Exemple #14
0
def assistance_saisie_automate(automate_id):
    automate = db.session.query(Automate).get(automate_id)

    if automate is None:
        return jsonify({
            'message':
            _('Impossible de proposer la liste des variables disponibles pour un automate inexistant'
              )
        })

    propositions = list()

    for el in automate.detecteur.regles:  # type: RechercheInteret
        if el.friendly_name is not None and el.friendly_name != '':
            propositions.append('{{' + el.friendly_name + '}}')

    for el in automate.actions:  # type: ActionNoeud
        if el.friendly_name is not None and el.friendly_name != '':
            propositions.append('{{' + el.friendly_name + '}}')

    return jsonify(propositions), 200
Exemple #15
0
class InformationRechercheInteretView(BaseAdminView):
    column_editable_list = ['est_obligatoire']
    column_searchable_list = [
        'designation', 'information_cible', 'est_obligatoire'
    ]
    column_exclude_list = ['mapped_class_child']
    column_details_exclude_list = None
    column_filters = ['designation', 'information_cible', 'est_obligatoire']
    form_excluded_columns = [
        'createur', 'date_creation', 'date_modification',
        'responsable_derniere_modification', 'mapped_class_child'
    ]
    can_export = True
    can_view_details = False
    can_create = True
    can_edit = True
    can_delete = True
    edit_modal = True
    create_modal = True
    details_modal = True
    column_labels = dict(friendly_name=_('Résultat dans variable'),
                         focus_cle=_('Recherche ciblée'))

    column_descriptions = {
        'friendly_name':
        _('Si vous souhaitez conserver et exploiter le résultat de la règle dans votre automate, '
          'spécifiez un nom simple ici'),
        'focus_cle':
        _('Force le moteur à effectuer la recherche sur une partie restreinte de la source, laissez vide '
          'pour laisser le moteur rechercher PARTOUT.')
    }

    form_choices = {
        'focus_cle':
        [('titre', _('Uniquement dans le TITRE')),
         ('corpus', _('Uniquement dans le CORPS')),
         ('expediteur', _('Dans le champ expéditeur du message')),
         ('destinataire', _('Dans le champ destinataire du message')),
         ('hyperliens', _('Dans la liste des URLs découvertes')),
         ('pieces-jointes', _('Dans la liste des noms des pièces jointes')),
         ('pieces-jointes-types',
          _('Dans la liste des formats MIME des pièces jointes'))],
    }

    def on_model_change(self, form, model, is_created):
        """

        :param form:
        :param hermes_ui.models.configuration.Configuration model:
        :param bool is_created:
        :return:
        """
        if is_created is True:
            model.createur = current_user
            model.date_creation = datetime.now()
            model.mapped_class_child = str(model.__class__)

        model.date_modification = datetime.now()
        model.responsable_derniere_modification = current_user
Exemple #16
0
def simulation_detecteur_fichier():
    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/octet-stream'
            and mon_fichier.content_type != 'message/rfc822') or (
                mon_fichier.filename.endswith('.eml') is False
                and mon_fichier.filename.endswith('.msg') is False):
        return jsonify({
            'message':
            _('Fichier message invalide, fichier binaire *.EML ou *.MSG requis !'
              )
        }), 400

    if mon_fichier.filename.endswith('.eml') is True:
        mon_message = Mail.from_eml(mon_fichier.stream.read())
    else:
        mon_message = Mail.from_msg(mon_fichier.stream.read())

    detecteurs = db.session.query(Detecteur).all()

    ob_detecteurs = list()
    ma_reponse_html = str()

    ma_reponse_html += """
    <div class="panel box box-warning">
      <div class="box-header with-border">
        <h4 class="box-title">
          <a data-toggle="collapse" data-parent="#accordion" href="#collapse-x" aria-expanded="false" class="">
            Ce que le moteur perçoit
          </a>
        </h4>
      </div>
      <div id="collapse-x" class="panel-collapse collapse" aria-expanded="false" style="">
        <div class="box-body">
            <pre>
    <code class="json">
{perception_moteur}
    </code>
            </pre>
        </div>
      </div>
    </div>""".format(perception_moteur=dumps(
        mon_message.extraction_interet.interets, indent=4, ensure_ascii=False))

    for detecteur, i in zip(detecteurs, range(0, len(detecteurs))):
        ob_detecteurs.append(detecteur.transcription())
        try:
            ob_detecteurs[-1].lance_toi(mon_message)
        except AucuneObligationInteretException as e:
            continue

        ma_reponse_html += """
<div class="panel box {box_color}">
  <div class="box-header with-border">
    <h4 class="box-title">
      <a data-toggle="collapse" data-parent="#accordion" href="#collapse{i_row}" aria-expanded="false" class="">
        {detecteur_res}
      </a>
    </h4>
  </div>
  <div id="collapse{i_row}" class="panel-collapse collapse" aria-expanded="false" style="">
    <div class="box-body">
        <pre>
<code>
{detecteur_explications}
</code>
        </pre>
    </div>
  </div>
</div>""".format(
            detecteur_res=str(ob_detecteurs[-1]),
            detecteur_explications=ob_detecteurs[-1].explain(),
            box_color="box-success"
            if ob_detecteurs[-1].est_accomplis else 'box-danger',
            i_row=str(i),
        )

    return Response(ma_reponse_html, status=200, content_type='text/html')
Exemple #17
0
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
Exemple #18
0
    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
Exemple #19
0
 def __repr__(self):
     if self.focus_cle and self.focus_cle != '':
         return _('<Recherche REGEX \'{expr}\' DANS \'{loc}\'>').format(expr=self.expression_reguliere, loc=self.focus_cle)
     return _('<Recherche REGEX \'{expr}\' PARTOUT>').format(expr=self.expression_reguliere)
Exemple #20
0
babel = Babel(app)

project = WebpackTemplateProject(
    __name__,
    project_folder='assets',
    config_path='assets/config.json',
)

app.config.update(dict(WEBPACKEXT_PROJECT=project, ))

# Initialize extension
FlaskWebpackExt(app)

admin = AdminLte(app,
                 skin='green-light',
                 name=_('Hermes - Automates à réaction aux échanges IMAP'),
                 short_name="<b>H</b><sup>ermes</sup>",
                 long_name="<b>Hermes</b>",
                 index_view=AdminIndexView(name=_("Éditeur d'Automate"),
                                           menu_icon_value='fa-pencil',
                                           menu_icon_type='fa'))

db.init_app(app)
migrate = Migrate(app, db)
ma = Marshmallow(app)
NotificationIncident.init_app(app)

admin.add_view(
    BoiteAuxLettresImapView(BoiteAuxLettresImap,
                            db.session,
                            name=_("Boite aux lettres (IMAP)"),
Exemple #21
0
 def __repr__(self):
     return _('<Recherche DE \'{nom}\'>').format(nom=self.designation)
Exemple #22
0
 def __repr__(self):
     return _('<Opération sur Critère(s) {operande} "{nom}">').format(operande=self.operande, nom=self.designation)
Exemple #23
0
 def __repr__(self):
     return _('<Recherche Clé Auto-Découverte \'{loc}\'>').format(loc=self.cle_recherchee)
Exemple #24
0
 def __repr__(self):
     return _('<Détection DE \'{detecteur_nom}\'>').format(detecteur_nom=self.designation)
Exemple #25
0
def modification_action(automate_id, action_noeud_id):
    automate = db.session.query(Automate).get(automate_id)  # type: Automate
    action_noeud = db.session.query(ActionNoeud).filter_by(
        automate_id=automate_id,
        id=action_noeud_id).first()  # type: ActionNoeud

    if not request.is_json:
        return jsonify(
            {'message':
             _('Aucun corps JSON présent dans la requête HTTP')}), 400

    if automate is None:
        return jsonify({
            'message':
            _('Aucun automate ne correspond à ID {id}').format(id=automate_id)
        }), 404
    if action_noeud is None:
        return jsonify({
            'message':
            _('Aucun action noeud ne correspond à ID {action_id} pour l\'automate ID {automate_id}'
              ).format(action_id=action_noeud_id, automate_id=automate_id)
        }), 404

    payload = request.json  # type: dict

    if 'type' not in payload.keys() or 'formulaire' not in payload.keys():
        return jsonify(
            {'message':
             _('Le JSON présent dans la requête est invalide')}), 400

    type_action = payload['type']
    formulaire = payload['formulaire']  # type: dict

    decompose_type_action = type_action.split("'")  # type: list[str]

    target_module = modules['.'.join(
        decompose_type_action[-2].split('.')[0:-1])]

    target_model_class = getattr(target_module,
                                 decompose_type_action[-2].split('.')[-1])
    target_model_instance = db.session.query(target_model_class).get(
        action_noeud.id)  # type: ActionNoeud

    for key_attr in formulaire.keys():
        try:
            getattr(target_model_instance, key_attr)
        except AttributeError as e:
            return jsonify({'message': str(e)}), 409

        if key_attr in target_model_class.PARAMETRES.keys(
        ) and target_model_class.PARAMETRES[key_attr]['format'] == 'CHECKBOX':
            formulaire[key_attr] = True if formulaire[key_attr] == 1 else False

        if isinstance(formulaire[key_attr], str) and len(
                formulaire[key_attr].strip()
        ) == 0 and key_attr in target_model_class.PARAMETRES.keys(
        ) and target_model_class.PARAMETRES[key_attr]['required'] is False:
            formulaire[key_attr] = None

        setattr(target_model_instance, key_attr, formulaire[key_attr])

    try:
        db.session.commit()
        db.session.flush()
    except IntegrityError as e:
        return jsonify({'message': str(e)}), 409

    return jsonify({}), 200
Exemple #26
0
 def __repr__(self):
     if self.focus_cle and self.focus_cle != '':
         return _('<Recherche Date \'{prefixe}\' DANS \'{loc}\'>').format(prefixe=self.prefixe, loc=self.focus_cle)
     return _('<Recherche Date \'{prefixe}\' PARTOUT>').format(prefixe=self.prefixe)
Exemple #27
0
 def __repr__(self):
     return _('<Recherche XPath \'{expr_xpath}\' DANS CORPS HTML>').format(expr_xpath=self.expression_xpath)
Exemple #28
0
def creation_action(automate_id):
    automate = db.session.query(Automate).get(automate_id)  # type: Automate

    if not request.is_json:
        return jsonify(
            {'message':
             _('Aucun corps JSON présent dans la requête HTTP')}), 400

    if automate is None:
        return jsonify({
            'message':
            _('Aucun automate ne correspond à ID {id}').format(id=automate_id)
        }), 404

    payload = request.json  # type: dict

    if 'type' not in payload or (
            'parent' not in payload
            and 'remplacement' not in payload) or 'formulaire' not in payload:
        return jsonify(
            {'message':
             _('Le JSON présent dans la requête est invalide')}), 400

    type_action = payload['type']
    parent_information = payload['parent'] if 'parent' in payload else None
    remplacement_action_noeud = payload[
        'remplacement'] if 'remplacement' in payload else None
    formulaire = payload['formulaire']

    decompose_type_action = type_action.split("'")  # type: list[str]

    if len(decompose_type_action) != 3 or not decompose_type_action[
            -2].startswith('hermes_ui.models.'):
        return jsonify({
            'message':
            _('Type d\'action illégale à la création: "{action_type}"').format(
                action_type=decompose_type_action[-2])
        }), 409

    target_module = modules['.'.join(
        decompose_type_action[-2].split('.')[0:-1])]

    try:
        target_model_class = getattr(target_module,
                                     decompose_type_action[-2].split(
                                         '.')[-1])  # type: type(ActionNoeud)
    except AttributeError as e:
        return jsonify({
            'message':
            _('Le type d\'action demandé à la création est inexistant: {action_type}'
              ).format(action_type=decompose_type_action[-2].split('.')[-1])
        }), 400

    for key_form in formulaire.keys():
        if isinstance(formulaire[key_form], str) and len(
                formulaire[key_form].strip()
        ) == 0 and key_form in target_model_class.PARAMETRES.keys(
        ) and target_model_class.PARAMETRES[key_form]['required'] is False:
            formulaire[key_form] = None

    try:
        target_model_instance = target_model_class(
            **formulaire)  # type: ActionNoeud
    except AttributeError as e:
        return jsonify({
            'message':
            _('Le formulaire de création est invalide, pour cause de "{msg_err}"'
              ).format(msg_err=str(e))
        }), 400

    target_model_instance.mapped_class_child = str(
        target_model_instance.__class__)

    target_model_instance.automate = automate
    target_model_instance.automate_id = automate.id

    target_model_instance.createur = current_user
    target_model_instance.responsable_derniere_modification = current_user

    target_model_instance.date_creation = datetime.datetime.now()
    target_model_instance.date_modification = datetime.datetime.now()

    try:
        db.session.add(target_model_instance)
        db.session.commit()
    except IntegrityError as e:
        return jsonify({'message': str(e)}), 409

    if remplacement_action_noeud is None:

        if parent_information is None:
            automate.action_racine = target_model_instance
        else:
            if len(parent_information) != 2:
                return jsonify({
                    'message':
                    _('Les informations de votre action parente sont malformés'
                      )
                }), 400

            action_parente_id, etat_reussite = tuple(parent_information)
            action_noeud_parente = db.session.query(ActionNoeud).filter_by(
                automate_id=automate_id,
                id=int(action_parente_id)).one()  # type: ActionNoeud

            if action_noeud_parente is None:
                return jsonify(
                    {'message': _('L\'action parente n\'existe pas !')}), 404

            if 'ECHEC' in parent_information:
                # cas simple de non ajout
                if action_noeud_parente.action_echec is None:
                    target_model_instance.action_echec_id = action_noeud_parente.id
                else:
                    # cas insertion dans arbre
                    action_deplacement = action_noeud_parente.action_echec

                    action_noeud_parente.action_echec = target_model_instance

                    target_model_instance.action_echec = action_deplacement

            elif 'REUSSITE' in parent_information:
                if action_noeud_parente.action_reussite is None:
                    target_model_instance.action_reussite_id = action_noeud_parente.id
                else:
                    # cas insertion dans arbre
                    action_deplacement = action_noeud_parente.action_reussite

                    action_noeud_parente.action_reussite = target_model_instance

                    target_model_instance.action_reussite = action_deplacement
    else:
        noeud_a_remplacer = db.session.query(ActionNoeud).filter_by(
            automate_id=automate_id,
            id=int(remplacement_action_noeud)).one()  # type: ActionNoeud

        if noeud_a_remplacer is None:
            return jsonify({
                'message':
                _("Le noeud que vous souhaitez remplacer est inexistant")
            }), 404

        target_model_instance.action_echec = noeud_a_remplacer.action_echec
        target_model_instance.action_reussite = noeud_a_remplacer.action_reussite

        noeud_a_remplacer.action_echec = None
        noeud_a_remplacer.action_reussite = None

        try:
            noeud_a_mettre_niveau_r = db.session.query(ActionNoeud).filter_by(
                automate_id=automate_id,
                action_reussite=noeud_a_remplacer).one()  # type: ActionNoeud
        except NoResultFound:
            noeud_a_mettre_niveau_r = None

        try:
            noeud_a_mettre_niveau_f = db.session.query(ActionNoeud).filter_by(
                automate_id=automate_id,
                action_echec=noeud_a_remplacer).one()  # type: ActionNoeud
        except NoResultFound:
            noeud_a_mettre_niveau_f = None

        if noeud_a_mettre_niveau_r is not None:
            noeud_a_mettre_niveau_r.action_reussite = target_model_instance

        if noeud_a_mettre_niveau_f is not None:
            noeud_a_mettre_niveau_f.action_echec = target_model_instance

        if noeud_a_mettre_niveau_r is None and noeud_a_mettre_niveau_f is None:
            automate.action_racine = target_model_instance

        db.session.delete(noeud_a_remplacer)

    try:
        db.session.commit()
        db.session.flush()
    except IntegrityError as e:
        return jsonify({'message': str(e)}), 409

    return jsonify({}), 201
Exemple #29
0
 def __repr__(self):
     return _('<Recherche Exactement \'{expr}\' DANS Clé Auto-Découverte "{loc}">').format(expr=self.expression_recherchee, loc=self.cle_recherchee)