Skip to content
Snippets Groups Projects
Commit d8418626 authored by lisasmah's avatar lisasmah
Browse files
parents 76b010db 7843e154
No related branches found
No related tags found
3 merge requests!55Draft: #30 Afficher la date de dernière mise à jour d'une table dans les métadonnées, si disponible,!51Draft: #65 Documentation du datamart de l'app avec un schéma + détails des tables,!33Main
...@@ -3,3 +3,6 @@ ...@@ -3,3 +3,6 @@
.Rdata .Rdata
.httr-oauth .httr-oauth
.DS_Store .DS_Store
explo_projet*
explo_projet_attachments.zip
.RDataTmp
downloadbutton <- function(outputId,
label = "Download",
class = "fr-link fr-link--download",
...,
icon = shiny::icon("download")) {
tags$a(id = outputId,
class = paste('btn btn-default shiny-download-link', class),
href = '',
target = '_blank',
download = NA,
icon,
label, ...)
}
search_bar <- function() {
shiny::tags$div(
class = "fr-search-bar",
id = "header-search",
role = "search",
shiny::tags$label(class = "fr-label", `for` = "search-784-input", "Recherche"),
shiny::tags$input(
class = "fr-input",
placeholder = "Rechercher",
type = "search",
id = "search_784_input",
name = "search_784_input"
),
shiny::tags$button(
class = "fr-btn",
title = "Rechercher",
type = "button",
`onclick` = "Shiny.onInputChange('search_button', Math.random());",
"Rechercher"
)
)
}
Prototype de catalogue interne, réalisée avec RShiny, pour un serveur de base de données RPostgreSQL/postgis.
https://app.moqups.com/k1K5vhD4tNIqdX403sCSy0auWvLPDNUk/edit/page/ac0c42cd4
library(tidyverse)
library(datalibaba)
# 1- Bases ------------------------------------------------------------------------------------
# Création des connexions aux différentes base de données
role <- "does"
db_list <- c(consultation = datalibaba::connect_to_db("consultation", user = role),
referentiels = datalibaba::connect_to_db("referentiels", user = role),
datamart = datalibaba::connect_to_db("datamart", user = role),
si_eau = datalibaba::connect_to_db("si_eau", user = role))
# db_liste est une liste des noms des bases de données
db_liste <- c("consultation", "referentiels", "datamart", "si_eau")
# Récupération des commentaires pour chaque base de données
commentaires_base <- purrr::map_dfr(.x = db_liste, .f = function(db_name) {
comment_data <- datalibaba::get_db_comment(db = db_name, user = role)
tibble(
base = db_name,
commentaire = comment_data$commentaire
)
})
# Création d'une liste combinée avec noms et commentaires
bases_avec_commentaires <- commentaires_base %>%
dplyr::mutate(commentaire = tidyr::replace_na(commentaire, "")) %>%
dplyr::mutate(display_name = paste(base, commentaire, sep = " : "))
# 2- Schémas ----------------------------------------------------------------------------------
# Création de la liste des schémas chaque base à partir des connexions
db_schema_list0 <- purrr::map2_dfr(.x = db_list, .y = names(db_list),
.f = ~datalibaba::list_schemas(.x) %>%
tibble::enframe(name = NULL, value = "nom_schema") %>%
dplyr::arrange(nom_schema) %>%
dplyr::mutate(base = .y)) %>%
# on écarte les schémas "techniques" information_schema de chaque base + le datamart du catalogue + schema d'archives
dplyr::filter(!(nom_schema %in% c("pg_catalog", "public", "information_schema")), nom_schema != "catalogue", !grepl("^zz_|^z_", nom_schema))
# Récupération des commentaires des schémas
commentaires_schema <- purrr::map2_dfr(.x = db_schema_list0$nom_schema, .y = db_schema_list0$base,
.f = ~(datalibaba::get_schema_comment(schema = .x, db = .y, user = role) %>%
dplyr::mutate(base = .y))
)
db_schema_list <- db_schema_list0 %>%
dplyr::left_join(commentaires_schema %>% dplyr::mutate(commentaire = tidyr::replace_na(commentaire, "")), by = c("base", "nom_schema")) %>%
dplyr::mutate(display_name = paste(nom_schema, commentaire, sep = " : ") %>%
gsub(": $", "", .))
rm(db_schema_list0)
#3- Tables ------------------------------------------------------------------------------------
## 3-1 Liste des tables accessibles pour le role
# Création d'une fonction pour récupérer la liste des tables de chaque schéma
# (elle prend en argument l'index d'une ligne de db_schema_list)
lister_tables <- function(i = 1) {
datalibaba::list_tables(db = db_schema_list$base[i], schema = db_schema_list$nom_schema[i],
con = db_list[[db_schema_list$base[i]]]) %>%
tibble::enframe(name = NULL, value = "table") %>%
# ajout des colonnes 'base' et 'schema'
dplyr::cross_join(db_schema_list[i, ])
}
# Creation de la table qui liste toutes les tables de tous les schémas des 4 bases
tb_sch_base_0 <- purrr::map_df(1:nrow(db_schema_list), .f = lister_tables) %>%
dplyr::arrange(base, nom_schema, table)
# Vérif bonne pratique noms tables : on écarte les tables dont le nom comprend des majuscules car il faut les quoter dans les requêtes SQL
anomalies_noms_tables <- tb_sch_base_0 %>%
dplyr::filter(tolower(table) != table)
## Pour mémoire : voici comment ajouter les quotes au besoin
# mutate(table = if_else(tolower(table) != table, paste0('"', table, '"'), table)) %>%
# on écarte les tables avec majuscules et les tables d'archives
tb_sch_base <- tb_sch_base_0 %>%
dplyr::filter(tolower(table) == table, !grepl("^zz_|^z_", table)) #, nom_schema != "culture_societe_service"
## 3.2 Récupération des métadonnées des tables
### A- Récupération des types
# référentiel des types de champs, associant pour chaque type de postgis, un type compréhensible par l'utilisateur
types_ref <- read.csv2(file = "data-raw//ref_type_champs.csv")
# lecture des types des champs dans le schéma d'information de chaque base listée dans db_list
types_champs <- purrr::map_dfr(db_list, ~DBI::dbGetQuery(.x, "SELECT table_catalog AS base, table_schema AS nom_schema, table_name AS nom_table,
column_name AS nom_col, ordinal_position AS num_ordre, udt_name AS type
FROM information_schema.columns")) %>%
# on ne garde que les enregistrement correspondant à la liste tb_sch_base
dplyr::semi_join(tb_sch_base, by = c("nom_schema", "nom_table" = "table")) %>%
dplyr::arrange(base, nom_schema, nom_table, num_ordre) %>%
dplyr::left_join(types_ref, by = "type")
### B- Récupération des commentaires de table et de champs
commentaires_tables <- purrr::map_dfr(.x = c(1:nrow(tb_sch_base)),
.f = ~(datalibaba::get_table_comments(table = tb_sch_base$table[.x], schema = tb_sch_base$nom_schema[.x], db = tb_sch_base$base[.x], user = role) %>%
dplyr::mutate(nom_col = dplyr::coalesce(nom_col, ""), base = tb_sch_base$base[.x]))
)
tables_catalog <- dplyr::full_join(types_champs, commentaires_tables, by = c("base", "nom_schema", "nom_table", "nom_col")) %>%
dplyr::distinct() %>%
dplyr::arrange(base, nom_schema, nom_table)
### C- Création d'une base pour la recherche plein texte
base_recherche_txt <- tables_catalog %>%
dplyr::mutate(col_info = dplyr::if_else(is.na(commentaire), nom_col, paste0(commentaire, " : ", nom_col))) %>%
dplyr::group_by(base, nom_schema, nom_table) %>%
dplyr::summarise(description = paste(col_info, collapse = '\n'), .groups = "keep") %>%
dplyr::mutate(description = paste(nom_table, description, collapse = '\n', sep = "\n")) %>%
# Ajouter un identifiant unique à chaque ligne
dplyr::mutate(id = row_number()) %>%
dplyr::select(id, base, nom_schema, nom_table, description)
# 4- Exports du datamart au format RData ---------------------------------------------------------
date_datamart <- Sys.Date() %>% format.Date("%d/%m/%Y")
tb_datamart <- c("commentaires_schema", "tables_catalog", "base_recherche_txt","bases_avec_commentaires",
"db_schema_list", "tb_sch_base", "date_datamart") # liste des objets à inclure
nom_datamart <- "datamart_catalogue.RData" # nom du RData
# Sauvegarde dans le répertoire du projet et dans le répertoire du projet sur T:
save(list = tb_datamart, file = nom_datamart)
save(list = tb_datamart, file = paste0("T:/datalab/SCTE/CATALOGUE/PRODUCTION/", nom_datamart))
# 5- exports des anomalies en vue d'une remédiation ultérieure
if(nrow(anomalies_noms_tables) > 0) {
write.csv2(x = anomalies_noms_tables,
file = paste0("T:/datalab/SCTE/CATALOGUE/DONNEES_INTERNES/anomalies_noms_tables_", Sys.Date(), ".csv"))
}
type;type_fr
_text;texte
bool;booléen (Vrai/Faux)
bpchar;texte
date;date
float8;numérique
geometry;spatial
int2;entier
int4;entier
int8;entier
numeric;numérique
polygon;spatial
text;texte
timestamp;date/heure
timestamptz;date/heure
uuid;texte
varchar;texte
File added
# deploiement vers le sserveur interne de dataviz
library(RCurl)
# creation de l'adresse de connexion FTP au serveur
con_ftp_svr_dataviz <- paste0("ftp://", Sys.getenv("svr_dataviz_user"), ":", Sys.getenv("svr_dataviz_mdp"),
"@", Sys.getenv("svr_dataviz_ip"), "/catalogueR/")
# creation d'une fonction de transfert FTP vers le serveur à l'aide de ftpUpload de RCurl
## Les adresses des fichiers à transferer parte de la racine du projet RStudio
to_svr_dataviz_ftp <- function(fic = "datamart_catalogue.RData") {
ftpUpload(what = fic, to = paste0(con_ftp_svr_dataviz, fic))
}
# fichiers à transférer
app_files <- c("datamart_catalogue.RData", "global.R", list.files("R/", full.names = TRUE, recursive = TRUE),list.files("www/", full.names = TRUE, recursive = TRUE),
"server.R", "ui.R", "catalogue.Rproj")
# Exécution des transferts
lapply(X = app_files, FUN = to_svr_dataviz_ftp)
library(gmailr)
library(logging)
library(base64enc)
library(dplyr)
# Configuration du logging
basicConfig(level = 'DEBUG')
# Fonction pour encoder le sujet en Base64
encode_base64_utf8 <- function(string) {
raw_string <- charToRaw(string)
encoded_string <- base64encode(raw_string)
return(sprintf("=?UTF-8?B?%s?=", encoded_string))
}
# Fonction pour envoyer un email
send_email <- function(subject, body, to = "adl.dreal-pdl@developpement-durable.gouv.fr", cc = "lisa.smah@developpement-durable.gouv.fr") {
gm_auth_configure(path = "X:/SCTE/CSD/APPLICATIONS_SIG_BUREAUTIQUES/RESSOURCES_R/client_secret_api_gmail_csd.json")
gm_auth(
scopes = c(
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/gmail.compose"
)
)
# Encoder le sujet en Base64 pour éviter les problèmes d'encodage
subject_base64 <- encode_base64_utf8(subject)
email <- gm_mime() %>%
gm_to(to) %>%
gm_cc(cc) %>%
gm_from("lisa.smah@developpement-durable.gouv.fr") %>%
gm_subject(subject_base64) %>%
gm_text_body(body)
gm_send_message(email)
}
# Fonction pour lire et filtrer les logs
read_logs <- function(log_file) {
logs <- readLines(log_file)
# Filtrer les lignes indésirables
filtered_logs <- logs[!grepl("Attaching core tidyverse packages", logs) &
!grepl("Conflicts", logs) &
!grepl("package ‘", logs) &
!grepl("✔", logs) &
!grepl("ℹ Use the conflicted package", logs) &
!grepl("─", logs) &
!grepl("✖", logs)&
!grepl("Messages d'avis", logs) &
!grepl("compilé avec la version R", logs) &
!grepl("Attachement du package", logs) &
!grepl("L'objet suivant est masqué depuis", logs)&
!grepl("complete", logs)]
return(filtered_logs)
}
# Fonction pour analyser les logs et préparer le contenu de l'email
prepare_email_content <- function(logs) {
tryCatch({
datamart_success <- any(grepl("Mise à jour du datamart catalogueR réussie", logs))
deploy_success <- any(grepl("Déploiement de l'application réussi", logs))
error_messages <- logs[grepl("Erreur|Échec", logs)]
date <- Sys.Date()
if (datamart_success && deploy_success) {
subject <- "Succès mise à jour datamart catalogueR et déploiement de l'application"
body <- paste(logs, collapse = "\n")
} else if (!datamart_success) {
subject <- "Échec mise à jour datamart catalogueR"
body <- sprintf("La mise à jour du datamart a échoué le %s. Erreurs:\n%s", date, paste(error_messages, collapse = "\n"))
} else if (!deploy_success) {
subject <- "Échec du déploiement de l'application"
body <- sprintf("Le déploiement de l'application a échoué le %s. Erreurs:\n%s", date, paste(error_messages, collapse = "\n"))
}
list(subject = subject, body = body)
}, error = function(e) {
subject <- "Erreur lors de l'analyse des logs"
body <- sprintf("Une erreur est survenue lors de l'analyse des logs le %s. Erreur:\n%s", Sys.Date(), e$message)
list(subject = subject, body = body)
})
}
# Chemin vers le fichier de log généré par script_routine
args <- commandArgs(trailingOnly = FALSE)
script_path <- sub("--file=", "", args[grep("--file=", args)])
project_path <- normalizePath(file.path(dirname(script_path), ".."))
setwd(project_path)
log_file <- "logs/script_routine.log"
# Lire et analyser les logs
logs <- read_logs(log_file)
# Préparer le sujet et le contenu de l'email basé sur l'analyse des logs
email_content <- prepare_email_content(logs)
# Envoi de l'email de notification
send_email(email_content$subject, email_content$body)
library(logging)
Sys.setenv("HTTP_PROXY" = "http://pfrie-std.proxy.e2.rie.gouv.fr:8080")
Sys.setenv("HTTPS_PROXY" = "http://pfrie-std.proxy.e2.rie.gouv.fr:8080")
# a n'utiliser que lorsque le fichier est exécuté par la tache planifiée
args <- commandArgs(trailingOnly = FALSE)
script_path <- sub("--file=", "", args[grep("--file=", args)])
project_path <- normalizePath(file.path(dirname(script_path), ".."))
setwd(project_path)
# Configuration du logging ------------------------------------------------------------------------------------------------------------
basicConfig(level = 'DEBUG')
log_file <- "logs/script_routine.log"
log_con <- file(log_file, open = "wt")
# Fonction pour exécuter un script et capturer les logs -------------------------------------------------------------------------------
execute_script <- function(script_path) {
tryCatch({
source(script_path)
loginfo("Script exécuté avec succès : %s", script_path)
return(TRUE)
}, error = function(e) {
logerror("Erreur lors de l'exécution du script %s : %s", script_path, e$message)
return(FALSE)
})
}
sink(log_con, type = "message")
sink(log_con, type = "output")
# Exécution de la mise à jour du datamart ---------------------------------------------------------------------------------------------
start_time <- Sys.time()
datamart_success <- execute_script("data-raw/datamartage.R")
end_time <- Sys.time()
if (datamart_success) {
execution_time <- end_time - start_time
loginfo("Mise à jour du datamart catalogueR réussie")
# Récupérer la taille du datamart
datamart_file <- "datamart_catalogue.RData"
datamart_size <- file.info(datamart_file)$size
loginfo("Taille du datamart : %s bytes", datamart_size)
loginfo("Temps d'exécution : %s minutes", execution_time)
} else {
logerror("Échec de la mise à jour du datamart catalogueR")
}
# Exécution du déploiement de l'application -------------------------------------------------------------------------------------------
deploy_success <- execute_script("dev/deploiemt_svr_dataviz.R")
if (deploy_success) {
loginfo("Déploiement de l'application réussi")
} else {
logerror("Échec du déploiement de l'application")
}
# Fermer les connexions de fichier ----------------------------------------------------------------------------------------------------
sink(type = "message")
sink(type = "output")
close(log_con)
...@@ -3,58 +3,12 @@ library(tidyverse) ...@@ -3,58 +3,12 @@ library(tidyverse)
library(datalibaba) library(datalibaba)
library(purrr) library(purrr)
library(shinygouv) library(shinygouv)
library(sf)
# Création des une connexion à la base de données library(mapview)
role <- "does" library(DBI)
db_list <- c(consultation = datalibaba::connect_to_db("consultation", user = role), # chargement du datamart en fonction du contexte d'exécution de l'app
referentiels = datalibaba::connect_to_db("referentiels", user = role), nom_local <- "datamart_catalogue.RData"
datamart = datalibaba::connect_to_db("datamart", user = role), adresse_T <- paste0("T:/datalab/SCTE/CATALOGUE/PRODUCTION/", nom_local)
si_eau = datalibaba::connect_to_db("si_eau", user = role)) if(file.exists(adresse_T)) load(file = adresse_T) else load(nom_local)
liste_bases <- bases_avec_commentaires$base %>% setNames(bases_avec_commentaires$display_name)
# Récupère les schémas chaque base de données
db_schema_list <- map2_dfr(.x = db_list, .y = names(db_list),
~list_schemas(.x) %>%
enframe(name = NULL, value = "nom_schema") %>%
filter(!grepl("^zz_|^z_", nom_schema), !(nom_schema %in% c("pg_catalog", "public"))) %>% #"information_schema",
arrange(nom_schema) %>%
mutate(base = .y) %>%
rowid_to_column(var = "id_schema"))
# une fonction qui récupère la liste des tables pour une ligne de db_schema_list
lister_tables <- function(i = 1) {
datalibaba::list_tables(db = db_schema_list$base[i], schema = db_schema_list$nom_schema[i], con = db_list[[db_schema_list$base[i]]]) %>%
enframe(name = NULL, value = "table") %>%
cross_join(db_schema_list[i, ])
}
# Récupère les tables pour chaque base de données
info_0 <- map_dfr(db_schema_list$id_schema, .f = lister_tables)
info <- info_0 %>%
# on écarte les tables dont le nom comprend des majuscules car il faut les quoter
# mutate(table = if_else(tolower(table) != table, paste0('"', table, '"'), table)) %>%
filter(tolower(table) == table, nom_schema != "culture_societe_service")
# Récupération des métadonnées
## 1- toutes les tables des schémas des bases listées dans db_list
metadata_schemas <- map_dfr(db_list, ~DBI::dbGetQuery(.x, "SELECT table_catalog AS base, table_schema AS nom_schema, table_name AS nom_table,
column_name AS nom_col, ordinal_position AS num_ordre, udt_name AS type
FROM information_schema.columns")) %>%
filter(nom_schema %in% info$nom_schema) %>%
arrange(base, nom_schema, nom_table, num_ordre)
commentaires <- map_dfr(.x = c(1:nrow(info)), # les 52/53 en erreur à causes des majuscules dans le nom des champs qui font planter get_table_comments même si absente de la liste
.f = ~(get_table_comments(table = info$table[.x], schema = info$nom_schema[.x], db = info$base[.x], user = role) %>%
mutate(nom_col = coalesce(nom_col, "Toutes, commentaire de table"), base = info$base[.x]))
)
# la relation « culture_societe_service.arc_n_perimetre_fusion_mh_r52 » n'existe pas
base_recherche <- full_join(metadata_schemas, commentaires, by = c("base", "nom_schema", "nom_table", "nom_col")) %>%
distinct() %>%
arrange(base, nom_schema, nom_table)
save.image(file = "sauvegarde.RData")
commentaires_1_51 <- commentaires
shinyApp(ui, server)
── Attaching core tidyverse packages ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.5
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.5.1 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.1
✔ purrr 1.0.2
── Conflicts ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
2024-08-01 15:35:51.133374 INFO::Script exécuté avec succès : data-raw/datamartage.R
Messages d'avis :
1: le package 'tidyverse' a été compilé avec la version R 4.3.3
2: le package 'tibble' a été compilé avec la version R 4.3.3
3: le package 'tidyr' a été compilé avec la version R 4.3.3
4: le package 'readr' a été compilé avec la version R 4.3.3
5: le package 'purrr' a été compilé avec la version R 4.3.3
6: le package 'dplyr' a été compilé avec la version R 4.3.3
7: le package 'stringr' a été compilé avec la version R 4.3.3
8: le package 'forcats' a été compilé avec la version R 4.3.3
9: le package 'lubridate' a été compilé avec la version R 4.3.3
2024-08-01 15:35:51.146315 INFO::Mise à jour du datamart catalogueR réussie
2024-08-01 15:35:51.161657 INFO::Taille du datamart : 613731 bytes
2024-08-01 15:35:51.163688 INFO::Temps d'exécution : 8.98370524644852 minutes
Attachement du package : 'RCurl'
L'objet suivant est masqué depuis 'package:tidyr':
complete
2024-08-01 15:35:52.923841 INFO::Script exécuté avec succès : dev/deploiemt_svr_dataviz.R
Message d'avis :
le package 'RCurl' a été compilé avec la version R 4.3.2
2024-08-01 15:35:52.925733 INFO::Déploiement de l'application réussi
server <- function(input, output) { server <- function(input, output, session) {
# Fonction pour récupérer les informations sur les tables, les schémas et les bases de données r <- reactiveValues(
selected_metadata = NULL, # table de metadonnées à afficher
selected_metadata_base = NULL, # table de metadonnées de la base à telécharger
selected_metadata_schema = NULL , # table de metadonnées du schema à télécharger
selected_metadata_cmt = NULL, # commentaires de base/schema/table/
selected_data = NULL, # table selectionnee
isSpatial = FALSE, # booleen pour identifier les tables spatiales
role = "dreal", # on initialise la connexion au SGBD avec le rôle de connexion dreal par défaut
acces = FALSE,
table_rows = NULL,
table_size = NULL,
title_metadata = NULL
)
observeEvent(input$base, {
selected_base <- input$base
req(selected_base)
schemas_pour_base <- db_schema_list %>%
dplyr::filter(base == selected_base)
# Affiche les informations sur les tables, les schémas et les bases de données # Vérifiez que schemas_pour_base a des éléments avant de mettre à jour
output$table_info <- renderPrint({ if(nrow(schemas_pour_base) > 0) {
database_info <- getDatabaseInfo() shiny::updateSelectInput(session, "schema", choices = c("Tous", schemas_pour_base$nom_schema %>% setNames(schemas_pour_base$display_name)),
return(database_info) selected = "Tous")
} else {
shiny::updateSelectInput(session, "schema", choices = c("Tous"), selected = "Tous")
}
}) })
observeEvent(c(input$base, input$schema), {
selected_base <- input$base
selected_schema <- input$schema
req(selected_base, selected_schema)
if (selected_schema == "Tous") {
tables_pour_schema <- character(0) # Pas de tables à afficher
} else {
tables_pour_schema <- tb_sch_base %>%
dplyr::filter(base == selected_base, nom_schema == selected_schema) %>%
dplyr::pull(table)
}
if(length(tables_pour_schema) > 0) {
shiny::updateSelectInput(session, "table", choices = c("Toutes", tables_pour_schema), selected = "Toutes")
} else {
shiny::updateSelectInput(session, "table", choices = c("Toutes"), selected = "Toutes")
}
})
# Afficher le tableau selected_metadata uniquement si le bouton est cliqué
observeEvent(input$visualiserMetadata, {
selected_base <- input$base
selected_schema <- input$schema
selected_table <- input$table
r$selected_data <- NULL
#r$acces <- FALSE
r$data_csv <- NULL
req(selected_base, selected_schema, selected_table)
if (selected_table == "Toutes") {
if (selected_schema == "Tous") {
# Cas où "Toutes" est sélectionné pour table et schema
r$selected_metadata_base <- commentaires_schema %>%
dplyr::filter(base == selected_base) %>%
dplyr::select(base, nom_schema, commentaire)
r$selected_metadata <- r$selected_metadata_base %>%
dplyr::select(-base)
r$selected_metadata_cmt <- NULL
r$fil_ariane <- NULL
r$selected_row100 <- NULL
r$isSpatial <- NULL
r$nom_csv <- paste(selected_base, Sys.Date(), sep = ".")
r$nom_meta_csv <- paste("matadonnées",selected_base, Sys.Date(), sep = ".")
r$data_csv <- r$selected_metadata_base
#Affichage du commentaire de la base
r$title_metadata <- selected_base
r$commentaire <- bases_avec_commentaires %>%
filter(base == selected_base) %>%
pull(commentaire) %>%
unique()
r$table_rows <- NULL
r$table_size <- NULL
} else {
# Cas où une base, un schéma sont sélectionnés et "Toutes" pour les tables
r$selected_metadata_schema <- tables_catalog %>%
dplyr::filter(base == selected_base, nom_schema == selected_schema) %>%
dplyr::group_by(nom_table) %>%
dplyr::slice_tail() %>%
dplyr::select(base, nom_schema, nom_table, commentaire)
r$selected_metadata <- r$selected_metadata_schema %>%
dplyr::select(- c(base,nom_schema))
r$selected_metadata_cmt <- commentaires_schema %>%
dplyr::filter(base == selected_base, nom_schema == selected_schema) %>%
dplyr::pull(commentaire)
r$fil_ariane <- tags$nav(
class = "fr-breadcrumb",
class = "fr-breadcrumb__list",
tags$span(id = "base_text", class = "fr-breadcrumb__item", selected_base),
tags$span(" > "),
tags$span(id = "schema_text", class = "fr-breadcrumb__item", selected_schema)
)
r$selected_row100 <- NULL
r$isSpatial <- NULL
r$nom_csv <- paste(selected_base, selected_schema, Sys.Date(), sep = ".")
r$nom_meta_csv <- paste("metadonnees", selected_base, selected_schema, Sys.Date(), sep = ".")
r$data_csv <- r$selected_metadata_schema
#Affichage du commentaire du schema
r$title_metadata <- selected_schema # Définir title_metadata pour schéma
r$commentaire <- commentaires_schema %>%
filter(base == selected_base, nom_schema == selected_schema) %>%
pull(commentaire) %>%
unique()
r$table_rows <- NULL
r$table_size <- NULL
}
} else {
# Cas où une base, un schéma, et une table sont sélectionnés
r$selected_metadata_0 <- tables_catalog %>%
dplyr::filter(base == selected_base, nom_schema == selected_schema, nom_table == selected_table)
# dictionnaire d'attribut
r$selected_metadata <- r$selected_metadata_0 %>%
dplyr::filter(nom_col != "") %>%
dplyr::select(nom_col, commentaire, type, type_fr)
# commentaire de table
r$selected_metadata_cmt <- r$selected_metadata_0 %>%
dplyr::filter(nom_col == "") %>%
dplyr::pull(commentaire)
# Établir la connexion à la base de données
conn <- datalibaba::connect_to_db(
db = selected_base,
user = "does"
)
# Récupérer le nombre de lignes et la taille de la table
r$table_rows <- dbGetQuery(conn, paste0("SELECT COUNT(*) AS n_rows FROM ", selected_schema, ".", selected_table))$n_rows
r$table_size <- dbGetQuery(conn, paste0("SELECT pg_size_pretty(pg_relation_size('", selected_schema, ".", selected_table, "')) AS table_size"))$table_size
# Fermer la connexion par prudence
dbDisconnect(conn)
rm(conn)
# aperçu de la table: gerer les connexions refusées avec un message d'erreur
tryCatch({
r$selected_row100 <- datalibaba::importer_data(table = selected_table, schema = selected_schema, db = selected_base, user = r$role, limit = 30)
}, error = function(e) {
message("Erreur lors de la récupération des données de la table : ", e$message)
r$selected_row100 <- NULL
})
r$acces <- isTruthy(r$selected_row100)
r$isSpatial <- any(grepl("spatial", r$selected_metadata$type_fr))
r$fil_ariane <- tags$nav(
class = "fr-breadcrumb",
class = "fr-breadcrumb__list",
tags$span(id = "base_text", class = "fr-breadcrumb__item", selected_base),
tags$span(" > "),
tags$span(id = "schema_text", class = "fr-breadcrumb__item", selected_schema),
tags$span(" > "),
tags$span(id = "table_text", class = "fr-breadcrumb__item", selected_table)
)
r$nom_csv <- paste(selected_base, selected_schema, selected_table, Sys.Date(), sep = ".")
r$nom_meta_csv <- paste("metadonnées", selected_base, selected_schema, selected_table, Sys.Date(), sep = ".")
r$data_csv <- r$selected_metadata
r$title_metadata <- selected_table # Définir title_metadata pour table
r$commentaire <- r$selected_metadata_cmt
}
})
# Mettre à jour la table de métadonnées en sortie
output$metadata_section <- renderUI({
req(r$selected_metadata)
tagList(
if (input$table != "Toutes") tags$h4("Dictionnaire d'attributs"),
DT::dataTableOutput("data_table")
)
})
# Mettre à jour l'affichage du fil d'Ariane en utilisant les variables réactives
output$breadcrumb_metadata <- renderUI({
r$fil_ariane
})
output$title_metadata <- renderUI({
req(r$title_metadata)
tags$h4(r$title_metadata)
})
output$commentaire_metadata <- renderUI({
req(r$commentaire)
tags$p(tags$strong("Descriptif :"), r$commentaire)
})
output$table_metadata <- renderUI({
req(r$table_rows, r$table_size)
div(id = "div_meta", class = "fr-highlight",
tags$p(tags$strong("Nombre de lignes :"), format(r$table_rows, big.mark = "\u202f", scientific = FALSE)),
tags$p(tags$strong("Taille de la table :"), r$table_size)
)
})
output$data_table <- DT::renderDataTable({
req(r$selected_metadata)
DT::datatable(
r$selected_metadata,
filter = 'bottom',
extensions = 'Buttons',
rownames = FALSE,
options = list(
dom = 'Bfrtip',
pageLength = 20,
lengthMenu = c(20, 50, 100),
language = list(url = 'https://cdn.datatables.net/plug-ins/1.10.21/i18n/French.json'),
autoWidth = FALSE,
scrollX = TRUE, # Activer le défilement horizontal
buttons = list(
list(
extend = 'csv',
text = 'Télécharger CSV',
filename = r$nom_meta_csv
)
)
)
)
})
# Rendre le bouton de visualisation des données conditionnellement (seulement si métadonnées visualisées ET droits accès à la table ok)
output$viz_data <- renderUI({
req(r$acces)
if(input$table != "Toutes") {
shinygouv::actionButton_dsfr("data_a_viz", "Visualiser les données", class = "fr-my-3w")
} else {
return(NULL)
}
})
# "Visualiser les données"
observeEvent(input$data_a_viz, {
selected_base <- sub(" : .*", "", input$base)
selected_schema <- sub(" : .*", "", input$schema)
selected_table <- sub(" : .*", "", input$table)
req(r$acces)
r$selected_data <- datalibaba::importer_data(table = selected_table, schema = selected_schema, db = selected_base, user = r$role)
r$data_csv <- sf::st_drop_geometry(r$selected_data)
})
# Mettre à jour l'affichage des données dans la zone principale de la page
output$data_table_preview <- DT::renderDataTable({
validate(
need(input$schema != "Tous", "Veuillez sélectionner un schéma et une table spécifiques."),
need(input$table != "Toutes", "Veuillez sélectionner une table.")
)
req(r$selected_data)
DT::datatable(head(r$data_csv, 100),
filter = 'bottom',
extensions = 'Buttons',
rownames = FALSE,
options = list(
dom = 'Bfrtip',
pageLength = 20,
lengthMenu = c(20, 50, 100),
language = list(url = 'https://cdn.datatables.net/plug-ins/1.10.21/i18n/French.json'),
autoWidth = FALSE,
scrollX = TRUE, # Activer le défilement horizontal
buttons = list(
list(
extend = 'csv',
text = 'Télécharger CSV',
filename = r$nom_csv
)
)
)
)
})
# Mettre à jour l'affichage des données dans la zone principale de la page
output$map <- renderLeaflet({
req(r$selected_data)
if (r$isSpatial) {
mapview(r$selected_data, layer.name = "aperçu")@map
} else {
return(NULL)
}
})
# Recherche plein texte-------------------------------------
observeEvent(input$search_button, {
filtered_data <- reactive({
if (is.null(input$search_784_input) || input$search_784_input == '') {
return(NULL)
}
search_results <- base_recherche_txt %>%
dplyr::filter(grepl(input$search_784_input, description, ignore.case = TRUE)) %>%
dplyr::select(base, nom_schema, nom_table)
if (nrow(search_results) > 0) {
search_results <- search_results %>%
left_join(tables_catalog %>%
dplyr::filter(nom_col == "") %>%
dplyr::select(base, nom_schema, nom_table, commentaire),
by = c("base", "nom_schema", "nom_table")) %>%
dplyr::rename(Libellé = commentaire)%>%
dplyr::distinct() # Éliminer les doublons
}
search_results
})
# Mettre à jour les résultats de recherche affichés
output$search_results <- DT::renderDataTable({
DT::datatable(
filtered_data(),
filter = 'bottom',
options = list(
pageLength = 20,
lengthMenu = c(20, 50, 100),
language = list(url = 'https://cdn.datatables.net/plug-ins/1.10.21/i18n/French.json'),
autoWidth = FALSE,
scrollX = TRUE # Activer le défilement horizontal
)
)
})
output$search_message <- renderUI({
results <- filtered_data()
if (is.null(results) || nrow(results) == 0) {
tagList(
p(
"Aucun lot de données ne correspond à votre recherche, veuillez renouveler votre recherche ou explorer les bases de données disponibles (2e onglet)",
actionLink("go_to_explorer", "Aller à Explorer", style = "margin-top: 10px; color: blue;")
)
)
} else {
NULL
}
})
})
observeEvent(input$go_to_explorer, {
updateTabsetPanel_dsfr(session = session, inputId = "mon_panel1", selected = "Explorer")
})
} }
library(shinygouv)
library(shiny)
library(leaflet)
library(DT)
ui <- fluidPage_dsfr( ui <- fluidPage_dsfr(
titlePanel("Explorateur de la base de données de la DREAL"), header = header_dsfr(
sidebarLayout( intitule = c("PREFET", "DE LA REGION", "PAYS DE LA LOIRE"),
sidebarPanel( nom_site_service = "Catalogue de données de la DREAL Pays de la Loire",
# Ajoutez des éléments de contrôle si nécessaire ),
footer = footer_dsfr(
intitule = c("PREFET", "DE LA REGION", "PAYS DE LA LOIRE"),
description = "Une application de la DREAL des Pays de la Loire",
accessibilite = "non"
),
tabsetPanel_dsfr(
id = "mon_panel1",
tabPanel_dsfr(
id = "rechercher",
title = "Rechercher",
content = fluidPage_dsfr(
h3("Rechercher un lot de données dans le patrimoine de la DREAL"),
search_bar(),
DT::dataTableOutput("search_results"),
uiOutput("search_message")
)
),
tabPanel_dsfr(
id = "explorer",
title = "Explorer",
content = fluidPage_dsfr(
sidebarLayout(
sidebarPanel(
h3("Explorer les bases de données du patrimoine de la DREAL"),
selectInput_dsfr("base", "Choisir la base", choices = liste_bases, selected = NULL), # Sélection de la base
shinygouv::selectInput_dsfr("schema", "Choisir le schéma", NULL), # Sélection du nom du schéma
shinygouv::selectInput_dsfr("table", "Choisir la table", NULL), # Sélection du nom de la table
shinygouv::actionButton_dsfr("visualiserMetadata", "Visualiser les métadonnées")# Bouton de validation pour visualiser les métadonnées
),
mainPanel(
uiOutput("breadcrumb_metadata"),
uiOutput("title_metadata"), # Titre de l'objet sélectionné
uiOutput("commentaire_metadata"),
uiOutput("table_metadata"), #Nb de lignes et taille de la table
uiOutput("metadata_section"), # Section des métadonnées avec "Dictionnaire d'attributs"
uiOutput("viz_data"), # Visualiser le table des données
DT::dataTableOutput("data_table_preview"),
leaflet::leafletOutput("map")
)
)
)
), ),
mainPanel( tabPanel_dsfr(
h3("Tables, Schémas et Bases de données"), id = "a_propos",
verbatimTextOutput("table_info") title = "À propos",
content = fluidPage_dsfr(
h3("À propos"),
includeMarkdown("www/about.md"),
div(paste0("Date de mise à jour des métadonnées affichées : ", date_datamart))
)
),
tabPanel_dsfr(
id = "mentions_legales",
title = "Mentions légales",
content = fluidPage_dsfr(
h3("Mentions légales"),
includeMarkdown("www/legal_notice.md")
)
) )
) )
) )
#### Objectif
Le Catalogue de données de la DREAL vise à faciliter la découverte et l'accès aux données stockées dans les bases de donnés internes de la DREAL.
#### Fonctionnalités
L'onglet **"Rechercher"** permet :
- d'effectuer une recherche textuelle à partir de mots-clés au d'expression,
- d'afficher en résultat un tableau de [tables](https://fr.wikipedia.org/wiki/Table_(base_de_donn%C3%A9es)) correspondant à la recherche.
L'onglet **"Explorer"** :
- de naviguer parmi les bases de données, schémas et tables associés,
- d'afficher en résultat un tableau de schémas ou de tables correspondants à la recherche.
Les deux options permettent ensuite de visualiser :
- le [dictionnaire des données](https://fr.wikipedia.org/wiki/Dictionnaire_des_donn%C3%A9es),
- le tableau des données,
- un aperçu des données spatiales.
#### Charte de nommage
Les noms de tous les objets des bases de données (schémas, tables, champs, etc.) doivent être choisis selon une charte présentée dans la fiche de procédure [Organisation des bases de données sur le SGBD PostgreSQL](http://set-pdl-wiki.dreal-pdl.ad.e2.rie.gouv.fr/outils/sgbd/organisation-bases-postgresql).
#### Service gestionnaire
**Direction Régionale de l’Environnement de l’Aménagement et du Logement des Pays de la Loire**
5 rue Françoise Giroud
CS 16326
44263 NANTES Cedex 2
**Tél :** 02 72 74 73 00
**Fax :** 02 72 74 73 09
**Courriel :** dreal-paysdelaloire@developpement-durable.gouv.fr
#### Directrice de publication
Anne Beauval, directrice régionale de l’environnement, de l’aménagement et du logement des Pays de la Loire.
#### Conception, Réalisation
- Charte graphique, ergonomie : [{shinygouv}](https://github.com/spyrales/shinygouv)
- Développement : Lisa SMAH, Juliette ENGELAERE-LEFEBVRE, DREAL Pays de la Loire
#### Hébergement
- DREAL Pays de la Loire
#### Droit d’auteur - Licence
Tous les contenus présents sur Ce site de la direction régionale de l’Environnement, de l’Aménagement et du Logement des Pays de la Loire sont couverts par le droit d’auteur. Toute reprise est dès lors conditionnée à l’accord de l’auteur en vertu de l’article L.122-4 du Code de la Propriété Intellectuelle.
#### Établir un lien
- Tout site public ou privé est autorisé à établir, sans autorisation préalable, un lien vers les informations diffusées par le Ministère de la Transition écologique et le Ministère de la Cohésion des Territoires et des Relations avec les Collectivités Territoriales.
- L’autorisation de mise en place d’un lien est valable pour tout support, à l’exception de ceux diffusant des informations à caractère polémique, pornographique, xénophobe ou pouvant, dans une plus large mesure porter atteinte à la sensibilité du plus grand nombre.
- Pour ce faire, et toujours dans le respect des droits de leurs auteurs, une icône "Marianne" est disponible sur le site de [la marque de l'Etat](https://www.gouvernement.fr/marque-Etat) pour agrémenter votre lien et préciser que le site d’origine est celui du Ministère de la Transition écologique ou du Ministère de la Cohésion des Territoires et des Relations avec les Collectivités Territoriales.
#### Usage
- Les utilisateurs sont responsables des interrogations qu’ils formulent ainsi que de l’interprétation et de l’utilisation qu’ils font des résultats. Il leur appartient d’en faire un usage conforme aux réglementations en vigueur et aux recommandations de la CNIL lorsque des données ont un caractère nominatif (loi n° 78.17 du 6 janvier 1978, relative à l’informatique, aux fichiers et aux libertés dite loi informatique et libertés).
- Il appartient à l’utilisateur de ce site de prendre toutes les mesures appropriées de façon à protéger ses propres données et/ou logiciels de la contamination par d’éventuels virus circulant sur le réseau Internet. De manière générale, la Direction Régionale de l’Environnement de l’Aménagement et du Logement des Pays de la Loire décline toute responsabilité à un éventuel dommage survenu pendant la consultation du présent site. Les messages que vous pouvez nous adresser transitant par un réseau ouvert de télécommunications, nous ne pouvons assurer leur confidentialité.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment