Nicolas MASSOT

Bienvenue sur mon portfolio personnel

Centre de recherche en données et intelligence géospatiales (CRDIG)
Université laval géomatique

Stage au Département des Sciences Géomatiques de l'Université Laval et au Centre de Recherche en Données et Intelligence Géospatiales (CRDIG)

DéambUL est une application gratuite qu’on peut télécharger et consulter sur son téléphone. Elle qui nous localise, offre une carte du campus de l’Université Laval et nous propose différents parcours thématiques. Elle permet de trouver le meilleur itinéraire entre les 43 pavillons et les 200 hectares du campus de Québec. Elle permet également de découvrir des parcours qui mettent en évidence certaines composantes du campus, découvrez les arts publics présents sur le campus, venez examiner certaines des grandes infrastructures de recherche de l’Université Laval et bien plus encore.

creation_vues_groupes_parcours.sql

				
					--Création de la vue v_groupe_poi

SELECT row_number() OVER (ORDER BY ((groupe_poi.idgroupe || '-'::text) || point_interet.idpoi))::integer AS objectid,
(((groupe_poi.idgroupe || '-'::text) || point_interet.idpoi))::character varying(30) AS id_groupe_poi,
groupe_poi.idgroupe,
groupe.nom AS nom_groupe,
point_interet.idpoi,
point_interet.idpav,
point_interet.titre,
point_interet.description_1,
point_interet.auteur,
point_interet.date_debut,
point_interet.date_fin,
point_interet.interieur,
point_interet.exterieur,
point_interet.vue,
point_interet.gout,
point_interet.toucher,
point_interet.odorat,
point_interet.ouie,
point_interet.video,
point_interet.audio_guide,
point_interet.realite_augmente,
point_interet.an_creation,
point_interet.hyp_li1,
point_interet.hyp_li2,
point_interet.hyp_li3,
point_interet.latitude,
point_interet.longitude,
point_interet.geom,
groupe_poi.description AS desc_groupe_poi
FROM point_interet
JOIN groupe_poi ON groupe_poi.idpoi = point_interet.idpoi
JOIN groupe ON groupe.idgroupe = groupe_poi.idgroupe
ORDER BY groupe_poi.idgroupe;



--Création de la vue v_parcours_poi

SELECT row_number() OVER (ORDER BY ((parcours_poi.idparcours || '-'::text) || point_interet.idpoi))::integer AS objectid,
(((parcours_poi.idparcours || '-'::text) || point_interet.idpoi))::character varying(30) AS id_parcours_poi,
parcours_poi.idparcours,
parcours.titre AS titre_parcours,
parcours_poi.ordre,
point_interet.idpoi,
point_interet.idpav,
point_interet.titre,
point_interet.description_1,
point_interet.auteur,
point_interet.date_debut,
point_interet.date_fin,
point_interet.interieur,
point_interet.exterieur,
point_interet.vue,
point_interet.gout,
point_interet.toucher,
point_interet.odorat,
point_interet.ouie,
point_interet.video,
point_interet.audio_guide,
point_interet.realite_augmente,
point_interet.an_creation,
point_interet.hyp_li1,
point_interet.hyp_li2,
point_interet.hyp_li3,
point_interet.logo,
point_interet.latitude,
point_interet.longitude,
point_interet.geom,
parcours_poi.description AS desc_parcours_poi,
parcours_poi.direction
FROM point_interet
JOIN parcours_poi ON parcours_poi.idpoi = point_interet.idpoi
JOIN parcours ON parcours.idparcours = parcours_poi.idparcours
ORDER BY parcours_poi.idparcours, parcours_poi.ordre;
				
			

1_export_donnees_compression_images.py

				
					"""
Ce script utilise ArcPy pour exporter les données et les pièces jointes d'un formulaire Survey123 depuis ArcGIS Online, les décompresse et les sauvegarde localement.
Ensuite, il compresse les images attachées et les enregistre dans un répertoire spécifique. Voici les grandes étapes du script :

1. Paramètres de Configuration : Définition des paramètres comme l'URL du portail, l'ID de l'élément Survey123, le chemin de sauvegarde et les paramètres de compression d'image.
2. Connexion au Portail ArcGIS : Connexion à ArcGIS Online via l'URL du portail et identification de l'utilisateur.
3. Exportation de la Géodatabase et des Pièces Jointes : Obtention des éléments Survey123, exportation des données en format File Geodatabase, 
   et téléchargement des fichiers zip contenant les données.
4. Extraction des Données : Décompression des fichiers zip téléchargés et gestion des fichiers temporaires si nécessaire.
5. Gestion des Pièces Jointes : Pour chaque couche ayant des pièces jointes, création de dossiers pour sauvegarder ces pièces, 
   et écriture des chemins d'accès aux pièces jointes dans des fichiers CSV.
6. Compression des Images : Compression des images attachées et sauvegarde dans un répertoire spécifique après redimensionnement.
7. Exécution du Script : Appel de la fonction principale pour lancer tout le processus décrit ci-dessus.


URL du formulaire : XXXXXXXX

-> À faire tourner avec le projet ArcGIS joint
"""

from arcgis.gis import GIS
import os, re, csv
from PIL import Image
import zipfile

def export_data():

    
    #___________________________________________________________________________________#
    #                                                                                   #
    # -Paramètres pour l'import des données et des attachments du formulaire Survey123- #
    #___________________________________________________________________________________#
    
    portalURL = "https://ulaval.maps.arcgis.com/"
    survey_item_id = "XXXXXXXX"
    save_path = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/export_donnes_enquete"     #Paramètre
    keep_org_item = False
    store_csv_w_attachments = False

    #___________________________________________________________________________________#
    #                                                                                   #
    # -----------------  Paramètres pour la compression des images  ------------------- #
    #___________________________________________________________________________________#
   
    image_path = save_path + '//repeatpoi_attachments'
    repertoire_image_compressee = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/export_donnes_enquete/images_compressee"     #Paramètre
    nv_compression = 2

    #___________________________________________________________________________________#
    #                                                                                   #
    # --------------------  Extraction de la FGDB + attachments  ---------------------- #
    #___________________________________________________________________________________#

    # Connexion au portail ArcGIS
    gis = GIS(portalURL, client_id='XXXXXXXX')
    print("Successfully logged in as: " + gis.properties.user.username)
    
    print('Export de la EGDB et des attachments...')

    # Obtention de l'élément du formulaire Survey123 par son ID
    survey_by_id = gis.content.get(survey_item_id)

    rel_fs = survey_by_id.related_items('Survey2Service', 'forward')[0]
    item_excel = rel_fs.export(title=survey_by_id.title, export_format='File Geodatabase')
    zip_path = item_excel.download(save_path=save_path)
    
    # Dézipper la géodatabase téléchargée
    with zipfile.ZipFile(zip_path, 'r') as zip_ref:
        zip_ref.extractall(save_path)

    if not keep_org_item:
        item_excel.delete(force=True)
    
    layers = rel_fs.layers + rel_fs.tables
    for i in layers:
        if i.properties.hasAttachments:
            feature_layer_folder = os.path.join(save_path, '{}_attachments'.format(re.sub(r'[^A-Za-z0-9]+', '', i.properties.name)))
            
            # Création du dossier des pièces jointes si nécessaire
            if not os.path.exists(feature_layer_folder):
                os.mkdir(feature_layer_folder)

            # Détermination du chemin du fichier CSV pour les pièces jointes
            if store_csv_w_attachments:
                path = os.path.join(feature_layer_folder, "{}_attachments.csv".format(i.properties.name))
            else:
                path = os.path.join(save_path, "{}_attachments.csv".format(i.properties.name))
            
            csv_fields = ['Parent objectId', 'Attachment path']
            with open(path, 'w', newline='') as csvfile:
                csvwriter = csv.writer(csvfile)
                csvwriter.writerow(csv_fields)
                
                feature_object_ids = i.query(where="1=1", return_ids_only=True, order_by_fields='objectid ASC')
                for j in range(len(feature_object_ids['objectIds'])):
                    current_oid = feature_object_ids['objectIds'][j]
                    current_oid_attachments = i.attachments.get_list(oid=current_oid)
                
                    if len(current_oid_attachments) > 0:
                        for k in range(len(current_oid_attachments)):
                            attachment_id = current_oid_attachments[k]['id']
                            current_attachment_path = i.attachments.download(oid=current_oid, attachment_id=attachment_id, save_path=feature_layer_folder)
                            csvwriter.writerow([current_oid, os.path.join('{}_attachments'.format(re.sub(r'[^A-Za-z0-9]+', '', i.properties.name)), os.path.split(current_attachment_path[0])[1])])

    print('  -> EGDB et Attachments exportées')

    #___________________________________________________________________________________#
    #                                                                                   #
    # --------------------------  Compression des images  ----------------------------- #
    #___________________________________________________________________________________#

    #Si besoin, crée un nouveau répertoire pour enregistrer les images
    if os.path.exists(repertoire_image_compressee) :
        print('Le dossier existe déjà, pas besoin de le recréer')
    else :
        print('Création du nouveau dossier...')
        os.mkdir(repertoire_image_compressee)
        print("Import effectué")

# Compression des images
    print('Compression des images...')
    for filename in os.listdir(image_path):

        o_image = os.path.join(image_path, filename)                                                 #Crée une variable avec le chemin complet + nom de fichier
        image = Image.open(o_image)                                                                  #Ouvre la ième image

        width, height = image.size                  
        new_size = (width // int(nv_compression), height // int(nv_compression))                      #Réduit la taille de l'image  new_size = (600, 800)

        resized_image = image.resize(new_size)                                                        #Ajoute la nouvelle image dans une variable
        compressed_image_path = os.path.join(repertoire_image_compressee, filename)          #Crée une variable compressed_image_path avec le nouveau chemin + nom de fichier

        resized_image.save(compressed_image_path, optimize=True, quality=20)                          #Enregistre l'image
    print('  -> Images compressées')


if __name__ == "__main__":
    # Appel de la fonction pour exécuter le processus d'importation et de compression
    export_data()
				
			

2_peuplement_bdd.py

				
					"""

Ce script utilise ArcPy pour peupler les tables et les relations d'une géodatabase d'entreprise (EGDB) en utilisant les données exportées d'un formulaire Survey123. Il couvre plusieurs étapes de manipulation et d'insertion de données, ainsi que la gestion des relations entre différentes tables. Voici les grandes étapes du script :

1. Initialisation des Variables : Définition des chemins pour les géodatabases, les couches et les tables source et cible, ainsi que les couches temporaires pour les manipulations.
2. Insertion des Données dans la Table Groupe : Recherche de l'ID maximum actuel dans la table `groupe`, insertion des données du formulaire Survey123 filtrées par groupe, et ajout des nouveaux groupes avec des ID uniques.
3. Insertion des Données dans la Table Parcours : Recherche de l'ID maximum actuel dans la table `parcours`, insertion des données du formulaire Survey123 filtrées par parcours, et ajout des nouveaux parcours avec des ID uniques.
4. Insertion des Données dans la Table Point d'Intérêt : Recherche de l'ID maximum actuel dans la table `point_interet`, insertion des données de la couche `repeat_poi`, ajout des informations des champs sensoriels, et gestion des relations intérieur/extérieur.
5. Insertion des Données dans la Table Photo : Recherche de l'ID maximum actuel dans la table `photo`, insertion des données des photos attachées depuis la couche `repeat_poi__ATTACH`, gestion des photos supplémentaires si nécessaire, et mise à jour des relations.
6. Peuplement des Tables de Relation : Ajout des ID générés dans les tables `Formulaire_1` et `repeat_poi`, création de jointures pour associer les ID aux relations entre les points d'intérêt, les groupes, et les parcours, et insertion des relations dans les tables correspondantes.
7. Peuplement de la Table de Relation poi_photo_groupe : Ajout des relations entre les photos et les groupes de points d'intérêt, en utilisant des jointures multiples pour assembler toutes les données nécessaires, et insertion des relations dans les tables cibles.
8. Exécution du Script : Appel de la fonction principale pour lancer tout le processus décrit ci-dessus.


-> À faire tourner avec le projet ArcGIS joint
"""


import arcpy
import arcpy.conversion
import arcpy.management

# Initialisation des variables à ajouter
p_fgdb = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/export_donnes_enquete/f5594030-f86b-43a2-8ab9-6a4e16f252a8.gdb"           #Paramètre -> chemin de la fgdb exporté à l'étape 1. Penser à changer les p_jointure_1/ par des /
p_formulaire_1 = p_fgdb + "/Formulaire_1"
p_repeat_poi = p_fgdb + "/repeat_poi"
p_attach = p_fgdb + "/repeat_poi__ATTACH"

# Initialisation des variables de la EGDB
p_egdb = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/deambul_dev.sde"  #Chemin de la EGDB                                      #Paramètre
p_groupe = p_egdb + "/deambul_dev.deambul_dev.groupe"                                       #tables parent
p_parcours = p_egdb + "/deambul_dev.deambul_dev.parcours"
p_point_interet = p_egdb + "/deambul_dev.deambul_dev.point_interet" 
p_photo = p_egdb + "/deambul_dev.deambul_dev.photo"

# Initialisation des variables pour les tables enfant
p_defaut_gdb = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/Default.gdb" 
p_groupe_poi = p_egdb + "/deambul_dev.deambul_dev.groupe_poi"                               #tables enfant
p_parcours_poi = p_egdb + "/deambul_dev.deambul_dev.parcours_poi"
p_poi_photo_groupe = p_egdb + "/deambul_dev.deambul_dev.poi_photo_groupe"
p_poi_photo_parcours = p_egdb + "/deambul_dev.deambul_dev.poi_photo_parcours"

#Initialisation des variables/couches temporaires pour les manipulations (jointures, CopyRows, CopyFeatures)
p_jointure_1 = p_defaut_gdb + "/jointure_1" 
p_jointure_2 = p_defaut_gdb + "/jointure_2" 
p_jointure_3 = p_defaut_gdb + "/jointure_3" 
p_jointure_4 = p_defaut_gdb + "/jointure_4"
p_jointure_5 = p_defaut_gdb + "/jointure_5" 
p_groupe_poi_temp = "memory/tbl_tempo_groupe"
p_parcours_poi_temp = "memory/tbl_tempo_parcours"


id_poi = []
id_photo = []
id_groupe = []
id_parcours = []

def peuplement():

    arcpy.env.overwriteOutput = True

    #___________________________________________________________________________________#
    #                                                                                   #
    # ---------------    Insertion des donnees dans la table groupe     --------------- #
    #___________________________________________________________________________________#

    # Trouver la valeur maximale de idgroupe dans la table groupe
    max_idgroupe = 0
    with arcpy.da.SearchCursor(p_groupe, ["idgroupe"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_idgroupe:
                max_idgroupe = row[0]

    # Définir les champs source et cible pour la table des groupes
    sf_g_1 = ["titre_groupe",
              "description_groupe", 
              "contributeur_groupe", 
              "date_debut", 
              "date_fin", 
              "parcours_groupe"]
    
    tf_g_1 = ["nom",
               "description", 
               "contributeur", 
               "date_debut", 
               "date_fin"]

    # Clause WHERE pour filtrer les enregistrements où le champ 'parcours_groupe' est égal à 'Groupe'
    test_groupe = "parcours_groupe = 'groupe'"

    # Utiliser SearchCursor pour lire les données de la table source (Formulaire_1)
    with arcpy.da.SearchCursor(p_formulaire_1, sf_g_1, where_clause=test_groupe) as search_cursor:
        # Utiliser InsertCursor pour insérer les données dans la table cible (p_groupe)
        with arcpy.da.InsertCursor(p_groupe, ["idgroupe"] + tf_g_1) as insert_cursor:
            for row in search_cursor:
                target_row_g = []
                # Ajouter une nouvelle valeur unique pour idgroupe
                max_idgroupe += 1
                target_row_g.append(max_idgroupe)
                id_groupe.append(target_row_g)

                # Ajouter les valeurs des champs source aux champs cibles
                for src_field in sf_g_1[:-1]:  # Exclure 'parcours_groupe' lors de l'ajout des champs
                    target_row_g.append(row[sf_g_1.index(src_field)])
                # Insérer la ligne dans la table cible
                insert_cursor.insertRow(target_row_g)

    print(" -> Peuplement des groupes effectué")


    #___________________________________________________________________________________#
    #                                                                                   #
    # ---------------   Insertion des donnees dans la table parcours    --------------- #
    #___________________________________________________________________________________#

    # Trouver la valeur maximale de idparcours dans la table parcours
    max_idparcours = 0
    with arcpy.da.SearchCursor(p_parcours, ["idparcours"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_idparcours:
                max_idparcours = row[0]

    # Définition des champs source et cible pour la table des parcours
    sf_p_1 = ["titre_parcours", 
              "description_parcours",
               "contributeur_parcours", 
               "date_debut", 
               "date_fin"]
    
    tf_p_1 = ["titre", 
              "description", 
              "contributeur", 
              "date_debut", 
              "date_fin"]

    sf_p_2 = ["hiver", 
              "printemps", 
              "ete", 
              "automne"]
    tf_p_2 = ["hiver", 
              "printemps", 
              "ete", 
              "automne"]

    test_parcours = "parcours_groupe = 'parcours'"

    # Utiliser SearchCursor pour lire les données de la table source (Formulaire_1)
    with arcpy.da.SearchCursor(p_formulaire_1, sf_p_1, where_clause=test_parcours) as search_cursor:
        # Utiliser InsertCursor pour insérer les données dans la couche cible (p_parcours)
        with arcpy.da.InsertCursor(p_parcours, ["idparcours"] + tf_p_1 + tf_p_2) as insert_cursor:
            for row in search_cursor:
                # Initialiser une liste pour contenir les valeurs des champs de la couche cible
                target_row_p = []

                # Ajouter une nouvelle valeur unique pour idparcours
                max_idparcours += 1
                target_row_p.append(max_idparcours)
                id_parcours.append(target_row_p)

                # Ajouter les champs de sf_p_1 à tf_p_1
                for src_field in sf_p_1:
                    target_row_p.append(row[sf_p_1.index(src_field)])

                # Lire les valeurs des champs de la table p_repeat_poi pour sf_p_2
                with arcpy.da.SearchCursor(p_repeat_poi, sf_p_2) as search_cursor_2:
                    row_2 = next(search_cursor_2)
                    for src_field_2 in sf_p_2:
                        target_row_p.append(row_2[sf_p_2.index(src_field_2)])

                # Vérification du nombre d'éléments dans target_row_p
                if len(target_row_p) == len(["idparcours"] + tf_p_1 + tf_p_2):
                    # Insérer la ligne dans la couche cible
                    insert_cursor.insertRow(target_row_p)

    print(" -> Peuplement des parcours effectué")



    #___________________________________________________________________________________#
    #                                                                                   #
    # --------------- Insertion des donnees dans la table point_interet --------------- #
    #___________________________________________________________________________________#

    sf_pi_1 = [ "SHAPE@",
                "titre_poi",                # couche repeat_poi
                "description_generique",
                "description_poi_parcours",
                "auteur",
                "contributeur_poi",
                "date_photo_1",
                "url_1",
                "url_2",
                "url_3",
                "SHAPE@Y",
                "SHAPE@X",
                "odre_poi_parcours",
                "interieur_exterieur"]   
       
    tf_pi_1 = [ "SHAPE@",
                "titre",                    
                "description_1", 
                "description_2", 
                "auteur",
                "contributeur_poi",
                "an_creation", 
                "hyp_li1",
                "hyp_li2",
                "hyp_li3",
                "latitude",
                "longitude",
                "ordre",
                "interieur",
                "exterieur"]

    sf_pi_2 = [ "vue",                      # couche Formulaire_1
                "gout",
                "toucher",
                "odorat",
                "ouie"]       
                                     
    tf_pi_2 = [ "vue",
                "gout",
                "toucher",
                "odorat",
                "ouie"]
    
    # Trouver la valeur maximale de idpoi dans la table point_interet
    max_idpoi = 0
    with arcpy.da.SearchCursor(p_point_interet, ["idpoi"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_idpoi:
                max_idpoi = row[0]

    # Charger les données de p_formulaire_1 dans un dictionnaire
    data_formulaire_1 = {}
    with arcpy.da.SearchCursor(p_formulaire_1, sf_pi_2) as search_cursor_2:
        for row in search_cursor_2:
            key = row[0]  # Assurez-vous que cela correspond à la clé unique
            data_formulaire_1[key] = row


    # Utiliser SearchCursor pour lire les données de la classe d'entités source (sf_pi_1)
    with arcpy.da.SearchCursor(p_repeat_poi, sf_pi_1) as search_cursor_1:
        # Utiliser InsertCursor pour insérer les données dans la classe d'entités cible
        with arcpy.da.InsertCursor(p_point_interet, ["idpoi"] + tf_pi_1 + tf_pi_2) as insert_cursor:
            for row_1 in search_cursor_1:
                # Créer une nouvelle ligne pour la classe d'entités cible en respectant le mapping des champs
                target_row = []
                
                # Ajouter une nouvelle valeur unique pour idpoi
                max_idpoi += 1
                target_row.append(max_idpoi)
                id_poi.append(target_row)

                # Ajouter les champs de sf_pi_1 à tf_pi_1
                for src_field in sf_pi_1:
                    if src_field == "interieur_exterieur":
                        interieur = -1 if row_1[sf_pi_1.index(src_field)] == "Intérieur" else 0
                        exterieur = -1 if interieur == 0 else 0
                        target_row.append(interieur)
                        target_row.append(exterieur)
                    else:
                        target_row.append(row_1[sf_pi_1.index(src_field)])

                for src_field in sf_pi_2:
                    if src_field == "vue":
                        vue = 0 if row_1[sf_pi_2.index(src_field)]  is None else -1
                        target_row.append(vue)
                    if src_field == "gout":
                        vue = 0 if row_1[sf_pi_2.index(src_field)]  is None else -1
                        target_row.append(vue)
                    if src_field == "toucher":
                        vue = 0 if row_1[sf_pi_2.index(src_field)]  is None else -1
                        target_row.append(vue)
                    if src_field == "odorat":
                        vue = 0 if row_1[sf_pi_2.index(src_field)]  is None else -1
                        target_row.append(vue)
                    if src_field == "ouie":
                        vue = 0 if row_1[sf_pi_2.index(src_field)]  is None else -1
                        target_row.append(vue)
             
            
            # Insérer la ligne dans la classe d'entités cible
                insert_cursor.insertRow(target_row)

    print(" -> Peuplement des points d'intérêt effectué")    



    #___________________________________________________________________________________#
    #                                                                                   #
    # ---------------    Insertion des donnees dans la table photo     ---------------- #
    #___________________________________________________________________________________#


    # Trouver la valeur maximale de idpho dans la table photo
    max_idpho = 0
    with arcpy.da.SearchCursor(p_photo, ["idpho"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_idpho:
                max_idpho = row[0]

    # Champs à utiliser pour les photos
    sf_ph_attach = ["ATT_NAME", "REL_GLOBALID"]  # Champs de repeat_poi__ATTACH
    tf_ph_attach = ["nom_fichier"]

    # Champs de repeat_poi pour les photos
    photo_fields = ["auteur_photo_", "credit_photo_", "date_photo_", "premiere_photo_"]

    def process_photos(photo_suffix, max_idpho):
        sf_ph = [field + photo_suffix for field in photo_fields] + ["GlobalID"]
        tf_ph = ["auteur", "credit_photo", "date_acquis", "premiere_photo"]

        # Utiliser SearchCursor pour lire les données de la table source (repeat_poi)
        with arcpy.da.SearchCursor(p_repeat_poi, sf_ph) as search_cursor_repeat_poi:
            # Utiliser InsertCursor pour insérer les données dans la table cible (p_photo)
            with arcpy.da.InsertCursor(p_photo, ["idpho"] + tf_ph_attach + tf_ph) as insert_cursor:
                for row_repeat_poi in search_cursor_repeat_poi:
                    global_id = row_repeat_poi[-1]  # Extraire GlobalID
                    if global_id in attach_dict:
                        attach_row = attach_dict[global_id]
                        target_row_ph = []

                        # Ajouter une nouvelle valeur unique pour idpho
                        max_idpho += 1
                        target_row_ph.append(max_idpho)
                        id_photo.append(max_idpho)

                        # Ajouter les valeurs des champs ATT_NAME
                        for field in sf_ph_attach[:-1]:  # Exclure REL_GLOBALID
                            target_row_ph.append(attach_row[sf_ph_attach.index(field)])

                        # Ajouter les valeurs des champs repeat_poi
                        for field in sf_ph[:-1]:  # Exclure GlobalID
                            if "date_photo_" in field and row_repeat_poi[sf_ph.index(field)]:
                                date_photo = row_repeat_poi[sf_ph.index(field)]
                                target_row_ph.append(date_photo)
                            else:
                                target_row_ph.append(row_repeat_poi[sf_ph.index(field)])

                        # Insérer la ligne dans la table cible
                        insert_cursor.insertRow(target_row_ph)
        return max_idpho

    # Utiliser SearchCursor pour lire les données de la table source (repeat_poi__ATTACH)
    attach_dict = {}
    with arcpy.da.SearchCursor(p_attach, sf_ph_attach) as search_cursor_attach:
        for row_attach in search_cursor_attach:
            attach_dict[row_attach[-1]] = row_attach[:-1]  # Associer REL_GLOBALID à ATT_NAME et autres champs

    # Processus pour la première photo (obligatoire)
    max_idpho = process_photos("1", max_idpho)

    # Champs additionnels pour vérifier si la photo 2 et 3 doivent être ajoutées
    check_fields = ["GlobalID", "ajouter_photo2", "ajouter_photo3"]

    # Utiliser SearchCursor pour vérifier les champs "ajouter_photo_2" et "ajouter_photo_3"
    with arcpy.da.SearchCursor(p_repeat_poi, check_fields) as cursor:
        for row in cursor:
            global_id = row[0]
            ajouter_photo_2 = row[1]
            ajouter_photo_3 = row[2]

            if ajouter_photo_2 == "Oui":
                max_idpho = process_photos("2", max_idpho)
            if ajouter_photo_3 == "Oui":
                max_idpho = process_photos("3", max_idpho)    
    print(" -> Peuplement des photos effectué")



    #___________________________________________________________________________________#
    #                                                                                   #
    # --------  Peuplement des tables de relation groupe_poi et parcours_poi  -------- #
    #___________________________________________________________________________________#

    """
        1.	Ajouter les idpoi, idgroupe, idparcours à des listes (fait plus haut)
        2.	Ajouter ces id aux tables Formulaire_1 et repeat_poi
        3.	Joindre ces deux tables entre globalid et parentglobalid
        4.	Insérer les lignes dans la table de relation
    """

    # -- Ajouter l'idpoi généré tantôt à la table repeat_poi -- #

    field_name = "idpoi"

    # Démarrez une session d'édition sur la table p_repeat_poi
    edit_session = arcpy.da.Editor(p_fgdb)
    edit_session.startEditing(False, True)  

    # Ouvrir un curseur de mise à jour pour mettre à jour le champ idpoi
    with arcpy.da.UpdateCursor(p_repeat_poi, field_name) as cursor:
        for row, new_id in zip(cursor, id_poi):
            row[0] = new_id[0]  
            cursor.updateRow(row)


    print(" -> Ajout des idpoi à la table repeat_poi")



    # -- Ajouter l'idparcours et l'idgroupe généré tantôt à la table Formulaire_1 -- #

    field_name_parcours = "idparcours"
    field_name_groupe = "idgroupe"

    # Ouvrir un curseur de mise à jour pour mettre à jour les champs idparcours et idgroupe dans la table p_formulaire_1
    with arcpy.da.UpdateCursor(p_formulaire_1, field_name_groupe, test_groupe) as cursor_g:
        for row, new_id_g in zip(cursor_g, id_groupe):  
            row[0] = new_id_g[0]  
            cursor_g.updateRow(row)
    print(" -> Ajout des idgroupe à la table repeat_poi")


    # Ouvrir un curseur de mise à jour pour mettre à jour les champs idparcours et idgroupe dans la table p_formulaire_1
    with arcpy.da.UpdateCursor(p_formulaire_1, field_name_parcours, test_parcours) as cursor_p:
        for row, new_id_p in zip(cursor_p, id_parcours):  
            row[0] = new_id_p[0] 
            cursor_p.updateRow(row)
    print(" -> Ajout des idparcours à la table repeat_poi")


    edit_session.stopEditing(True)  # True pour sauvegarder les modifications


    # -- Joindre les tables repeat_poi et formulaire_1 dans une table jointure_1 
    # -- pour obtenir dans une même table la correspondance entre les idpoi, idgroupe -- #

    #si p_jointure_1 existe, on la supprime
    if arcpy.Exists(p_jointure_1):
            arcpy.management.Delete(p_jointure_1)

    temp_jointure1 = arcpy.management.AddJoin(p_repeat_poi, "parentglobalid", p_formulaire_1, "globalid", "KEEP_ALL")
    arcpy.conversion.ExportFeatures(temp_jointure1, p_jointure_1)


    # -- Faire un append des idpoi, idgroupe et description à la table de relation poi_groupe -- #
    sf_idpoi_idgroupe = ["idpoi", 
                         "idgroupe", 
                         "description_generique"]
    
    tf_idpoi_idgroupe = ["idpoi", 
                         "idgroupe",
                          "description"]


    #si p_groupe_poi_temp existe, on la supprime
    if arcpy.Exists(p_groupe_poi_temp):
            arcpy.management.Delete(p_groupe_poi_temp)

    arcpy.management.CreateTable(p_defaut_gdb, "p_groupe_poi_temp", p_groupe_poi)
    arcpy.management.CopyRows(p_groupe_poi, p_groupe_poi_temp)

    #Insersion dans groupe_poi
    with arcpy.da.SearchCursor(p_jointure_1, sf_idpoi_idgroupe, where_clause=test_groupe) as search_cursor:
        with arcpy.da.InsertCursor(p_groupe_poi_temp, tf_idpoi_idgroupe) as insert_cursor :
            for row in search_cursor :
                insert_poi_groupe_temp = [row[0], row[1], row[2]]
                insert_cursor.insertRow(insert_poi_groupe_temp)

    print(" -> Peuplement table de relation groupe_poi effectué")



    #si p_groupe_poi existe, on la supprime pour permettre le copyrows
    if arcpy.Exists(p_groupe_poi):
            arcpy.management.Delete(p_groupe_poi)

    arcpy.management.CopyRows(p_groupe_poi_temp, p_groupe_poi)


    #si p_parcours_poi_temp existe, on la supprime
    if arcpy.Exists(p_parcours_poi_temp):
            arcpy.management.Delete(p_parcours_poi_temp)

    arcpy.management.CreateTable(p_defaut_gdb, "p_parcours_poi_temp", p_parcours_poi)
    arcpy.management.CopyRows(p_parcours_poi, p_parcours_poi_temp)


    #Peuplement poi_parcours
    sf_idpoi_idparcours = ["idpoi", "idparcours", "description_poi_parcours", "odre_poi_parcours"]
    tf_idpoi_idparcours = ["idpoi", "idparcours", "description", "ordre"]

    #Insersion dans parcours_poi
    with arcpy.da.SearchCursor(p_jointure_1, sf_idpoi_idparcours, where_clause=test_parcours) as search_cursor:
        with arcpy.da.InsertCursor(p_parcours_poi_temp, tf_idpoi_idparcours) as insert_cursor :
            for row in search_cursor :
                insert_poi_parcours_temp = [row[0], row[1], row[2], row[3]]
                insert_cursor.insertRow(insert_poi_parcours_temp)


    #si p_groupe_poi existe, on la supprime pour permettre le copyrows
    if arcpy.Exists(p_parcours_poi):
            arcpy.management.Delete(p_parcours_poi)


    arcpy.management.CopyRows(p_parcours_poi_temp, p_parcours_poi)


    #arcpy.management.CopyRows(p_groupe_poi_temp, p_groupe_poi)
    arcpy.management.DeleteRows(p_groupe_poi_temp)
    arcpy.management.DeleteRows(p_parcours_poi_temp)

    print(" -> Peuplement table de relation parcours_point_interet effectué")


    #___________________________________________________________________________________#
    #                                                                                   #
    # --- Peuplement de la table de relation poi_photo_groupe et poi_photo_parcours --- #
    #___________________________________________________________________________________#


    field_name = "id_pho"

    # Vérifier si le champ existe
    fields = arcpy.ListFields(p_jointure_1)

    field_exists = any(field.name == field_name for field in fields)

    # Si le champ n'existe pas, ajoutez-le
    if not field_exists:
        arcpy.management.AddField(p_jointure_1, field_name, "LONG")


    edit_session = arcpy.da.Editor(p_defaut_gdb)
    edit_session.startEditing(False, True)  

    #Ajouter l'id_photo à la table p_jointure_1
    with arcpy.da.UpdateCursor(p_jointure_1, field_name) as cursor:
        for row, new_id in zip(cursor, id_photo):
            row[0] = new_id  
            cursor.updateRow(row)

    edit_session.stopEditing(True)  

    #Ici, série de jointure pour assembler toutes les données nécessaires (idpoi, idparcours, idgroupe, idphoto, parcours_groupe, nom de la photo)
    if arcpy.Exists(p_jointure_5):
        arcpy.management.Delete(p_jointure_5)

    if arcpy.Exists(p_jointure_2):
        arcpy.management.Delete(p_jointure_2)

    temp_jointure2 = arcpy.management.AddJoin(p_attach, "REL_GLOBALID", p_repeat_poi, "globalid", "KEEP_ALL")
    arcpy.management.CopyRows(temp_jointure2, p_jointure_2)

    temp_jointure5 = arcpy.management.AddJoin(p_jointure_1, "parentglobalid", p_jointure_2, "repeat_poi_parentglobalid", "KEEP_ALL")
    arcpy.management.CopyRows(temp_jointure5, p_jointure_5)

    if arcpy.Exists(p_jointure_3):
        arcpy.management.Delete(p_jointure_3)

    temp_jointure3 = arcpy.management.AddJoin(p_jointure_2, "repeat_poi_idpoi", p_groupe_poi, "idpoi", "KEEP_ALL")
    arcpy.management.CopyRows(temp_jointure3, p_jointure_3)

    temp_jointure4 = arcpy.management.AddJoin(p_jointure_1, "parentglobalid", p_jointure_3, "jointure_2_repeat_poi_parentglobalid", "KEEP_ALL")
    arcpy.management.CopyRows(temp_jointure4, p_jointure_4)

    sf_poi_pho_gr = ["jointure_1_idpoi",
                     "jointure_1_idgroupe",
                     "jointure_1_id_pho"]

    tf_poi_pho_gr = ["idpoi",
                     "idgroupe",
                     "idpho"]

    test_poi_pho_gr = "jointure_1_parcours_groupe = 'groupe'"


    #Insersion des informations de joniture_4 dans la table poi_photo_groupe
    with arcpy.da.SearchCursor(p_jointure_4, sf_poi_pho_gr, where_clause=test_poi_pho_gr) as search_cursor:
        with arcpy.da.InsertCursor(p_poi_photo_groupe, tf_poi_pho_gr) as insert_cursor :
            for row in search_cursor :
                insert_poi_pho_gr = [row[0], row[1], row[2]]
                insert_cursor.insertRow(insert_poi_pho_gr)


    sf_poi_pho_pa = ["jointure_1_idpoi",
                     "jointure_1_idparcours",
                     "jointure_1_id_pho"]

    tf_poi_pho_pa = ["idpoi",
                     "idparcours",
                     "idpho"]

    test_poi_pho_pa = "jointure_1_parcours_groupe = 'parcours'"


    #Insersion des informations de joniture_4 dans la table poi_photo_parcours
    with arcpy.da.SearchCursor(p_jointure_4, sf_poi_pho_pa, where_clause=test_poi_pho_pa) as search_cursor:
        with arcpy.da.InsertCursor(p_poi_photo_parcours, tf_poi_pho_pa) as insert_cursor :
            for row in search_cursor :
                insert_poi_pho_pa = [row[0], row[1], row[2]]
                insert_cursor.insertRow(insert_poi_pho_pa)

    print(" -> Peuplement table de relation poi_photo_groupe effectué ")

if __name__ == "__main__":
    peuplement()

				
			

3_creation_cartes_web.py

				
					"""
Ce script ArcPy permet de mettre à jours les Feature Layer et Service Definition des parcours OU des groupes.
Les principales étapes du script sont les suivantes :

1. Initialisation des variables : Définition des chemins vers les bases de données et les fichiers nécessaires, ainsi que des paramètres de connexion à ArcGIS Online.
2. Connexion à ArcGIS Online
3. Nettoyage du dossier en ligne : Suppression de tous les éléments dans le dossier "Parcours_DEAMBUL" sur ArcGIS Online.
4. Nettoyage des couches locales : Suppression de toutes les classes d'entités dans la carte locale, en gardant les couches raster.
5. Création et configuration des couches : Pour chaque parcours, création de classes d'entités, application de la symbologie et des attachements.
6. Ajout et publication des couches : Ajout de chaque couche à la carte locale, mise en scène et publication sur ArcGIS Online, puis déplacement des éléments publiés dans le dossier spécifié.
7. Nettoyage final : Suppression des couches ajoutées pour préparer le traitement du parcours suivant.

Chaque couche publiée est partagée publiquement et organisée dans le dossier "Parcours_DEAMBUL" sur ArcGIS Online.

-> À faire tourner avec le projet ArcGIS joint
"""


import arcpy
import os
from arcgis.gis import GIS
from arcgis.features import FeatureLayerCollection


# Permet de choisir si on veut uploader la couche des groupes ou des parcours
parcours_groupe = "groupe"  # Si on veut uploader les groupes, remplacer "parcours" par "groupe"                    #Paramètre

# Paramètres de la EGDB
sde = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/deambul_dev.sde"                             #Paramètre
v_groupe_poi = sde + "/deambul_dev.deambul_dev.v_groupe_poi"
v_parcours_poi = sde + "/deambul_dev.deambul_dev.v_parcours_poi"
v_photo_groupe = sde + "/deambul_dev.deambul_dev.v_photo_groupe"
v_photo_parcours = sde + "/deambul_dev.deambul_dev.v_photo_parcours"

# Paramètres de la FGDB par défaut
default_gdb = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/Default.gdb"                         #Paramètre
temp_parcours_poi_1 = default_gdb + "/temp_parcours_poi_1"
temp_groupe_poi_1 = default_gdb + "/temp_groupe_poi_1"
temp_parcours_poi_2 = default_gdb + "/temp_parcours_poi_2"
temp_groupe_poi_2 = default_gdb + "/temp_groupe_poi_2"

# Paramètres des styles
lyrx_groupe_poi = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/symbole_groupe.lyrx"             #Paramètre
lyrx_parcours_poi = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/symbole_parcours_v2.lyrx"      #Paramètre
#campus_2021 = "https://tiles.arcgis.com/tiles/RkhyeW7cqOfSjlQG/arcgis/rest/services/Campus_2021/MapServer"

# Paramètres du dossier contenant les images compressées
doss_imag_comp = "C:/Users/nimas28/OneDrive - Université Laval/Image_compressee"                                    #Paramètre


# Paramètres pour ArcGIS Online
portal_url = "https://ulaval.maps.arcgis.com/"
username = ""                                                                                #Paramètre
password = ""                                                                                          #Paramètre
service_name = "Parcours_POI_Service"  # Nom du service sur ArcGIS Online
outdir = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis"                                          #Paramètre
sddraft_filename = service_name + ".sddraft"
sddraft_output_filename = outdir + "/" + sddraft_filename
sd_filename = service_name + ".sd"
sd_output_filename = outdir + "/" + sd_filename
Projet = "E:/Avignon_Universite/L3/Semestre_2/Stage/DEAMBUL/projet_arcgis/projet_arcgis.aprx"                       #Paramètre
        
# Connexion au portail ArcGIS
gis = GIS(portal_url, username, password)
print("Successfully logged in as: " + gis.properties.user.username)

aprx = arcpy.mp.ArcGISProject(Projet)
m = aprx.listMaps("Carte")[0]  



#Supprime tous les éléments dans le dossier spécifié.
folder = None

for f in gis.users.me.folders:
    if parcours_groupe == "parcours":
        if f['title'] == "Parcours_DEAMBUL":
            folder = f
            break
    if parcours_groupe == "groupe":
        if f['title'] == "Groupe_DEAMBUL":
            folder = f
            break


if folder:
    # Recherche tous les éléments de l'utilisateur
    all_items = gis.content.search(query=f'owner:{gis.users.me.username}', max_items=1000)
    
    # Suppression des éléments qui sont dans le dossier Carte_DEAMBUL sur ArcGIS Online
    folder_items = [item for item in all_items if item.ownerFolder == folder['id']]
    for item in folder_items:
        print(f"Suppression de l'élément : {item.title} de ArcGIS Online")
        item.delete()



    if parcours_groupe == "parcours":
        print("Tous les éléments du dossier Parcours_DEAMBUL ont été supprimés. \n")
    else :
        print("Tous les éléments du dossier Groupe_DEAMBUL ont été supprimés. \n")


# Supprimer toutes les classes d'entités présentes dans le contenu de la carte, sauf les rasters
layers_to_remove = [layer for layer in m.listLayers() if layer.isFeatureLayer]
for layer in layers_to_remove:
    layer_name = layer.name  # Stocker le nom de la couche avant de la supprimer
    m.removeLayer(layer)
    print(f"Suppression de la classe d'entités {layer_name} sur ArcGIS PRO \n")



def creation_web_map():

    if parcours_groupe == "parcours":
        
        # Trouver le dossier 'Parcours_DEAMBUL'
        folder = None
        for f in gis.users.me.folders:
            if f['title'] == 'Parcours_DEAMBUL':
                folder = f
                break

        # Créer une couche temporaire pour tous les parcours
        if arcpy.Exists(temp_parcours_poi_1):
            arcpy.management.Delete(temp_parcours_poi_1)
        arcpy.conversion.ExportFeatures(v_parcours_poi, temp_parcours_poi_1)

        # Créer les classes d'entités pour chaque parcours
        unique_parcours = set(row[0] for row in arcpy.da.SearchCursor(temp_parcours_poi_1, ["idparcours"]))

        for idparcours in unique_parcours:
            print("   -> Nous passons au parcours n°", idparcours)

            # Réinitialisation de la variable temporaire output_layer
            output_layer = f"{default_gdb}/parcours_{idparcours}"
            if arcpy.Exists(output_layer):
                arcpy.management.Delete(output_layer)
            where_clause = f"idparcours = {idparcours}"
            arcpy.conversion.ExportFeatures(temp_parcours_poi_1, output_layer, where_clause)


            # Appliquer les attachements et la symbologie pour chaque parcours. La symbologie ne marche pas
            arcpy.management.ApplySymbologyFromLayer(
                in_layer=output_layer, 
                in_symbology_layer=lyrx_parcours_poi, 
                symbology_fields=None, 
                update_symbology="UPDATE"
            )
            arcpy.EnableAttachments_management(output_layer)
            arcpy.management.AddAttachments(
                in_dataset=output_layer, 
                in_join_field="id_parcours_poi", 
                in_match_table=v_photo_parcours, 
                in_match_join_field="id_parcours_poi", 
                in_match_path_field="nom_fichier", 
                in_working_folder=doss_imag_comp
            )

            print(f"Classe d'entité créée pour le parcours numéro {idparcours} avec attachements et symbologie")


            # Ajoute la couche output_layer à la carte
            new_layer = m.addDataFromPath(output_layer)
            aprx.save()

            # Supprimer les fichiers .sddraft et .sd existants s'ils existent
            sddraft_output_filename = f"{outdir}/Parcours_{idparcours}.sddraft"
            sd_output_filename = f"{outdir}/Parcours_{idparcours}.sd"
            
            # Suppression des fichiers .sd et .sddraft avant de les recréer
            if os.path.exists(sddraft_output_filename):
                os.remove(sddraft_output_filename)
                print(f"Suppression du fichier sddraft existant ")
            if os.path.exists(sd_output_filename):
                os.remove(sd_output_filename)
                print(f"Suppression du fichier sd existant")

            # Créer MapImageSharingDraft et définir les propriétés du service pour chaque couche
            print(f'Création du MapImageSharingDraft pour Parcours_{idparcours}...')
            sharing_draft = m.getWebLayerSharingDraft("HOSTING_SERVER", "FEATURE", f"Parcours_{idparcours}")
            sharing_draft.overwriteExistingService = True
            sharing_draft.exportToSDDraft(sddraft_output_filename)


            print("Mise en scène du service...")
            # Mettre en scène le service
            arcpy.StageService_server(sddraft_output_filename, sd_output_filename)

            print("Publication du service...")
            # Publier sur ArcGIS Online dans le dossier 'Parcours_DEAMBUL'
            uploaded_item = gis.content.add({}, sd_output_filename)
            published_item = uploaded_item.publish(overwrite=True)
            published_item.share(everyone=True)

            # Déplacer l'élément publié dans le dossier 'Parcours_DEAMBUL'
            published_item.move(folder['id'])
            uploaded_item.move(folder['id'])

            print(f"   -> Service publié sur ArcGIS Online pour Parcours_{idparcours} dans le dossier {folder['title']} \n \n")

            # Supression de output_layer
            # Garder en tout temps la couche "Campus_2021/tiff" 
            m.removeLayer(new_layer)

            idparcours +=1

        aprx.save()

        print("   -> Création et mise à jour des couches pour chaque parcours terminée.")


    if parcours_groupe == "groupe":
        
        # Trouver le dossier 'groupe_DEAMBUL'
        folder = None
        for f in gis.users.me.folders:
            if f['title'] == 'Groupe_DEAMBUL':
                folder = f
                break

        # Créer une couche temporaire pour tous les groupe
        if arcpy.Exists(temp_groupe_poi_1):
            arcpy.management.Delete(temp_groupe_poi_1)
        arcpy.conversion.ExportFeatures(v_groupe_poi, temp_groupe_poi_1)

        # Créer les classes d'entités pour chaque groupe
        unique_groupe = set(row[0] for row in arcpy.da.SearchCursor(temp_groupe_poi_1, ["idgroupe"]))
        
        #idgroupe=0
        #idgroupe +=1

        for idgroupe in unique_groupe:
            

            print("   -> Nous passons au groupe n°", idgroupe)

            #Réinitialisation de la variable temporaire output_layer
            output_layer = f"{default_gdb}/groupe_{idgroupe}"
            if arcpy.Exists(output_layer):
                arcpy.management.Delete(output_layer)
            where_clause = f"idgroupe = {idgroupe}"
            arcpy.conversion.ExportFeatures(temp_groupe_poi_1, output_layer, where_clause)


            # Appliquer les attachements et la symbologie pour chaque groupe
            arcpy.management.ApplySymbologyFromLayer(
                in_layer=output_layer, 
                in_symbology_layer=lyrx_groupe_poi, 
                symbology_fields=None, 
                update_symbology="UPDATE"
            )
            aprx.save()


            arcpy.EnableAttachments_management(output_layer)
            arcpy.management.AddAttachments(
                in_dataset=output_layer, 
                in_join_field="id_groupe_poi", 
                in_match_table=v_photo_groupe, 
                in_match_join_field="id_groupe_poi", 
                in_match_path_field="nom_fichier", 
                in_working_folder=doss_imag_comp
            )

            print(f"Classe d'entité créée pour le groupe numéro {idgroupe} avec attachements et symbologie")


            #Ajoute la couche output_layer à la carte
            new_layer = m.addDataFromPath(output_layer)
            aprx.save()

            # Supprimer les fichiers .sddraft et .sd existants s'ils existent
            sddraft_output_filename_g = f"{outdir}/Groupe_{idgroupe}.sddraft"
            sd_output_filename_g = f"{outdir}/Groupe_{idgroupe}.sd"

            #Suppression des fichiers .sd et .sddraft avant de les recréer
            if os.path.exists(sddraft_output_filename_g):
                os.remove(sddraft_output_filename_g)
                print(f"Suppression du fichier sddraft existant ")
            if os.path.exists(sd_output_filename_g):
                os.remove(sd_output_filename_g)
                print(f"Suppression du fichier sd existant")

            # Créer MapImageSharingDraft et définir les propriétés du service pour chaque couche
            print(f'Création du MapImageSharingDraft pour groupe_{idgroupe}...')
            sharing_draft = m.getWebLayerSharingDraft("HOSTING_SERVER", "FEATURE", f"groupe_{idgroupe}")
            sharing_draft.overwriteExistingService = True
            sharing_draft.exportToSDDraft(sddraft_output_filename_g)

            #Ajout de la tuile Campus_2021
            #basemap_layer = m.addDataFromPath(campus_2021)
            #m.basemap = basemap_layer

            print("Mise en scène du service...")
            # Mettre en scène le service
            arcpy.StageService_server(sddraft_output_filename_g, sd_output_filename_g)

            print("Publication du service...")
            # Publier sur ArcGIS Online dans le dossier 'groupe_DEAMBUL'
            uploaded_item = gis.content.add({}, sd_output_filename_g)
            published_item = uploaded_item.publish(overwrite=True)
            published_item.share(everyone=True)

            # Déplacer l'élément publié dans le dossier 'groupe_DEAMBUL'
            published_item.move(folder['id'])
            uploaded_item.move(folder['id'])

            print(f"   -> Service publié sur ArcGIS Online pour Groupe_{idgroupe} dans le dossier {folder['title']} \n \n")

            #Supression de output_layer
            # Garder en tout temps la couche "Campus_2021.tiff" 
            m.removeLayer(new_layer)


        aprx.save()

        print("   -> Création et mise à jour des couches pour chaque groupe terminée.")

if __name__ == '__main__':
    creation_web_map()

				
			

« Le Centre de Recherche en Données et Intelligence Géospatiales (CRDIG) soutient la recherche scientifique de pointe dans le domaine géospatial. Ses membres collaborent activement avec le milieu afin d’appliquer leurs activités de recherche de façon innovante au bénéfice de la Société, dans trois domaines d’application privilégiés : les milieux marins et fluviaux, les villes et communautés intelligentes, les ressources naturelles et activités humaines. » (crdig.ulaval.ca)

1_export_donnees.py

				
					"""
Ce script utilise ArcPy pour importer les données et les pièces jointes d'un formulaire Survey123 depuis ArcGIS Online, les décompresse et les sauvegarde localement. Voici les grandes étapes du script :

1. Paramètres de Configuration : Définition des paramètres comme l'URL du portail, l'ID de l'élément Survey123, le chemin de sauvegarde, et les options de gestion des fichiers temporaires et des pièces jointes.
2. Connexion au Portail ArcGIS : Connexion à ArcGIS Online via l'URL du portail et identification de l'utilisateur.
3. Exportation de la Géodatabase et des Pièces Jointes : Obtention des éléments Survey123, exportation des données en format File Geodatabase, et téléchargement des fichiers zip contenant les données.
4. Extraction des Données : Décompression des fichiers zip téléchargés et gestion des fichiers temporaires si nécessaire.
5. Gestion des Pièces Jointes : Pour chaque couche ayant des pièces jointes, création de dossiers pour sauvegarder ces pièces, et écriture des chemins d'accès aux pièces jointes dans des fichiers CSV.
6. Exécution du Script : Appel de la fonction principale pour lancer tout le processus décrit ci-dessus.

URL du formulaire : https://arcg.is/1byfbm2
-> À faire tourner avec le projet ArcGIS joint
"""



from arcgis.gis import GIS
import os, re, csv
import zipfile

def export_data():
    """
    ID_CRDIG
    Cette fonction permet d'importer les données et les attachments du formulaire Survey 123


    """

    #___________________________________________________________________________________#
    #                                                                                   #
    # -Paramètres pour l'import des données et des attachments du formulaire Survey123- #
    #___________________________________________________________________________________#

    portalURL = "https://ulaval.maps.arcgis.com/"
    survey_item_id = "XXXXXXXX"
    save_path = "E:/Avignon_Universite/L3/Semestre_2/Stage/ID_CRDIG/projet_arcgis/export_donnee_enquete"     #Paramètre
    keep_org_item = False
    store_csv_w_attachments = False


    #___________________________________________________________________________________#
    #                                                                                   #
    # --------------------  Extraction de la FGDB + attachments  ---------------------- #
    #___________________________________________________________________________________#

    # Connexion au portail ArcGIS
    gis = GIS(portalURL, client_id='dhfvy8MKaIoTG1li')
    print("Successfully logged in as: " + gis.properties.user.username)

    print('Export de la EGDB et des attachments...')

    # Obtention de l'élément du formulaire Survey123 par son ID
    survey_by_id = gis.content.get(survey_item_id)

    rel_fs = survey_by_id.related_items('Survey2Service', 'forward')[0]
    item_excel = rel_fs.export(title=survey_by_id.title, export_format='File Geodatabase')
    zip_path = item_excel.download(save_path=save_path)

    # Dézipper la géodatabase téléchargée
    with zipfile.ZipFile(zip_path, 'r') as zip_ref:
        zip_ref.extractall(save_path)

    if not keep_org_item:
        item_excel.delete(force=True)

    layers = rel_fs.layers + rel_fs.tables
    for i in layers:
        if i.properties.hasAttachments:
            feature_layer_folder = os.path.join(save_path, '{}_attachments'.format(re.sub(r'[^A-Za-z0-9]+', '', i.properties.name)))

            # Création du dossier des pièces jointes si nécessaire
            if not os.path.exists(feature_layer_folder):
                os.mkdir(feature_layer_folder)

            # Détermination du chemin du fichier CSV pour les pièces jointes
            if store_csv_w_attachments:
                path = os.path.join(feature_layer_folder, "{}_attachments.csv".format(i.properties.name))
            else:
                path = os.path.join(save_path, "{}_attachments.csv".format(i.properties.name))

            csv_fields = ['Parent objectId', 'Attachment path']
            with open(path, 'w', newline='') as csvfile:
                csvwriter = csv.writer(csvfile)
                csvwriter.writerow(csv_fields)

                feature_object_ids = i.query(where="1=1", return_ids_only=True, order_by_fields='objectid ASC')
                for j in range(len(feature_object_ids['objectIds'])):
                    current_oid = feature_object_ids['objectIds'][j]
                    current_oid_attachments = i.attachments.get_list(oid=current_oid)

                    if len(current_oid_attachments) > 0:
                        for k in range(len(current_oid_attachments)):
                            attachment_id = current_oid_attachments[k]['id']
                            current_attachment_path = i.attachments.download(oid=current_oid, attachment_id=attachment_id, save_path=feature_layer_folder)
                            csvwriter.writerow([current_oid, os.path.join('{}_attachments'.format(re.sub(r'[^A-Za-z0-9]+', '', i.properties.name)), os.path.split(current_attachment_path[0])[1])])

    print('  -> EGDB et Attachments exportées')

if __name__ == "__main__":
    # Appel de la fonction pour exécuter le processus d'importation et de compression
    export_data()
				
			

2_peuplement_bdd.py

				
					"""
Ce script utilise ArcPy pour peupler les tables et les relations d'une géodatabase d'entreprise (EGDB) en utilisant les données exportées d'un formulaire Survey123. Voici les grandes étapes du script :

1. Initialisation des Variables : Définition des chemins pour les géodatabases, les couches et les tables source et cible, ainsi que les couches temporaires pour les manipulations.
2. Peuplement de la Table Données : Recherche de l'ID maximum actuel dans la table `donnees`, création de nouvelles entrées pour les données exportées du formulaire Survey123, et ajout des nouvelles données avec des ID uniques. Vérification des utilisateurs associés et affichage de messages d'avertissement pour les utilisateurs non trouvés dans la base de données.
3. Peuplement de la Table Pub_Doi : Recherche de l'ID maximum actuel dans la table `doi_pub`, création de nouvelles entrées pour les publications DOI associées aux données, et ajout des nouvelles publications avec des ID uniques.
4. Peuplement de la Table Boite_Englobante : Recherche de l'ID maximum actuel dans la table `boite_englobante`, création de nouvelles entrées pour les boîtes englobantes basées sur les géométries fournies dans le formulaire, et ajout des nouvelles boîtes englobantes avec des ID uniques.
5. Peuplement de la Table Centre : Création des centroids pour les boîtes englobantes, ajout des centroids à la table `centre` avec des ID uniques et les coordonnées (latitude et longitude), et gestion des duplications.
6. Peuplement des Tables de Relation : Ajout des ID générés dans les tables `Formulaire_ajout_metadonnees_ID_CRDIG`, `repeat_pub_doi`, et les autres tables de relations, création de jointures pour associer les ID aux relations entre les données, les boîtes englobantes, les centres, les publications DOI, et les utilisateurs, et insertion des relations dans les tables correspondantes.
7. Exécution du Script : Appel de la fonction principale pour lancer tout le processus décrit ci-dessus.

-> À faire tourner avec le projet ArcGIS joint

"""



import arcpy
import arcpy.management

# Initialisation des variables à ajouter
nom_gdb = "536ca540-efcf-42bc-880f-02e9ae3cb4de.gdb"                                                            # Paramètre à mettre à jour à chaque export de données
p_fgdb = "E:/Avignon_Universite/L3/Semestre_2/Stage/ID_CRDIG/projet_arcgis/export_donnee_enquete/" + nom_gdb    # Paramètre
p_formulaire = p_fgdb + "/Formulaire_ajout_metadonnees_ID_CRDIG"
p_repeat_pub_doi = p_fgdb + "/repeat_pub_doi"
p_attach = p_fgdb + "/Formulaire_ajout_metadonnees_ID_CRDIG__ATTACH"

p_defaut_gdb = "E:/Avignon_Universite/L3/Semestre_2/Stage/ID_CRDIG/projet_arcgis/Mon projet.gdb"                # Paramètre

# Initialisation des variables de la EGDB
p_egdb = "E:/Avignon_Universite/L3/Semestre_2/Stage/ID_CRDIG/projet_arcgis/egdb_fictive.gdb"                    # Paramètre
donnees = p_egdb + "/donnees"
utilisateur = p_egdb + "/utilisateur"
doi_pub = p_egdb + "/doi_pub"
centre = p_egdb + "/centre"
boite_englobante = p_egdb + "/boite_englobante"
be_donnee = p_egdb + "/be_donnee"
centre_donnee = p_egdb + "/centre_donnee"
doi_pub_donnee = p_egdb + "/doi_pub_donnee"
utilisateur_donnee = p_egdb + "/utilisateur_donnee"

# Initialisation des couches temporaires
jointure_1 = p_defaut_gdb + "/jointure_1"
jointure_2 = p_defaut_gdb + "/jointure_2"
centre_temp = p_defaut_gdb + "/centre_temp"

# Initialisation des paramètres pour la création d'une boite englobante à partir de coordonés (lat_min, lat_max, long_min, long_max)
# Cf. ligne 155
#table_point = p_defaut_gdb + "/table_point"
#point_1 = p_defaut_gdb + "/points_1"
#point_2 = p_defaut_gdb + "/points_2"
#point_3 = p_defaut_gdb + "/points_3"
#point_4 = p_defaut_gdb + "/points_4"
#points = p_defaut_gdb + "/points"
#be_temp = p_defaut_gdb + "/be_temp"

id_donnee = []
id_idul = []
id_doi_pub = []
id_centre = []
id_be = []


def peuplement():


    #___________________________________________________________________________________#
    #                                                                                   #
    # ------------------       Peuplement de la table donnees        ------------------ #
    #___________________________________________________________________________________#

    # Colonnes source et cible
    sf_donnees_1 = ["jeu_collection", "nom_collection", "desc_gen", "desc_prec", "doi", "reel_sim", "primitive",
                    "annee_debut", "annee_fin", "restriction", "georeference", "systeme_ref_hor", "dimension",
                    "systeme_ref_vert", "ellipsoide", "epsg", "commentaires", "CreationDate", "nom_prod", "nom_prop", "nom_proj", "coord_proj", "liste_idul"]

    tf_donnees_1 = ["donnees_collection", "nom_donnee", "description_generale", "description_detaillee", "doi_donnee",
                    "reel_sim", "primitive", "annee_debut", "annee_fin", "restric_utilis", "georeference", "sys_ref_hor",
                    "dimension", "sys_ref_vert", "ellipsoide", "epsg", "commentaire", "date_ajout", "nom_producteur", "nom_prop", "nom_sys_proj", "coord_proj", "idul"]


    # Trouver la valeur maximale de id_donnee dans la table donnees
    max_id_donnee = 0
    with arcpy.da.SearchCursor(donnees, ["id_donnee"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_id_donnee:
                max_id_donnee = row[0]

    # Créer un dictionnaire pour les idul de la couche utilisateur
    idul_dict = {}
    with arcpy.da.SearchCursor(utilisateur, ["idul"]) as cursor:
        for row in cursor:
            idul_dict[row[0]] = True

    # Utiliser SearchCursor pour lire les données de la table source (Formulaire_ajout_metadonnees_ID_CRDIG)
    with arcpy.da.SearchCursor(p_formulaire, sf_donnees_1) as search_cursor:
        # Utiliser InsertCursor pour insérer les données dans la table cible (donnees)
        with arcpy.da.InsertCursor(donnees, ["id_donnee"] + tf_donnees_1) as insert_cursor:
            for row in search_cursor:
                target_row_d = [max_id_donnee + 1]  # Ajouter une nouvelle valeur unique pour id_donnee
                max_id_donnee += 1
                id_donnee.append(max_id_donnee)

                    # Ajouter les valeurs des champs source aux champs cibles
                for src_field in sf_donnees_1:
                    target_row_d.append(row[sf_donnees_1.index(src_field)])

                # Insérer la ligne dans la table cible
                insert_cursor.insertRow(target_row_d)

    # Ouvrir un curseur de lecture pour la table p_formulaire
    with arcpy.da.SearchCursor(p_formulaire, ["liste_idul", "mail"]) as cursor:
        for row in cursor:
            liste_idul = row[0]
            mail = row[1]

            if liste_idul is None:
                print(f"\n\n ⚠ ⚠ L'utilisateur ayant le mail suivant '{mail}' n'existe pas dans la base de donnée, pensez à l'ajouter (tables : utilisateur, utilisateur_donnee). ⚠ ⚠ \n")


    print(" -> Peuplement de la table donnees effectué")


    #___________________________________________________________________________________#
    #                                                                                   #
    # ------------------       Peuplement de la table pub_doi        ------------------ #
    #___________________________________________________________________________________#

    # Trouver la valeur maximale de id_doi_pub dans la table pub_doi
    max_id_doi_pub = 0
    with arcpy.da.SearchCursor(doi_pub, ["id_doi_pub"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_id_doi_pub:
                max_id_doi_pub = row[0]

    # Utiliser cette valeur pour insérer de nouvelles lignes dans la table doi_pub
    with arcpy.da.SearchCursor(p_repeat_pub_doi, ["pub_doi", "parentglobalid"]) as search_cursor:
        with arcpy.da.InsertCursor(doi_pub, ["id_doi_pub", "pub_doi", "parentglobalid"]) as insert_cursor: #le champ parentglobalid est utilisé pour faire une jointure qui permettra de peupler la table de relation doi_pub_donnee
            for row in search_cursor:
                max_id_doi_pub += 1  # Incrémenter pour chaque nouvelle ligne
                target_row = [max_id_doi_pub, row[0], row[1]]
                insert_cursor.insertRow(target_row)

    print(" -> Peuplement de la table doi_pub effectué")


    #___________________________________________________________________________________#
    #                                                                                   #
    # -----------------    Peuplement de la table boite_englobante     ---------------- #
    #___________________________________________________________________________________#


    # Trouver la valeur maximale de id_be dans la table boite_englobante
    max_id_be = 0
    with arcpy.da.SearchCursor(boite_englobante, ["id_be"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_id_be:
                max_id_be = row[0]

    # ----- Si la BE est fournie par un dessin sur le canva de la carte ----- #


    # Utiliser cette valeur pour insérer de nouvelles lignes dans la table boite_englobante
    with arcpy.da.SearchCursor(p_formulaire, ["SHAPE@"]) as search_cursor:
        with arcpy.da.InsertCursor(boite_englobante, ["id_be", "SHAPE@"]) as insert_cursor:
            for row in search_cursor:
                max_id_be += 1  # Incrémenter pour chaque nouvelle ligne
                id_be.append(max_id_be)
                target_row = [max_id_be, row[0]]
                insert_cursor.insertRow(target_row)


    # ----- Le code suivant a pour but de peupler la table boite_englobante à partir d'une liste de coordonés (lat_min, lat_max, long_min, long_max)  ----- # ↓
    # ----- Ne marche pas totalement mais il y a des bons éléments à garder
    """
    clause_coord = "choix_be = 'coord'"

    # Définir les champs à lire et écrire
    fields_read = ["lat_min", "lat_max", "long_min", "long_max"]

    # Utiliser un SearchCursor pour lire les coordonnées de p_formulaire
    with arcpy.da.SearchCursor(p_formulaire, fields_read, where_clause=clause_coord) as search_cursor:
        for row in search_cursor:
            # si table_point existe, on la supprime
            if arcpy.Exists(table_point):
                arcpy.management.Delete(table_point)

            arcpy.management.CopyRows(p_formulaire, table_point)

            src = arcpy.SpatialReference(4326)

            # Permet d'ajouter les quatre angles de la boîte englobante dans quatre couches différentes
            if arcpy.Exists(point_1):
                arcpy.management.Delete(point_1)
            arcpy.management.XYTableToPoint(in_table=table_point, out_feature_class=point_1, x_field="long_min", y_field="lat_min", coordinate_system=src)

            if arcpy.Exists(point_2):
                arcpy.management.Delete(point_2)
            arcpy.management.XYTableToPoint(in_table=table_point, out_feature_class=point_2, x_field="long_max", y_field="lat_min", coordinate_system=src)

            if arcpy.Exists(point_3):
                arcpy.management.Delete(point_3)
            arcpy.management.XYTableToPoint(in_table=table_point, out_feature_class=point_3, x_field="long_max", y_field="lat_max", coordinate_system=src)

            if arcpy.Exists(point_4):
                arcpy.management.Delete(point_4)
            arcpy.management.XYTableToPoint(in_table=table_point, out_feature_class=point_4, x_field="long_min", y_field="lat_max", coordinate_system=src)

            # Créer une nouvelle couche points
            if arcpy.Exists(points):
                arcpy.management.Delete(points)
            arcpy.management.CreateFeatureclass(p_defaut_gdb, "points", geometry_type="POINT", spatial_reference=src)

            # Insérer les 4 points dans une seule couche que l'on vient de créer
            source_layers = [point_1, point_2, point_3, point_4]
            for layer in source_layers:
                with arcpy.da.SearchCursor(layer, ["SHAPE@"]) as point_cursor:
                    with arcpy.da.InsertCursor(points, ["SHAPE@"]) as insert_point_cursor:
                        for point_row in point_cursor:
                            insert_point_cursor.insertRow(point_row)



            with arcpy.da.SearchCursor(p_formulaire, ["choix_be"], clause_coord) as cursor:
                for row in cursor:
                    if row[0] == 'coord':
                        # Ajouter la BE à la couche be_temp
                        if arcpy.Exists(be_temp):
                            arcpy.management.Delete(be_temp)

                        arcpy.management.MinimumBoundingGeometry(points, be_temp, geometry_type="ENVELOPE", group_option="ALL")

                        # Vérifier si le champ id_be existe
                        field_name = "id_be"
                        fields = arcpy.ListFields(be_temp)
                        field_exists = any(field.name == field_name for field in fields)
                        # Si le champ n'existe pas, on l'ajoute
                        if not field_exists:
                            arcpy.management.AddField(be_temp, field_name, "LONG")

                        # Mettre à jour l'id_be et ajouter la géométrie
                        with arcpy.da.UpdateCursor(be_temp, ["id_be", "SHAPE@"]) as cursor:
                            for row in cursor:
                                max_id_be += 1
                                row[0] = max_id_be  # Mise à jour de l'id_be
                                cursor.updateRow(row)

                        fields_write = ["id_be", "SHAPE@"]

                        with arcpy.da.SearchCursor(be_temp, fields_write) as be_cursor:
                            with arcpy.da.InsertCursor(boite_englobante, fields_write) as insert_cursor_be:
                                for be_row in be_cursor:
                                    insert_cursor_be.insertRow(be_row)


    # Utilisation d'un UpdateCursor pour supprimer les enregistrements où Shape_Area est égal à 0
    with arcpy.da.UpdateCursor(boite_englobante, ["Shape_Area"]) as cursor:
        for row in cursor:
            if row[0] == 0:
                cursor.deleteRow()

        print(" -> Peuplement de la table boite_englobante effectué")

#Reste à traiter les boites englobantes avec les fichiers

    """

    #___________________________________________________________________________________#
    #                                                                                   #
    # ----------------------    Peuplement de la table centre     --------------------- #
    #___________________________________________________________________________________#

    # Supprimer centre_temp s'il existe
    if arcpy.Exists(centre_temp):
        arcpy.management.Delete(centre_temp)

    # Créer les centroids dans centre_temp à partir de boite_englobante
    arcpy.management.FeatureToPoint(boite_englobante, centre_temp, point_location="INSIDE")

    # Vérifier si le champ id_centre existe
    field_name = "id_centre"
    fields = arcpy.ListFields(centre)
    field_exists = any(field.name == field_name for field in fields)
    # Si le champ n'existe pas, on l'ajoute
    if not field_exists:
        arcpy.management.AddField(centre, field_name, "LONG")

    # Vérifier si les champs lat et long existent
    for field in ["lat", "long"]:
        if not any(field.name == field for field in fields):
            arcpy.management.AddField(centre, field, "DOUBLE")


    # Insérer les centroids dans la table centre avec id_centre incrémenté et lat/long
    max_id_centre = 0
    with arcpy.da.SearchCursor(centre_temp, ["SHAPE@", "id_be"]) as search_cursor:
        with arcpy.da.InsertCursor(centre, ["SHAPE@", "id_centre", "lat", "long"]) as insert_cursor:
            for row in search_cursor:
                max_id_centre += 1
                centroid = row[0].centroid
                insert_row = (centroid, max_id_centre, centroid.Y, centroid.X)
                insert_cursor.insertRow(insert_row)


    arcpy.management.DeleteIdentical(centre, "Shape")


    # Utiliser un SearchCursor pour lire et ajouter les valeurs du champ id_centre à la liste du même nom
    with arcpy.da.SearchCursor(centre, "id_centre") as cursor:
        for row in cursor:
            id_centre.append(row[0])  # Ajouter la valeur du champ id_centre à la liste

    print(" -> Peuplement de la table centre effectué \n")


    #___________________________________________________________________________________#
    #                                                                                   #
    # -----------------  Peuplement des tables de relation be_donnee  ----------------- #
    #___________________________________________________________________________________#

    """
        1.	Ajouter les id_donnee, id_be, id_centre, id_doi_pub à des listes (fait plus haut)
        2.	Ajouter ces id aux tables p_formulaire
        3.	Joindre ces deux tables entre globalid et parentglobalid
        4.	Insérer les lignes dans la table de relation
    """

    # Vérifier si le champ 'id_be' existe dans la table p_formulaire
    field_name = "id_be"
    fields = arcpy.ListFields(p_formulaire)
    id_be_exists = any(field.name == field_name for field in fields)
    # Si le champ n'existe pas, l'ajouter
    if not id_be_exists:
        arcpy.management.AddField(p_formulaire, field_name, "LONG")


    field_name_donnee = "id_donnee"
    id_donnee_exists = any(field.name == field_name_donnee for field in fields)
    # Si le champ n'existe pas, l'ajouter
    if not id_donnee_exists:
        arcpy.management.AddField(p_formulaire, "id_donnee", "LONG")

    edit_session = arcpy.da.Editor(p_fgdb)
    edit_session.startEditing(False, True)

    # Ouvrir un curseur de mise à jour pour la table p_formulaire pour ajouter l'id_be à p_formulaire
    with arcpy.da.UpdateCursor(p_formulaire, "id_be") as cursor:
        for row, new_id in zip(cursor, id_be):
            row[0] = new_id
            cursor.updateRow(row)

    # Ouvrir un curseur de mise à jour pour la table p_formulaire pour ajouter l'id_donnee à p_formulaire
    with arcpy.da.UpdateCursor(p_formulaire, "id_donnee") as cursor:
        for row, new_id in zip(cursor, id_donnee):
            row[0] = new_id
            cursor.updateRow(row)

    edit_session.stopEditing(True)


    #Peupler la table be_donnees
    # Trouver la valeur maximale de id_be dans la table boite_englobante
    max_id_be_donnee = 0
    with arcpy.da.SearchCursor(be_donnee, ["id_be_donnee"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_id_be_donnee:
                max_id_be_donnee = row[0]

    with arcpy.da.SearchCursor(p_formulaire, ["id_be", "id_donnee"]) as search_cursor :
        with arcpy.da.InsertCursor(be_donnee, ["id_be_donnee", "id_be", "id_donnee"]) as insert_cursor:
            for row in search_cursor :
                max_id_be_donnee += 1
                insert_row = (max_id_be_donnee, row[0], row[1])  # Créer la nouvelle ligne à insérer
                insert_cursor.insertRow(insert_row)


    print(" -> Peuplement de la table de relation be_donnee effectué")


    #___________________________________________________________________________________#
    #                                                                                   #
    # ---------------  Peuplement des tables de relation centre_donnee  --------------- #
    #___________________________________________________________________________________#


    field_name_centre = "id_centre"
    id_centre_exists = any(field.name == field_name_centre for field in fields)
    # Si le champ n'existe pas, l'ajouter
    if not id_centre_exists:
        arcpy.management.AddField(p_formulaire, "id_centre", "LONG")


    edit_session = arcpy.da.Editor(p_fgdb)
    edit_session.startEditing(False, True)

    # Ouvrir un curseur de mise à jour pour la table p_formulaire pour ajouter l'id_centre à p_formulaire
    with arcpy.da.UpdateCursor(p_formulaire, "id_centre") as cursor:
        for row, new_id in zip(cursor, id_centre):
            row[0] = new_id
            cursor.updateRow(row)

    edit_session.stopEditing(True)


    #Peupler la table centre_donnee
    # Trouver la valeur maximale de id_be dans la table boite_englobante
    max_id_centre_donnee = 0
    with arcpy.da.SearchCursor(centre_donnee, ["id_centre_donnee"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_id_centre_donnee:
                max_id_centre_donnee = row[0]

    with arcpy.da.SearchCursor(p_formulaire, ["id_centre", "id_donnee"]) as search_cursor :
        with arcpy.da.InsertCursor(centre_donnee, ["id_centre_donnee", "id_centre", "id_donnee"]) as insert_cursor:
            for row in search_cursor :
                max_id_centre_donnee += 1
                insert_row = (max_id_centre_donnee, row[0], row[1])  # Créer la nouvelle ligne à insérer
                insert_cursor.insertRow(insert_row)

    print(" -> Peuplement de la table de relation centre_donnee effectué")



    #___________________________________________________________________________________#
    #                                                                                   #
    # ---------------  Peuplement des tables de relation doi_pub_donnee  -------------- #
    #___________________________________________________________________________________#



    #si jointure_1 existe, on la supprime
    if arcpy.Exists(jointure_1):
            arcpy.management.Delete(jointure_1)

    temp_jointure1 = arcpy.management.AddJoin(doi_pub, "parentglobalid", p_formulaire, "globalid", "KEEP_COMMON")
    arcpy.management.CopyRows(temp_jointure1, jointure_1)



    #Peupler la table doi_pub_donnee
    # Trouver la valeur maximale de id_doi_pub_donnee dans la table doi_pub_donnee
    max_id_doi_pub_donnee = 0
    with arcpy.da.SearchCursor(doi_pub_donnee, ["id_doi_pub_donnee"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_id_doi_pub_donnee:
                max_id_doi_pub_donnee = row[0]


    with arcpy.da.SearchCursor(jointure_1, ["doi_pub_id_doi_pub", "Formulaire_ajout_metadonnees_ID_CRDIG_id_donnee"]) as search_cursor :
        with arcpy.da.InsertCursor(doi_pub_donnee, ["id_doi_pub_donnee", "id_doi_pub", "id_donnee"]) as insert_cursor:
            for row in search_cursor :
                max_id_doi_pub_donnee += 1
                insert_row = (max_id_doi_pub_donnee, row[0], row[1])  # Créer la nouvelle ligne à insérer
                insert_cursor.insertRow(insert_row)

    print(" -> Peuplement de la table de relation doi_pub_donnee effectué")


    #___________________________________________________________________________________#
    #                                                                                   #
    # -------------  Peuplement des tables de relation utilisateur_donnee  ------------ #
    #___________________________________________________________________________________#

    #si jointure_2 existe, on la supprime
    if arcpy.Exists(jointure_2):
            arcpy.management.Delete(jointure_2)

    temp_jointure2 = arcpy.management.AddJoin(p_formulaire, "liste_idul", utilisateur, "idul", "KEEP_COMMON")
    arcpy.management.CopyRows(temp_jointure2, jointure_2)



    #Peupler la table doi_pub_donnee
    # Trouver la valeur maximale de id_doi_pub_donnee dans la table doi_pub_donnee
    max_id_utilisateur_donnee = 0
    with arcpy.da.SearchCursor(utilisateur_donnee, ["id_utilisateur_donnee"]) as cursor:
        for row in cursor:
            if row[0] is not None and row[0] > max_id_utilisateur_donnee:
                max_id_utilisateur_donnee = row[0]


    with arcpy.da.SearchCursor(jointure_2, ["utilisateur_idul", "Formulaire_ajout_metadonnees_ID_CRDIG_id_donnee"]) as search_cursor :
        with arcpy.da.InsertCursor(utilisateur_donnee, ["id_utilisateur_donnee", "id_utilisateur", "id_donnee"]) as insert_cursor:
            for row in search_cursor :
                max_id_utilisateur_donnee += 1
                insert_row = (max_id_utilisateur_donnee, row[0], row[1])  # Créer la nouvelle ligne à insérer
                insert_cursor.insertRow(insert_row)


    print(" -> Peuplement de la table de relation utilisateur_donnee effectué \n")


if __name__ == "__main__":
    peuplement()