from pymongo import MongoClient import pymongo import json from flask import Flask, request, jsonify #from flask_mongoengine import MongoEngine import json from bson import ObjectId import re import numpy as np import ela_index_bdd_classes as ela_index import logging from datetime import datetime import prj_common as mycommon import secrets from pymongo import ReturnDocument import inspect import sys, os import csv import pandas as pd from unidecode import unidecode import GlobalVariable as MYSY_GV class JSONEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, ObjectId): return str(o) print(self) print(o) return json.JSONEncoder.default(self, o) def get_recherche_gle_class(sentence): try: if not sentence: return False #mycommon.myprint(" On recehrche la phrase +'"+sentence+"'") tab_training = [] tab_training = ela_index.ela_recherche_tokens(sentence) ''' pour analyser la recherche, decommenter les 2 lignes ci-dessous ''' #mycommon.myprint(" pour phrase : #"+sentence+"#, voici la liste des formations") #mycommon.myprint(tab_training) coll_name = MYSY_GV.dbname['myclass'] insertObject = [] for x in coll_name.find({"external_code": {"$in": tab_training}, 'published':'1'}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }): mycommon.myprint(x) user = x insertObject.append(JSONEncoder().encode(user)) # mycommon.myprint(" insertObject = ", insertObject) return insertObject except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False def get_class_by_list_attr(attribut, list_values): try: ela_array = [] ela_array = list_values.split(",") mycommon.myprint(" attribut"+ attribut+" ==> list_values = "+ela_array) coll_name = MYSY_GV.dbname['myclass'] insertObject = [] for x in coll_name.find({attribut:{ "$in":ela_array}, 'published':'1'},{"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }): mycommon.myprint(x) user = x insertObject.append(JSONEncoder().encode(user)) #mycommon.myprint(" insertObject = ", insertObject) return insertObject except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False def update_class_by_attribut(objId, attribut, value): try: mycommon.myprint("objId = "+objId+" attribut "+attribut+" value = "+value) coll_name = MYSY_GV.dbname['myclass'] insertObject = [] for x in coll_name.find({attribut: value, 'published':'1'}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }): mycommon.myprint(x) user = x insertObject.append(JSONEncoder().encode(user)) mycommon.myprint(" insertObject = "+ insertObject) return insertObject except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False def get_all_class(diction): try: # Dictionnaire des champs utilisables field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city', 'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif', 'support', 'type', 'lang', 'price', 'distance', 'duration', 'cpf', 'connection_type'] incom_keys = diction.keys() ''' # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste # field_list. ''' for val in incom_keys: if str(val).lower() not in str(field_list).lower(): mycommon.myprint(str(inspect.stack()[0][3]) + " Le champ '" + val + "' n'est pas autorisé") return False, " Recherche impossible" # Recuperation des parametres mydata = {} if ("user_ip" in diction.keys()): if diction['user_ip']: mydata['user_ip'] = diction['user_ip'] if ("user_country_code" in diction.keys()): if diction['user_country_code']: mydata['user_country_code'] = diction['user_country_code'] if ("user_country_name" in diction.keys()): if diction['user_country_name']: mydata['user_country_name'] = diction['user_country_name'] if ("user_city" in diction.keys()): if diction['user_city']: mydata['user_city'] = diction['user_city'] if ("user_postal" in diction.keys()): if diction['user_postal']: mydata['user_postal'] = diction['user_postal'] if ("user_latitude" in diction.keys()): if diction['user_latitude']: mydata['user_latitude'] = diction['user_latitude'] if ("user_longitude" in diction.keys()): if diction['user_longitude']: mydata['user_longitude'] = diction['user_longitude'] if ("user_state" in diction.keys()): if diction['user_state']: mydata['user_state'] = diction['user_state'] connection_type = "" if ("connection_type" in diction.keys()): if diction['connection_type']: connection_type = diction['connection_type'] token = "" if ("token" in diction.keys()): if diction['token']: token = diction['token'] #print(" My Data ="+str(mydata)) status, tab_training_inzone = get_training_in_user_zone(diction) nb_formation_a_jouter = MYSY_GV.MAINPAGE_QUERY_LIMIT_ROW - len(tab_training_inzone) #print(" #### get_all_class : nb_formation_a_jouter "+str(nb_formation_a_jouter)+" " # "MYSY_GV.MAINPAGE_QUERY_LIMIT_ROW = "+str(MYSY_GV.MAINPAGE_QUERY_LIMIT_ROW)+" len(tab_training_inzone) = "+ # str(len(tab_training_inzone) )) alread_found = [] #print(str(tab_training_inzone)) for val in tab_training_inzone: stud_obj = json.loads(val) json_obj = json.dumps(stud_obj) if( stud_obj['external_code'] ): alread_found.append(str(stud_obj['external_code'])) #print(" stud_obj = "+str(stud_obj['external_code'])) user_recid = "None" # Verification de la validité du token/mail dans le cas des partner en mode connecté if (len(str(token)) > 0 and str(connection_type).strip() == "partner"): retval = mycommon.check_partner_token_validity("", token) if retval is False: mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide") return "Err_Connexion", "La session de connexion n'est pas valide" # Recuperation du recid de l'utilisateur user_recid = mycommon.get_parnter_recid_from_token(token) if user_recid is False: mycommon.myprint( str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur") return False, " Impossible de récupérer le token de l'utilisateur" """ Travail à faire : le bug actuel vient du fait que la 2ieme requete ci-dessous qui complete la liste des formation ajoute les formations deja trouvée dans la requete d'en haute. A faire : faire en sorte que la requete d'en dessous exclus les elements deja trouvée dans lreque en dessus. """ print(" alread_found = "+str(alread_found)) coll_name = MYSY_GV.dbname['myclass'] val_tmp = len(tab_training_inzone) insertObject = [] """ ORIG FOR for x in coll_name.find({ "$or": [ {'valide':'1', 'locked':'0', 'isalaune':'1', 'published':'1'}, { 'coeur': 1, 'published':'1' } ] }, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }).\ """ connected_client_recid = "" if (str(connection_type).strip() == "partner"): connected_client_recid = user_recid pipe = [{'$match': {"$and": [{"$or": [{'valide': '1', 'locked': '0', 'isalaune': '1', 'published': '1'}, {'coeur': 1, 'published': '1'}]}, {'external_code': {'$nin': alread_found}}, {'display_rank': {'$nin': []}} ]} }, {'$project': { 'indexed': 0, 'indexed_desc': 0, 'indexed_obj': 0, "indexed_title": 0, "valide": 0, "locked": 0, }}, {'$lookup': { 'from': 'business_prices', 'let': {'partner_owner_recid': "$partner_owner_recid", 'programme': '$programme'}, 'pipeline': [ {'$match': {'$expr': {'$and': [ {'$eq': ["$partner_recid", "$$partner_owner_recid"]}, {'$eq': ["$client_recid", connected_client_recid]}, {'$eq': ["$valide", "1"]} ] } } }, ], 'as': 'business_prices' } }, { '$sort': {"display_rank": pymongo.DESCENDING, "price": pymongo.ASCENDING, "date_update": pymongo.DESCENDING}}, {'$limit': nb_formation_a_jouter}, ] print(" ### pipe = ", pipe) for x in coll_name.aggregate(pipe): """ for x in coll_name.find( {"$and": [{"$or": [{'valide': '1', 'locked': '0', 'isalaune': '1', 'published': '1'}, {'coeur': 1, 'published': '1'}]}, {'external_code': {'$nin': alread_found}} ]}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }).\ limit(nb_formation_a_jouter).\ sort( [("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING) ]): """ #print("AVANT ==> "+str(x['description'])) if ("description" in x.keys()): val = x['description'] no_html = mycommon.cleanhtml(x['description']) if( len(no_html) > MYSY_GV.MAX_CARACT ): x['description'] = no_html[:MYSY_GV.MAX_CARACT]+" ..." else: x['description'] = no_html #mycommon.myprint("APRES ==> " + str(x['description'])) if ("business_prices" in x.keys()): # print(" ### business_prices = ", x['business_prices'], " len(x['business_prices']) = ", len(x['business_prices'])) if (len(x['business_prices']) > 0 and "discount" in x['business_prices'][0].keys()): """ Calcal du prix discounté """ # print(" ### discount = ", x['business_prices'][0]['discount'], " PRIX initial = ", x['price']) local_discount = mycommon.tryFloat(str(x['business_prices'][0]['discount'])) local_initial_price = mycommon.tryFloat(str(x['price'])) local_discounted_price = round(local_initial_price - (local_initial_price * (local_discount / 100)), 2) x['business_prices'][0]['discounted_price'] = str(local_discounted_price) # print(" #### local_discounted_price = ", local_discounted_price) user = x user['id'] = str(val_tmp) insertObject.append(JSONEncoder().encode(user)) #print(" 1111111 ") #print(str(x)) mycommon.InsertStatistic(x, "summary",mydata) tab_training_inzone.append(JSONEncoder().encode(user)) val_tmp = val_tmp + 1 #print(" ### insertObject = ", str(tab_training_inzone)) #return True, insertObject return True, tab_training_inzone except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False, " Impossible de récupérer les formations" """ A l'image de la fonction get_all_class, cette fonction retourne les formation avec un recid donnée """ def get_all_class_Given_partner_owner_recid_No_Login(diction): try: # Dictionnaire des champs utilisables field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city', 'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif', 'support', 'type', 'lang', 'price', 'distance', 'duration', 'cpf', 'connection_type', 'partner_owner_recid', 'subdomain'] incom_keys = diction.keys() ''' # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste # field_list. ''' for val in incom_keys: if str(val).lower() not in str(field_list).lower(): mycommon.myprint(str(inspect.stack()[0][3]) + " Le champ '" + val + "' n'est pas autorisé") return False, " Recherche impossible" # Recuperation des parametres mydata = {} if ("user_ip" in diction.keys()): if diction['user_ip']: mydata['user_ip'] = diction['user_ip'] if ("user_country_code" in diction.keys()): if diction['user_country_code']: mydata['user_country_code'] = diction['user_country_code'] if ("user_country_name" in diction.keys()): if diction['user_country_name']: mydata['user_country_name'] = diction['user_country_name'] if ("user_city" in diction.keys()): if diction['user_city']: mydata['user_city'] = diction['user_city'] if ("user_postal" in diction.keys()): if diction['user_postal']: mydata['user_postal'] = diction['user_postal'] if ("user_latitude" in diction.keys()): if diction['user_latitude']: mydata['user_latitude'] = diction['user_latitude'] if ("user_longitude" in diction.keys()): if diction['user_longitude']: mydata['user_longitude'] = diction['user_longitude'] if ("user_state" in diction.keys()): if diction['user_state']: mydata['user_state'] = diction['user_state'] connection_type = "" if ("connection_type" in diction.keys()): if diction['connection_type']: connection_type = diction['connection_type'] token = "" if ("token" in diction.keys()): if diction['token']: token = diction['token'] # print(" My Data ="+str(mydata)) partner_owner_recid = "" if( "subdomain" in diction.keys() and diction['subdomain']): partnair_data_count = MYSY_GV.dbname['partnair_account'].count_documents({'subdomaine_catalog_pub': diction['subdomain'], 'active': '1', 'locked': '0', 'firstconnexion': '0' }) if (partnair_data_count == 1): partnair_data = MYSY_GV.dbname['partnair_account'].find_one({'subdomaine_catalog_pub': diction['subdomain'], 'active': '1', 'locked': '0', 'firstconnexion': '0' }, {'_id': 1, 'recid': 1, 'nom': 1}) if( partnair_data and 'recid' in partnair_data.keys() ): partner_owner_recid = partnair_data['recid'] status, tab_training_inzone = get_training_in_user_zone(diction) nb_formation_a_jouter = MYSY_GV.MAINPAGE_QUERY_LIMIT_ROW - len(tab_training_inzone) # print(" #### get_all_class : nb_formation_a_jouter "+str(nb_formation_a_jouter)+" " # "MYSY_GV.MAINPAGE_QUERY_LIMIT_ROW = "+str(MYSY_GV.MAINPAGE_QUERY_LIMIT_ROW)+" len(tab_training_inzone) = "+ # str(len(tab_training_inzone) )) alread_found = [] # print(str(tab_training_inzone)) for val in tab_training_inzone: stud_obj = json.loads(val) json_obj = json.dumps(stud_obj) if (stud_obj['external_code']): alread_found.append(str(stud_obj['external_code'])) # print(" stud_obj = "+str(stud_obj['external_code'])) user_recid = "None" # Verification de la validité du token/mail dans le cas des partner en mode connecté if (len(str(token)) > 0 and str(connection_type).strip() == "partner"): retval = mycommon.check_partner_token_validity("", token) if retval is False: mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide") return "Err_Connexion", "La session de connexion n'est pas valide" # Recuperation du recid de l'utilisateur user_recid = mycommon.get_parnter_recid_from_token(token) if user_recid is False: mycommon.myprint( str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur") return False, " Impossible de récupérer le token de l'utilisateur" """ Travail à faire : le bug actuel vient du fait que la 2ieme requete ci-dessous qui complete la liste des formation ajoute les formations deja trouvée dans la requete d'en haute. A faire : faire en sorte que la requete d'en dessous exclus les elements deja trouvée dans lreque en dessus. """ print(" alread_found = " + str(alread_found)) coll_name = MYSY_GV.dbname['myclass'] val_tmp = len(tab_training_inzone) insertObject = [] """ ORIG FOR for x in coll_name.find({ "$or": [ {'valide':'1', 'locked':'0', 'isalaune':'1', 'published':'1'}, { 'coeur': 1, 'published':'1' } ] }, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }).\ """ connected_client_recid = "" if (str(connection_type).strip() == "partner"): connected_client_recid = user_recid pipe = [{'$match': {"$and": [{"$or": [{'valide': '1', 'locked': '0', 'isalaune': '1', }, {'coeur': 1, 'published': '1'}]}, {'external_code': {'$nin': alread_found}}, {'display_rank': {'$nin': []}}, {'partner_owner_recid':partner_owner_recid} ]} }, {'$project': {'indexed': 0, 'indexed_desc': 0, 'indexed_obj': 0, "indexed_title": 0, "valide": 0, "locked": 0}}, {'$lookup': { 'from': 'business_prices', 'let': {'partner_owner_recid': "$partner_owner_recid", 'programme': '$programme'}, 'pipeline': [ {'$match': {'$expr': {'$and': [ {'$eq': ["$partner_recid", "$$partner_owner_recid"]}, {'$eq': ["$client_recid", connected_client_recid]}, {'$eq': ["$valide", "1"]} ] } } }, ], 'as': 'business_prices' } }, {'$sort': {"display_rank": pymongo.DESCENDING, "price": pymongo.ASCENDING, "date_update": pymongo.DESCENDING}}, {'$limit': nb_formation_a_jouter}, ] print(" ### get_all_class_Given_partner_owner_recid_No_Login pipe = ", pipe) for x in coll_name.aggregate(pipe): """ for x in coll_name.find( {"$and": [{"$or": [{'valide': '1', 'locked': '0', 'isalaune': '1', }, {'coeur': 1, 'published': '1'}]}, {'external_code': {'$nin': alread_found}} ]}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }).\ limit(nb_formation_a_jouter).\ sort( [("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING) ]): """ # print("AVANT ==> "+str(x['description'])) if ("description" in x.keys()): val = x['description'] no_html = mycommon.cleanhtml(x['description']) if (len(no_html) > MYSY_GV.MAX_CARACT): x['description'] = no_html[:MYSY_GV.MAX_CARACT] + " ..." else: x['description'] = no_html # mycommon.myprint("APRES ==> " + str(x['description'])) if ("business_prices" in x.keys()): # print(" ### business_prices = ", x['business_prices'], " len(x['business_prices']) = ", len(x['business_prices'])) if (len(x['business_prices']) > 0 and "discount" in x['business_prices'][0].keys()): """ Calcal du prix discounté """ # print(" ### discount = ", x['business_prices'][0]['discount'], " PRIX initial = ", x['price']) local_discount = mycommon.tryFloat(str(x['business_prices'][0]['discount'])) local_initial_price = mycommon.tryFloat(str(x['price'])) local_discounted_price = round(local_initial_price - (local_initial_price * (local_discount / 100)), 2) x['business_prices'][0]['discounted_price'] = str(local_discounted_price) # print(" #### local_discounted_price = ", local_discounted_price) user = x user['id'] = str(val_tmp) insertObject.append(JSONEncoder().encode(user)) # print(" 1111111 ") # print(str(x)) mycommon.InsertStatistic(x, "summary", mydata) tab_training_inzone.append(JSONEncoder().encode(user)) val_tmp = val_tmp + 1 # print(" ### insertObject = ", str(tab_training_inzone)) # return True, insertObject return True, tab_training_inzone except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False, " Impossible de récupérer les formations" ''' Cette Fonction récupérer les formations dans la zone de l'utilisateur. Par zone utilisateur j'entends : ville or pays /!\ IMPORTANT : Si on veut UNIQUEMENT diffuser une formation dans une ville, alors il faut : - reseigner Le champ : zone_diffusion.city - Laisser Le champ : zone_diffusion.country à VIDE. /!\ IMPORTANT2 : La formation doit etre à la une : donc le paramttrafe "isalaune" = 1 Par defaut, le système cherche les diffuser dans un pays ou dans une ville. Le champ pays est renseigner, alors la formation a est diffuser dans tous le pays. Si le la collection "zone_diffusion" est vide ou n'existe pas, alors les formations sont diffusées partout dans le monde. ''' def get_training_in_user_zone(diction): try: insertObject = [] # Dictionnaire des champs utilisables field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city', 'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif', 'support', 'type', 'lang', 'price', 'distance', 'duration', 'cpf', 'connection_type', 'partner_owner_recid', 'subdomain'] incom_keys = diction.keys() ''' # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste # field_list. ''' for val in incom_keys: if str(val).lower() not in str(field_list).lower(): mycommon.myprint(str(inspect.stack()[0][3]) + " Le champ '" + val + "' n'est pas autorisé") return False, " Recherche impossible" # Recuperation des parametres mydata = {} if ("user_ip" in diction.keys()): if diction['user_ip']: mydata['user_ip'] = diction['user_ip'] if ("user_country_code" in diction.keys()): if diction['user_country_code']: mydata['user_country_code'] = diction['user_country_code'] if ("user_country_name" in diction.keys()): if diction['user_country_name']: mydata['user_country_name'] = diction['user_country_name'] if ("user_city" in diction.keys()): if diction['user_city']: mydata['user_city'] = diction['user_city'] if ("user_postal" in diction.keys()): if diction['user_postal']: mydata['user_postal'] = diction['user_postal'] if ("user_latitude" in diction.keys()): if diction['user_latitude']: mydata['user_latitude'] = diction['user_latitude'] if ("user_longitude" in diction.keys()): if diction['user_longitude']: mydata['user_longitude'] = diction['user_longitude'] if ("user_state" in diction.keys()): if diction['user_state']: mydata['user_state'] = diction['user_state'] # print(" My Data ="+str(mydata)) coll_name = MYSY_GV.dbname['myclass'] val_tmp = 1 insertObject = [] #print(" ########## critère de recherche : user_country_code = "+str(mydata['user_country_code']).lower()+" ---- user_city = "+str(mydata['user_city']).lower()) for x in coll_name.find({ "$or": [ {'valide':'1', 'locked':'0', 'isalaune':'1','published':'1', "zone_diffusion.country":str(mydata['user_country_code']).lower()}, {'valide':'1', 'locked':'0', 'isalaune':'1', 'published':'1', "zone_diffusion.city":str(mydata['user_city']).lower()} ] }, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }).\ limit(MYSY_GV.MAINPAGE_QUERY_LIMIT_ROW).\ sort( [ ("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING),]): #print("AVANT AVANN ==> ") val_not_cleaned = x['description'] CLEANR = re.compile('<.*?>') val = re.sub(CLEANR, '', str(val_not_cleaned)) val = str(val).replace(" ", " ").replace('\n','') #print("AVANT 2 ==> " + str(x['description']) + " taille = " + str(len(x['description']))) no_html = mycommon.cleanhtml(x['description']) no_html = str(no_html).replace(" ", " ").replace('\n', '') if( len(no_html) > MYSY_GV.MAX_CARACT ): x['description'] = no_html[:MYSY_GV.MAX_CARACT]+" ..." else: x['description'] = no_html #print("APRES 2 ==> " + str(x['description'])) user = x user['id'] = str(val_tmp) #print(" dans:get_training_in_user_zone return user = "+str(user['title'])) insertObject.append(JSONEncoder().encode(user)) #print(" ### summary_inzone "+str(x['external_code'])) mycommon.InsertStatistic(x, "summary", mydata) val_tmp = val_tmp + 1 return True, insertObject except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False, " Impossible de récupérer les formations dans la zone de l'utilisateur" ''' Cette fonction recherche les formations correspondant à un text IMPORTANT : Dans la recherche par tips, on fait du && et non du ou. exemple : pour la recherche "description:"fichier" title:"Niveau 1"" le système va chercher toutes les formations qui on : - "description:"fichier" ET ET ET ET ET - title:"Niveau 1" En gros, on fait une intersection entre les 2 listes. ''' def recherche_text_simple(diction): try: ''' # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste # field_list. ''' field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city', 'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif', 'support', 'type', 'lang', 'price', 'distance', 'duration', 'cpf', 'connection_type', 'subdomain'] incom_keys = diction.keys() for val in incom_keys: if val not in field_list and val.startswith('my_') is False: mycommon.myprint(str(inspect.stack()[0][3])+" - : Le champ '" + val + "' n'existe pas, recherche annuléee") return False, " Le champ '" + val + "' n'existe pas, recherche annulée" ''' Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente, On controle que les champs obligatoires sont presents dans la liste ''' field_list_obligatoire = ['search_text', 'token'] for val in field_list_obligatoire: if val not in diction: mycommon.myprint(str(inspect.stack()[0][3])+" - La valeur '" + val + "' n'est pas presente dans la liste des arguments ") return False, " : La valeur '" + val + "' n'est pas presente dans la liste des arguments " # recuperation des paramettre search_text = "" user_recid = "" token = "" critere_date = {} critere_string = "" new_diction = {} new_diction['token'] = "" if ("search_text" in diction.keys()): if diction['search_text']: search_text = diction['search_text'] if ("token" in diction.keys()): if diction['token']: token = diction['token'] new_diction['token'] = diction['token'] connection_type = "" if ("connection_type" in diction.keys()): if diction['connection_type']: connection_type = diction['connection_type'] ''' Recuperation de donnée du user connecté si connexion (user ou partner) /!\ Important : si le token est vide, alors c'est une recherche faite en mode non-connecté. on doit l'accepter. Si non le champ "connection_type" permet de savoir si c'est un user ou un partner le controle de la validé du token est faite que ce dernier n'est pas vide. ''' user_recid = "None" coll_search_result = MYSY_GV.dbname['user_recherche_result'] # Verification de la validité du token/mail dans le cas des user en mode connecté if ( len(str(token)) > 0 and str(connection_type).strip() == "user"): retval = mycommon.check_token_validity("", token) if retval is False : mycommon.myprint(str(inspect.stack()[0][3])+" - La session de connexion n'est pas valide") return "Err_Connexion", "La session de connexion n'est pas valide" # Recuperation du recid de l'utilisateur user_recid = mycommon.get_user_recid_from_token(token) if user_recid is False: mycommon.myprint(str(inspect.stack()[0][3])+" - Impossible de récupérer le token de l'utilisateur") return False, " Impossible de récupérer le token de l'utilisateur" # Verification de la validité du token/mail dans le cas des partner en mode connecté if (len(str(token)) > 0 and str(connection_type).strip() == "partner"): retval = mycommon.check_partner_token_validity("", token) if retval is False: mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide") return "Err_Connexion", "La session de connexion n'est pas valide" # Recuperation du recid de l'utilisateur user_recid = mycommon.get_parnter_recid_from_token(token) if user_recid is False: mycommon.myprint( str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur") return False, " Impossible de récupérer le token de l'utilisateur" #mycommon.myprint(" On recehrche la phrase +'" + search_text + "' + user_recid = "+user_recid) # Enregistrerment de la recherche retval, message, store_recherche_Id = store_recherche(diction, user_recid) if (retval is False): return retval, message ''' Verification si le texte de recherche contient un pattern de tips, c'est a dire une chaine de type : title:"titre" Si c'est le cas, nous sommes dans le cadre d'un recherche par type ''' cleaned_search_text = mycommon.Parse_Clean_Search_Text(search_text) print(" NOT CLEANED search_text = " + str(search_text)) print(" CLEANED search_text = "+str(cleaned_search_text)) regexp = r"[\w\.-]+:\"[\w\s]*\"" tips = re.findall(regexp, str(cleaned_search_text), re.MULTILINE) nb_tips = len(tips) final_message3 = {} if( nb_tips > 0 ): mycommon.myprint(" Une recherche par tips a été identifiée") new_diction['token'] = token # Traitement pour chaque recherche par tips final_retval = False final_message = [] insertObject = [] is_first_tip = True for val in tips : val2 = val.replace('"', '') new_diction['search_text'] = val2 print(" On va recherche : #####"+str(new_diction['search_text'] )) retval, message = recherche_tips_ret_ref(new_diction) print(" pour la recherche de : "+str(new_diction)+" -- Voici le resultat "+str(message)) if (retval == True ): final_retval = True #print(" contact de message "+str(message)+ " # final_message "+str(final_message)) if( is_first_tip is True) : final_message3 = message else: final_message3 = [x for x in message if x in final_message3] print(" final_message3 = "+str(final_message3)) final_message.append(message) is_first_tip = False final_message = final_message3 #print(" liste defitive des ref "+str(final_message)) final_message2 = [] for t in final_message: if( t is not False): #print( " unique = "+str(t)) final_message2.append(t) coll_name = MYSY_GV.dbname['myclass'] ''' A present mise à jour de la table "user_recherche" avec les resultats trouvés ''' #store_recherche_Id find_result = {'find_result':str(final_message2)} tab_user_recherche = MYSY_GV.dbname['user_recherche'] # seules les formations avec locked = 0 et valide=1 sont modifiables #print(str(inspect.stack()[0][3]) + " ENREG DES RESULT :"+str(store_recherche_Id)+" --- "+str(final_message2)) ret_val_user_rech = coll_name.find_one_and_update( {'_id': ObjectId(store_recherche_Id)}, {"$set": find_result}, return_document=ReturnDocument.AFTER ) if (ret_val_user_rech is False ): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = "+ str( store_recherche_Id)) return False, "La recheche est impossible " ''' la valeur nb_result permettra de savoir si la requete a donnée un resultat. si ce n'est pas le cas, il faudra à la fin enregistrer la requete avec un result a vide''' nb_result = 0 for x in coll_name.find({"external_code": {"$in": final_message2}, 'published':'1'}, { "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }).\ sort([("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING), ]): nb_result = nb_result +1 my_recid = {} my_recid['user_rec_id'] = str(user_recid) mydict_combined = {**diction, **x, **my_recid} mydict_combined['date_update'] = str(datetime.now()) mydict_combined['type_view'] = "summary" if ("_id" in mydict_combined.keys()): mydict_combined['class_id'] = mydict_combined.pop('_id') #mycommon.myprint("COMBINED = " + str(mydict_combined)) ''' Statistique : Insertion du recherche - resultat ''' ret_val_tmp = coll_search_result.insert_one(mydict_combined) if (ret_val_tmp is False): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = ") return False, "La recheche est impossible " user = x val = x['description'] no_html = mycommon.cleanhtml(x['description']) if (len(no_html) > MYSY_GV.MAX_CARACT): x['description'] = no_html[:MYSY_GV.MAX_CARACT] + " ..." else: x['description'] = no_html insertObject.append(JSONEncoder().encode(user)) # mycommon.myprint(" insertObject = ", insertObject) ''' en cas de resultat vide, enregsitrement de la requete de recherche avec les filtres associé''' if( nb_result == 0): my_recid = {} my_recid['user_rec_id'] = str(user_recid) mydict_combined = {**diction, **my_recid} mydict_combined['date_update'] = str(datetime.now()) mydict_combined['type_view'] = "summary" ''' Statistique : Insertion du recherche - resultat ''' ret_val_tmp = coll_search_result.insert_one(mydict_combined) if (ret_val_tmp is False): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = ") return False, "La recheche est impossible " return True, insertObject # Fin de la recherche par tips. tab_training = [] tab_training = ela_index.ela_recherche_tokens(search_text) ''' pour analyser la recherche, decommenter les 2 lignes ci-dessous ''' mycommon.myprint(" pour phrase : #" + search_text + "#, voici la liste des formations") mycommon.myprint(tab_training) coll_name = MYSY_GV.dbname['myclass'] ''' la valeur nb_result permettra de savoir si la requete a donnée un resultat. si ce n'est pas le cas, il faudra à la fin enregistrer la requete avec un result a vide''' nb_result = 0 insertObject = [] connected_client_recid = "" if( str(connection_type).strip() == "partner"): connected_client_recid = user_recid """ 23/02/2023 : FIN Uniquement pour des raisons de tests """ """ for x in coll_name.find({"external_code":{"$in":tab_training}, 'published':'1'}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0 }).sort([("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING), ]): """ pipe = [ { '$match': {'external_code': {"$in": tab_training}, 'published':'1'} }, { '$project': { 'indexed': 0, 'indexed_desc': 0, 'indexed_obj': 0, "indexed_title": 0, "valide": 0, "locked": 0} }, { '$lookup': { 'from': 'business_prices', 'let': { 'partner_owner_recid': "$partner_owner_recid", 'programme' : '$programme' }, 'pipeline': [ { '$match': { '$expr': { '$and': [ { '$eq': [ "$partner_recid", "$$partner_owner_recid" ] }, { '$eq': [ "$client_recid", connected_client_recid ] }, { '$eq': [ "$valide", "1" ] } ] } } }, ], 'as': 'business_prices' } }, {'$sort': {"display_rank": pymongo.DESCENDING, "price": pymongo.ASCENDING, "date_update": pymongo.DESCENDING}}, ] print(" ### pipe recherche_text_simple = ", pipe) for x in coll_name.aggregate(pipe): nb_result = nb_result + 1 if ("business_prices" in x.keys()): #print(" ### business_prices = ", x['business_prices'], " len(x['business_prices']) = ", len(x['business_prices'])) if(len(x['business_prices']) > 0 and "discount" in x['business_prices'][0].keys() ): """ Calcal du prix discounté """ #print(" ### discount = ", x['business_prices'][0]['discount'], " PRIX initial = ", x['price']) local_discount = mycommon.tryFloat(str(x['business_prices'][0]['discount'])) local_initial_price = mycommon.tryFloat(str(x['price'])) local_discounted_price = round( local_initial_price - (local_initial_price * (local_discount/100)), 2) x['business_prices'][0]['discounted_price'] = str(local_discounted_price) #print(" #### local_discounted_price = ", local_discounted_price) my_recid = {} my_recid['user_rec_id'] = str(user_recid) #print(" XXXXXXXXXX = "+str(x)) mydict_combined = {**diction, **x, **my_recid} mydict_combined['date_update'] = str(datetime.now()) mydict_combined['type_view'] = "summary" #print( "mydict_combined YYYYYYYYY = "+str(mydict_combined)) if("_id" in mydict_combined.keys()): #print(" ### mydict_combined[_id] = ", str(mydict_combined['_id'])) mydict_combined['class_id'] = mydict_combined.pop('_id') ''' Statistique : Insertion du recherche - resultat ''' ret_val_tmp = coll_search_result.insert_one(mydict_combined) if (ret_val_tmp is False): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = ") return False, "La recheche est impossible " user = x val = mycommon.clean_emoji(str(x['description'])) no_html = mycommon.cleanhtml(val) if (len(no_html) > MYSY_GV.MAX_CARACT): x['description'] = no_html[:MYSY_GV.MAX_CARACT] + " ..." else: x['description'] = no_html #print(" ### user = ", user) insertObject.append(mycommon.JSONEncoder().encode(user)) ''' /!\ Important : Recuperation des elements de la recherche etendue c'est a dire l'utilisation d'API externe /!\ update du 20/05/22 : Cette approche relentie bcp le systeme avec l'appel externe. donc on annule # aller chercher la recherche etendue et la rajouter ici. ext_status, external_code_prefixe = mycommon.Get_Extended_Result(search_text) if(ext_status is True): exten_coll = MYSY_GV.YTUBES_dbname['mysyserpapi'] for x in exten_coll.find({'external_code': {'$regex': re.compile(r".*" + str(external_code_prefixe) + ".*")}}, {"_id": 0, "valide": 0, }): nb_result = nb_result + 1 my_recid = {} my_recid['user_rec_id'] = str(user_recid) user = x val = x['description'] if (len(x['description']) > MYSY_GV.MAX_CARACT): x['description'] = val[:MYSY_GV.MAX_CARACT] + " ..." else: x['description'] = val[:MYSY_GV.MAX_CARACT] x['extented_search'] = "1" if str(x['url']) not in str(insertObject): insertObject.append(JSONEncoder().encode(user)) else: print(str(x['url'])+" existe deja, pas d'ajout à faire ") ''' #print("#### #", insertObject) #print(" result ok ") ''' en cas de resultat vide, enregsitrement de la requete de recherche avec les filtres associé''' if (nb_result == 0): my_recid = {} my_recid['user_rec_id'] = str(user_recid) mydict_combined = {**diction, **my_recid} mydict_combined['date_update'] = str(datetime.now()) mydict_combined['type_view'] = "summary" ''' Statistique : Insertion du recherche - resultat ''' ret_val_tmp = coll_search_result.insert_one(mydict_combined) if (ret_val_tmp is False): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = ") return False, "La recheche est impossible " return True, insertObject except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False, "Impossible de lancer la recherche" """ 25/08/2024 - A l'image de la recherche_text_simple, cette fonction fait une recheche pour la catalogue public du partner DONC LA NOTION DE PUBLICATION (PUBLISH) NE DOIT PAS ETRE PRISE EN COMPTE """ def recherche_text_simple_for_partner_catalog(diction): try: ''' # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste # field_list. ''' field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city', 'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif', 'support', 'type', 'lang', 'price', 'distance', 'duration', 'cpf', 'connection_type', 'subdomain'] incom_keys = diction.keys() for val in incom_keys: if val not in field_list and val.startswith('my_') is False: mycommon.myprint( str(inspect.stack()[0][3]) + " - : Le champ '" + val + "' n'existe pas, recherche annuléee") return False, " Le champ '" + val + "' n'existe pas, recherche annulée" ''' Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente, On controle que les champs obligatoires sont presents dans la liste ''' field_list_obligatoire = ['search_text', 'token'] for val in field_list_obligatoire: if val not in diction: mycommon.myprint( str(inspect.stack()[0][3]) + " - La valeur '" + val + "' n'est pas presente dans la liste des arguments ") return False, " : La valeur '" + val + "' n'est pas presente dans la liste des arguments " # recuperation des paramettre search_text = "" user_recid = "" token = "" critere_date = {} critere_string = "" new_diction = {} new_diction['token'] = "" if ("search_text" in diction.keys()): if diction['search_text']: search_text = diction['search_text'] if ("token" in diction.keys()): if diction['token']: token = diction['token'] new_diction['token'] = diction['token'] connection_type = "" if ("connection_type" in diction.keys()): if diction['connection_type']: connection_type = diction['connection_type'] ''' Recuperation de donnée du user connecté si connexion (user ou partner) /!\ Important : si le token est vide, alors c'est une recherche faite en mode non-connecté. on doit l'accepter. Si non le champ "connection_type" permet de savoir si c'est un user ou un partner le controle de la validé du token est faite que ce dernier n'est pas vide. ''' user_recid = "None" coll_search_result = MYSY_GV.dbname['user_recherche_result'] # Verification de la validité du token/mail dans le cas des user en mode connecté if (len(str(token)) > 0 and str(connection_type).strip() == "user"): retval = mycommon.check_token_validity("", token) if retval is False: mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide") return "Err_Connexion", "La session de connexion n'est pas valide" # Recuperation du recid de l'utilisateur user_recid = mycommon.get_user_recid_from_token(token) if user_recid is False: mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur") return False, " Impossible de récupérer le token de l'utilisateur" # Verification de la validité du token/mail dans le cas des partner en mode connecté if (len(str(token)) > 0 and str(connection_type).strip() == "partner"): retval = mycommon.check_partner_token_validity("", token) if retval is False: mycommon.myprint(str(inspect.stack()[0][3]) + " - La session de connexion n'est pas valide") return "Err_Connexion", "La session de connexion n'est pas valide" # Recuperation du recid de l'utilisateur user_recid = mycommon.get_parnter_recid_from_token(token) if user_recid is False: mycommon.myprint( str(inspect.stack()[0][3]) + " - Impossible de récupérer le token de l'utilisateur") return False, " Impossible de récupérer le token de l'utilisateur" # mycommon.myprint(" On recehrche la phrase +'" + search_text + "' + user_recid = "+user_recid) # Enregistrerment de la recherche retval, message, store_recherche_Id = store_recherche(diction, user_recid) if (retval is False): return retval, message ''' Verification si le texte de recherche contient un pattern de tips, c'est a dire une chaine de type : title:"titre" Si c'est le cas, nous sommes dans le cadre d'un recherche par type ''' cleaned_search_text = mycommon.Parse_Clean_Search_Text(search_text) print(" NOT CLEANED search_text = " + str(search_text)) print(" CLEANED search_text = " + str(cleaned_search_text)) regexp = r"[\w\.-]+:\"[\w\s]*\"" tips = re.findall(regexp, str(cleaned_search_text), re.MULTILINE) nb_tips = len(tips) final_message3 = {} if (nb_tips > 0): mycommon.myprint(" Une recherche par tips a été identifiée") new_diction['token'] = token # Traitement pour chaque recherche par tips final_retval = False final_message = [] insertObject = [] is_first_tip = True for val in tips: val2 = val.replace('"', '') new_diction['search_text'] = val2 print(" On va recherche : #####" + str(new_diction['search_text'])) retval, message = recherche_tips_ret_ref(new_diction) print(" pour la recherche de : " + str(new_diction) + " -- Voici le resultat " + str(message)) if (retval == True): final_retval = True # print(" contact de message "+str(message)+ " # final_message "+str(final_message)) if (is_first_tip is True): final_message3 = message else: final_message3 = [x for x in message if x in final_message3] print(" final_message3 = " + str(final_message3)) final_message.append(message) is_first_tip = False final_message = final_message3 # print(" liste defitive des ref "+str(final_message)) final_message2 = [] for t in final_message: if (t is not False): # print( " unique = "+str(t)) final_message2.append(t) coll_name = MYSY_GV.dbname['myclass'] ''' A present mise à jour de la table "user_recherche" avec les resultats trouvés ''' # store_recherche_Id find_result = {'find_result': str(final_message2)} tab_user_recherche = MYSY_GV.dbname['user_recherche'] # seules les formations avec locked = 0 et valide=1 sont modifiables # print(str(inspect.stack()[0][3]) + " ENREG DES RESULT :"+str(store_recherche_Id)+" --- "+str(final_message2)) ret_val_user_rech = coll_name.find_one_and_update( {'_id': ObjectId(store_recherche_Id)}, {"$set": find_result}, return_document=ReturnDocument.AFTER ) if (ret_val_user_rech is False): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = " + str( store_recherche_Id)) return False, "La recheche est impossible " ''' la valeur nb_result permettra de savoir si la requete a donnée un resultat. si ce n'est pas le cas, il faudra à la fin enregistrer la requete avec un result a vide''' nb_result = 0 for x in coll_name.find({"external_code": {"$in": final_message2}, }, {"indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }). \ sort([("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING), ]): nb_result = nb_result + 1 my_recid = {} my_recid['user_rec_id'] = str(user_recid) mydict_combined = {**diction, **x, **my_recid} mydict_combined['date_update'] = str(datetime.now()) mydict_combined['type_view'] = "summary" if ("_id" in mydict_combined.keys()): mydict_combined['class_id'] = mydict_combined.pop('_id') # mycommon.myprint("COMBINED = " + str(mydict_combined)) ''' Statistique : Insertion du recherche - resultat ''' ret_val_tmp = coll_search_result.insert_one(mydict_combined) if (ret_val_tmp is False): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = ") return False, "La recheche est impossible " user = x val = x['description'] no_html = mycommon.cleanhtml(x['description']) if (len(no_html) > MYSY_GV.MAX_CARACT): x['description'] = no_html[:MYSY_GV.MAX_CARACT] + " ..." else: x['description'] = no_html insertObject.append(JSONEncoder().encode(user)) # mycommon.myprint(" insertObject = ", insertObject) ''' en cas de resultat vide, enregsitrement de la requete de recherche avec les filtres associé''' if (nb_result == 0): my_recid = {} my_recid['user_rec_id'] = str(user_recid) mydict_combined = {**diction, **my_recid} mydict_combined['date_update'] = str(datetime.now()) mydict_combined['type_view'] = "summary" ''' Statistique : Insertion du recherche - resultat ''' ret_val_tmp = coll_search_result.insert_one(mydict_combined) if (ret_val_tmp is False): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = ") return False, "La recheche est impossible " return True, insertObject # Fin de la recherche par tips. tab_training = [] tab_training = ela_index.ela_recherche_tokens(search_text) ''' pour analyser la recherche, decommenter les 2 lignes ci-dessous ''' mycommon.myprint(" pour phrase : #" + search_text + "#, voici la liste des formations") mycommon.myprint(tab_training) coll_name = MYSY_GV.dbname['myclass'] ''' la valeur nb_result permettra de savoir si la requete a donnée un resultat. si ce n'est pas le cas, il faudra à la fin enregistrer la requete avec un result a vide''' nb_result = 0 insertObject = [] connected_client_recid = "" if (str(connection_type).strip() == "partner"): connected_client_recid = user_recid """ 23/02/2023 : FIN Uniquement pour des raisons de tests """ """ for x in coll_name.find({"external_code":{"$in":tab_training}, 'published':'1'}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0 }).sort([("display_rank", pymongo.DESCENDING), ("price", pymongo.ASCENDING), ("date_update", pymongo.DESCENDING), ]): """ pipe = [ {'$match': {'external_code': {"$in": tab_training}, }}, {'$project': {'_id': 0, 'indexed': 0, 'indexed_desc': 0, 'indexed_obj': 0, "indexed_title": 0, "valide": 0, "locked": 0}}, {'$lookup': { 'from': 'business_prices', 'let': {'partner_owner_recid': "$partner_owner_recid", 'programme': '$programme'}, 'pipeline': [ {'$match': {'$expr': {'$and': [ {'$eq': ["$partner_recid", "$$partner_owner_recid"]}, {'$eq': ["$client_recid", connected_client_recid]}, {'$eq': ["$valide", "1"]} ] } } }, ], 'as': 'business_prices' } }, {'$sort': {"display_rank": pymongo.DESCENDING, "price": pymongo.ASCENDING, "date_update": pymongo.DESCENDING}}, ] print(" ### pipe recherche_text_simple = ", pipe) for x in coll_name.aggregate(pipe): nb_result = nb_result + 1 if ("business_prices" in x.keys()): # print(" ### business_prices = ", x['business_prices'], " len(x['business_prices']) = ", len(x['business_prices'])) if (len(x['business_prices']) > 0 and "discount" in x['business_prices'][0].keys()): """ Calcal du prix discounté """ # print(" ### discount = ", x['business_prices'][0]['discount'], " PRIX initial = ", x['price']) local_discount = mycommon.tryFloat(str(x['business_prices'][0]['discount'])) local_initial_price = mycommon.tryFloat(str(x['price'])) local_discounted_price = round(local_initial_price - (local_initial_price * (local_discount / 100)), 2) x['business_prices'][0]['discounted_price'] = str(local_discounted_price) # print(" #### local_discounted_price = ", local_discounted_price) my_recid = {} my_recid['user_rec_id'] = str(user_recid) # print(" XXXXXXXXXX = "+str(x)) mydict_combined = {**diction, **x, **my_recid} mydict_combined['date_update'] = str(datetime.now()) mydict_combined['type_view'] = "summary" # print( "mydict_combined YYYYYYYYY = "+str(mydict_combined)) if ("_id" in mydict_combined.keys()): mydict_combined['class_id'] = mydict_combined.pop('_id') ''' Statistique : Insertion du recherche - resultat ''' ret_val_tmp = coll_search_result.insert_one(mydict_combined) if (ret_val_tmp is False): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = ") return False, "La recheche est impossible " user = x val = mycommon.clean_emoji(str(x['description'])) no_html = mycommon.cleanhtml(val) if (len(no_html) > MYSY_GV.MAX_CARACT): x['description'] = no_html[:MYSY_GV.MAX_CARACT] + " ..." else: x['description'] = no_html insertObject.append(JSONEncoder().encode(user)) ''' /!\ Important : Recuperation des elements de la recherche etendue c'est a dire l'utilisation d'API externe /!\ update du 20/05/22 : Cette approche relentie bcp le systeme avec l'appel externe. donc on annule # aller chercher la recherche etendue et la rajouter ici. ext_status, external_code_prefixe = mycommon.Get_Extended_Result(search_text) if(ext_status is True): exten_coll = MYSY_GV.YTUBES_dbname['mysyserpapi'] for x in exten_coll.find({'external_code': {'$regex': re.compile(r".*" + str(external_code_prefixe) + ".*")}}, {"_id": 0, "valide": 0, }): nb_result = nb_result + 1 my_recid = {} my_recid['user_rec_id'] = str(user_recid) user = x val = x['description'] if (len(x['description']) > MYSY_GV.MAX_CARACT): x['description'] = val[:MYSY_GV.MAX_CARACT] + " ..." else: x['description'] = val[:MYSY_GV.MAX_CARACT] x['extented_search'] = "1" if str(x['url']) not in str(insertObject): insertObject.append(JSONEncoder().encode(user)) else: print(str(x['url'])+" existe deja, pas d'ajout à faire ") ''' # print("#### #", insertObject) # print(" result ok ") ''' en cas de resultat vide, enregsitrement de la requete de recherche avec les filtres associé''' if (nb_result == 0): my_recid = {} my_recid['user_rec_id'] = str(user_recid) mydict_combined = {**diction, **my_recid} mydict_combined['date_update'] = str(datetime.now()) mydict_combined['type_view'] = "summary" ''' Statistique : Insertion du recherche - resultat ''' ret_val_tmp = coll_search_result.insert_one(mydict_combined) if (ret_val_tmp is False): mycommon.myprint(str(inspect.stack()[0][3]) + " - Impossible de mettre à jour la table des resultat" " d'une recherche de formation. Voir _id = ") return False, "La recheche est impossible " return True, insertObject except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False, "Impossible de lancer la recherche" ''' Cette fonction enregistre les recherches faites par les user dans la base de données. L'idée principale est de stocker toutes les recherche, que soit en mode connecté ou en mode non connecté. le difference se fera au niveau du mail de la personne. structure du document dans la BDD (id, uer_mail, text_recherche, critere_recherce(JSON), valide) la fontion prend en entrée un dictionnaire : - le texte - la liste des critères; dont les valeurs exacts sont : • type • lang • level • dist (distance) • price • certif • source Dans le cas ou le user a donnée un nom à la recherche, on ajoute le champ "name", ou s'il d'agit d'une mise à jour le champ "id" • name • id ''' def store_recherche(diction, user_recid=""): try: ''' # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste # field_list. ''' if ( len(str(user_recid)) <= 0 ): user_recid = 'None' # by default field_list = ['token', 'user_ip', 'user_country_code', 'user_country_name', 'user_city', 'user_postal', 'user_latitude', 'user_longitude', 'user_state', 'search_text', 'certif', 'support', 'type', 'lang', 'price', 'distance', 'duration', 'cpf', 'connection_type', 'subdomain'] incom_keys = diction.keys() for val in incom_keys: if val not in field_list and val.startswith('my_') is False: mycommon.myprint(str(inspect.stack()[0][3]) + " Le champ '" + val + "' n'est pas autorisé") return False, " Le champ '" + val + "' n'est pas autorisé", None ''' Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente, On controle que les champs obligatoires sont presents dans la liste ''' field_list_obligatoire = ['search_text', 'token'] for val in field_list_obligatoire: if val not in diction: mycommon.myprint(" : La valeur '" + val + "' n'est pas presente dans la liste des arguments ") return False, " : La valeur '" + val + "' n'est pas presente dans la liste des arguments ", None # recuperation des paramettre mydata = {} mydata_id = "" my_token = "" if ("search_text" in diction.keys()): if diction['search_text']: mydata['search_text'] = diction['search_text'] if ("user_mail" in diction.keys()): if diction['user_recid']: mydata['user_recid'] = diction['user_recid'] if ("token" in diction.keys()): if diction['token']: my_token = diction['token'] '''# Recuperation du recid de l'utilisateur user_recid = mycommon.get_user_recid_from_token(my_token) if user_recid is False: mycommon.myprint(" Impossible d'enregistrer la recherche de utilisateur") return False, " Impossible d'enregistrer la recherche de utilisateur" ''' mydata['user_recid'] = user_recid mydata['document_recherche'] = "formation" if ("type" in diction.keys()): if diction['type']: mydata['type'] = diction['type'] if ("lang" in diction.keys()): if diction['lang']: mydata['lang'] = diction['lang'] if ("level" in diction.keys()): if diction['level']: mydata['level'] = diction['level'] if ("dist" in diction.keys()): if diction['dist']: mydata['dist'] = diction['dist'] if ("price" in diction.keys()): if diction['price']: mydata['price'] = diction['price'] if ("connection_type" in diction.keys()): if diction['connection_type']: mydata['connection_type'] = diction['connection_type'] if ("certif" in diction.keys()): if diction['certif']: mydata['certif'] = diction['certif'] if ("source" in diction.keys()): if diction['source']: mydata['source'] = diction['source'] if ("name" in diction.keys()): if diction['name']: mydata['name'] = diction['name'] if ("id" in diction.keys()): if diction['id']: mydata_id = diction['id'] mydata['date_update'] = str(datetime.now()) mydata['valide'] = "1" # By default if ("valide" in diction.keys()): if diction['valide']: mydata['valide'] = diction['valide'] coll_name = MYSY_GV.dbname['user_recherche'] # Si le champ "id" est renseigné, il s'agit d'une mis jour #mycommon.myprint(str(inspect.stack()[0][3]) + " on va stocker "+str(mydata)+" id = "+str(mydata_id)) if( len(str(mydata_id)) > 0 ): ret_val = coll_name.find_one_and_update({'_id': ObjectId(str(mydata_id)), 'valide': '1'}, {"$set": mydata}, return_document=ReturnDocument.AFTER ) if (ret_val and ret_val['_id']): nb_doc = str(ret_val['_id']) mycommon.myprint(str(inspect.stack()[0][3]) + " La recherche a bien été mise à jour . Le Doc Id = "+str(nb_doc)) return True, "La recherche a bien été mise à jour", ret_val['_id'] else: return False, "Impossible de mettre à jour a la recherche", None else: ret_val = coll_name.insert_one(mydata) if ret_val and ret_val.inserted_id: nb_doc = ret_val.inserted_id #mycommon.myprint(str(inspect.stack()[0][3]) + " La recherche a été bien enregistrée. Id = '" + str(nb_doc)+"' ") return True, "La recherche a bien été mise à jour", nb_doc else: mycommon.myprint( str(inspect.stack()[0][3]) + "Impossible d'enregistrer la recherche") return False, "Impossible d'enregistrer la recherche ", None except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False, "Impossible d'enregistrer la recherche", None ''' Cette fonction prend une chaine de recherche en mode tips. Si la fonction detecte un tips, alors elle retroune un 1 - Un status = True et 2 - Un tableau avec qui contient uniquement la reference externe de la formation Si la fonction ne detecte pas de tips, elle retoure 1 - Un status = False 2 - Un tableau = False ''' def recherche_tips_ret_ref(diction): try: ''' # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste # field_list. ''' #print(" RRRRR "+str(diction)) field_list = ['search_text', 'token', 'support', 'id', 'type', 'lang', 'level', 'dist', 'price', 'certif', 'source', 'name','valide', 'duration', 'distance'] incom_keys = diction.keys() for val in incom_keys: if val not in field_list and val.startswith('my_') is False: mycommon.myprint(str(inspect.stack()[0][3])+" - Le champ '" + val + "' n'est pas autorisé, recherche annulée") return False, " Le champ '" + val + "' n'est pas autorisé, recherche annulée" ''' Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente, On controle que les champs obligatoires sont presents dans la liste ''' field_list_obligatoire = ['search_text', 'token'] for val in field_list_obligatoire: if val not in diction: mycommon.myprint(str(inspect.stack()[0][3])+" - La valeur '" + val + "' n'est pas presente dans la liste des arguments ") return False, " : La valeur '" + val + "' n'est pas presente dans la liste des arguments " user_recid = "None" # recuperation du recId du user si le token est fourni. # si le token est vide, c'est que nous sommes sur une recherche en mode non connecté. if (len(str(diction['token'])) > 0): user_recid = mycommon.get_user_recid_from_token(str(diction['token'])) if user_recid is False : mycommon.myprint(str(inspect.stack()[0][3])+" - Impossible de récupérer le recid du user") return False, "Impossible d'enregistrer la recherche" print(" ####### recherche tips, voici mon new diction"+str(diction)+ " user_recid = "+user_recid) # Enregistrerment de la recherche retval, message, store_recherche_Id = store_recherche(diction, user_recid) if( retval is False): return retval, message # recuperation des paramettre search_text = "" user_mail = "" token = "" if ("search_text" in diction.keys()): if diction['search_text']: search_text = diction['search_text'] if( len(str(search_text)) <= 0 ): return False, False if (":" not in search_text): print(" La phrase ne contient pas de ':' ") return False, False print(" la chaine recu est "+search_text) chaine = search_text.split(":") val1 = str(chaine[0]).lower() print(" chaine[0] = "+val1) # Liste des tips acceptés tab_tips = ['title', 'description', 'desc', 'objectif', 'obj','trainer'] min = 100 my_tips = "" for val in tab_tips: retval = mycommon.levenshtein(val1, val) #print(" la distance entre '"+val1+"' et le mot "+str(val)+" = "+str(retval)) if( retval <= min ): min = retval my_tips = val if (min >= len(str(val1)) or min >= len(str(my_tips)) ): mycommon.myprint(str(inspect.stack()[0][3])+" - le mot '"+val1+" ne correspond aucun tips, sorry") return False, " le mot '"+val1+" ne correspond aucun tips, sorry" if (str(my_tips) == "desc"): my_tips = 'description' mycommon.myprint(" Le tips recherché est "+my_tips+". Sa distance de Levenshtein ="+str(min)) tab_ret = {} tab_ret['tips'] = str(my_tips) tab_ret['search_text'] = str(chaine[1]).lower() #return True, " le tips recherché est '"+my_tips+"' " tab_training = [] tab_training = ela_index.ela_recherche_tokens_source_field(str(chaine[1]).lower(), str(my_tips) ) if( tab_training is False): return False, tab_training #mycommon.myprint(" pour phrase : #" + str(chaine[1]).lower() + "# , Pour le tips #"+ str(my_tips)+"#, voici la liste des formations") #mycommon.myprint(tab_training) coll_name = MYSY_GV.dbname['myclass'] return True, tab_training # ici lancer la recherche sur Le champ title sss #return True, str(tab_ret) except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False, "N/A" ''' Cette fonction prend une chaine de recherche en mode tips. Si la fonction detecte un tips, alors elle retroune un 1 - Un status = True et 2 - Un tableau avec - Tab[0] : le champ sur lequel s'applique la recherche - Tab[0] : la chaine à rechercher Si la fonction ne detecte pas de tips, elle retoure 1 - Un status = False 2 - Un tableau = False ''' def recherche_tips(diction): try: ''' # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste # field_list. ''' field_list = ['search_text', 'token', 'support', 'id', 'type', 'lang', 'level', 'dist', 'price', 'certif', 'source', 'name','valide'] incom_keys = diction.keys() for val in incom_keys: if val not in field_list and val.startswith('my_') is False: mycommon.myprint(str(inspect.stack()[0][3])+" - Le champ '" + val + "' n'existe pas, recherche annulée") return False, " Le champ '" + val + "' n'existe pas, recherche annulée" ''' Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente, On controle que les champs obligatoires sont presents dans la liste ''' field_list_obligatoire = ['search_text', 'token'] for val in field_list_obligatoire: if val not in diction: mycommon.myprint(str(inspect.stack()[0][3])+" - La valeur '" + val + "' n'est pas presente dans la liste des arguments ") return False, " : La valeur '" + val + "' n'est pas presente dans la liste des arguments " user_recid = "None" # recuperation du recId du user si le token est fourni. # si le token est vide, c'est que nous sommes sur une recherche en mode non connecté. if (len(str(diction['token'])) > 0): user_recid = mycommon.get_user_recid_from_token(str(diction['token'])) if user_recid is False : mycommon.myprint(str(inspect.stack()[0][3])+" - Impossible de récupérer le recid du user") return False, "Impossible d'enregistrer la recherche" print(" ####### recherche tips, voici mon new diction"+str(diction)+" RRRC ID = "+user_recid) # Enregistrerment de la recherche retval, message, store_recherche_Id = store_recherche(diction, user_recid) if( retval is False): return retval, message # recuperation des paramettre search_text = "" user_mail = "" token = "" if ("search_text" in diction.keys()): if diction['search_text']: search_text = diction['search_text'] if( len(str(search_text)) <= 0 ): return False, False if (":" not in search_text): print(" La phrase ne contient pas de ':' ") return False, False print(" la chaine recu est "+search_text) chaine = search_text.split(":") val1 = str(chaine[0]).lower() print(" chaine[0] = "+val1) # Liste des tips acceptés tab_tips = ['title', 'description', 'desc', 'objectif', 'obj','trainer'] min = 100 my_tips = "" for val in tab_tips: retval = mycommon.levenshtein(val1, val) #print(" la distance entre '"+val1+"' et le mot "+str(val)+" = "+str(retval)) if( retval <= min ): min = retval my_tips = val if (min >= len(str(val1)) or min >= len(str(my_tips)) ): mycommon.myprint(str(inspect.stack()[0][3])+" - le mot '"+val1+" ne correspond aucun tips, sorry") return False, " le mot '"+val1+" ne correspond aucun tips, sorry" ''' Remplacement de l'abreviation 'desc' par description ''' if( str(my_tips) == "desc"): my_tips = 'description' mycommon.myprint(" Le tips recherché est '"+my_tips+"'. Sa distance de Levenshtein ="+str(min)) tab_ret = {} tab_ret['tips'] = str(my_tips) tab_ret['search_text'] = str(chaine[1]).lower() #return True, " le tips recherché est '"+my_tips+"' " tab_training = [] tab_training = ela_index.ela_recherche_tokens_source_field(str(chaine[1]).lower(), str(my_tips) ) if (tab_training is False): return False, tab_training ''' Pour analyser les recherches, decommenter les 2 lignes ci-dessous ''' #mycommon.myprint(" pour phrase : #" + str(chaine[1]).lower() + "# , Pour le tips #"+ str(my_tips)+"#, voici la liste des formations") #mycommon.myprint(tab_training) coll_name = MYSY_GV.dbname['myclass'] insertObject = [] for x in coll_name.find({"external_code": {"$in": tab_training}, 'published':'1'}, {"_id": 0, "indexed": 0, "indexed_desc": 0, "indexed_obj": 0, "indexed_title": 0, "valide": 0, "locked": 0, }): #mycommon.myprint(x) user = x val = x['description'] no_html = mycommon.cleanhtml(x['description']) if (len(no_html) > MYSY_GV.MAX_CARACT): x['description'] = no_html[:MYSY_GV.MAX_CARACT] + " ..." else: x['description'] = no_html insertObject.append(JSONEncoder().encode(user)) # mycommon.myprint(" insertObject = ", insertObject) return True, insertObject # ici lancer la recherche sur Le champ title sss #return True, str(tab_ret) except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False, "N/A" ''' Cette fonction retourne les recherche enregistrer d'un user donnée ''' def get_stored_recherche(diction): try: ''' # Verification que les champs reçus dans l'API sont bien dans la liste des champs autorisés # Cela evite le cas ou une entité tierce ajouter les valeurs inconnu dans l'API # Ici on doit mettre tous les champs possible (obligatoire ou non) de la BDD dans la liste # field_list. ''' field_list = ['token'] incom_keys = diction.keys() for val in incom_keys: if val not in field_list and val.startswith('my_') is False: mycommon.myprint(str(inspect.stack()[0][3])+" - Le champ '" + val + "' n'existe pas, recherche annulée") return False, " Le champ '" + val + "' n'existe pas, recherche annulée" ''' Une fois qu'on a controlé que toutes les clés mise dans l'API sont correcte. etape precedente, On controle que les champs obligatoires sont presents dans la liste ''' field_list_obligatoire = [ 'token'] for val in field_list_obligatoire: if val not in diction: mycommon.myprint(str(inspect.stack()[0][3])+" - La valeur '" + val + "' n'est pas presente dans la liste des arguments ") return False, " : La valeur '" + val + "' n'est pas presente dans la liste des arguments " # recuperation des paramettre search_text = "" user_recid = "" token = "" if ("search_text" in diction.keys()): if diction['search_text']: search_text = diction['search_text'] if ("token" in diction.keys()): if diction['token']: token = diction['token'] # Verification de la validité du token/mail dans le cas des user en mode connecté if ( len(str(token)) <= 0): mycommon.myprint(str(inspect.stack()[0][3])+" - Le token est vide") return False, " Impossible de récupérer historique de recherche" retval = mycommon.check_token_validity("", token) if retval is False: mycommon.myprint(str(inspect.stack()[0][3])+" - La session de connexion n'est pas valide") return False, " Impossible de récupérer l'historique de recherche" # Recuperation du recid du user user_recid = "" user_recid = mycommon.get_user_recid_from_token(token) if user_recid is False : mycommon.myprint(str(inspect.stack()[0][3])+" - Impossible de récupérer le recid du user") return False, " Impossible de récupérer l'historique de recherche" coll_name = MYSY_GV.dbname['user_recherche'] RetObject = [] for retVal in coll_name.find({'user_recid': user_recid, 'valide':'1'}): #mycommon.myprint(str(retVal)) user = retVal RetObject.append(JSONEncoder().encode(user)) return True, RetObject except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() mycommon.myprint(str(inspect.stack()[0][3]) + " -" + str(e) + " - ERRORRRR AT Line : " + str(exc_tb.tb_lineno)) return False, "Impossible de récupérer les recherches du user "