0.18.3
This commit is contained in:
@@ -1,3 +1,11 @@
|
|||||||
|
### 0.18.2 - 0.18.3 (2026-06-18)
|
||||||
|
##### features
|
||||||
|
- возможность отражение лога действий по базам (для администраторов) и отдельно для каждой записи (сгруппированы по уникальным действиям)
|
||||||
|
- возможность экспорта таблицы со списком значений не прошедшие валидацию согласно схеме (для администраторов)
|
||||||
|
|
||||||
|
##### refactor
|
||||||
|
- перестройка структуры репозитория
|
||||||
|
|
||||||
### 0.18.1 (2026-06-08)
|
### 0.18.1 (2026-06-08)
|
||||||
##### fix
|
##### fix
|
||||||
- правильный экспорт текстовых данных
|
- правильный экспорт текстовых данных
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
options(box.path = here::here())
|
options(box.path = here::here())
|
||||||
box::use(R/modules/data_manipulations[is_this_empty_value])
|
box::use(
|
||||||
|
R/modules/data_manipulations[is_this_empty_value]
|
||||||
|
)
|
||||||
|
|
||||||
#' @export
|
#' @export
|
||||||
init_val = function(scheme, ns) {
|
init_val = function(scheme, ns) {
|
||||||
@@ -114,4 +116,134 @@ val_choice_within_a_dict = function(x, choices) {
|
|||||||
text <- paste0("'",x[!compare_to_dict],"'", collapse = ", ")
|
text <- paste0("'",x[!compare_to_dict],"'", collapse = ", ")
|
||||||
glue::glue("варианты, не соответствующие схеме: {text}")
|
glue::glue("варианты, не соответствующие схеме: {text}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ЭКСПОРТ ДАННЫХ ДЛЯ ВАЛИДАЦИИ
|
||||||
|
#' @export
|
||||||
|
validate_value_for_form <- function(data_to_check, form_type, choices, val_required) {
|
||||||
|
|
||||||
|
res <- NULL
|
||||||
|
# for `number` type: if in `choices` column has values then parsing them to range validation
|
||||||
|
# value `0; 250` -> transform to rule validation value from 0 to 250
|
||||||
|
if (form_type == "number") {
|
||||||
|
|
||||||
|
res <- val_is_a_number(data_to_check)
|
||||||
|
if(!is.null(res)) return(res)
|
||||||
|
|
||||||
|
# проверка на соответствие диапазону значений
|
||||||
|
if (!is.na(choices)) {
|
||||||
|
|
||||||
|
# разделить на несколько елементов
|
||||||
|
ranges <- as.integer(stringr::str_split_1(choices, "; "))
|
||||||
|
|
||||||
|
# проверка на кол-во значений
|
||||||
|
if (length(ranges) > 3) {
|
||||||
|
warning("Количество переданных элементов'", x_input_id, "' > 2")
|
||||||
|
} else {
|
||||||
|
|
||||||
|
res <- val_number_within_a_range(data_to_check, ranges = ranges)
|
||||||
|
if (!is.null(res)) return(res)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (form_type %in% c("select_multiple", "select_one", "radio", "checkbox")) {
|
||||||
|
|
||||||
|
if (!is_this_empty_value(data_to_check)) {
|
||||||
|
split_data <- stringr::str_split_1(data_to_check, "; ")
|
||||||
|
} else {
|
||||||
|
split_data <- NA
|
||||||
|
}
|
||||||
|
|
||||||
|
res <- val_choice_within_a_dict(split_data, choices = choices)
|
||||||
|
if(!is.null(res)) return(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
# if in `required` column value is `1` apply standart validation
|
||||||
|
if (!is.na(val_required) && val_required == 1) {
|
||||||
|
|
||||||
|
if (is_this_empty_value(data_to_check)) {
|
||||||
|
|
||||||
|
res <- "Необходимо заполнить."
|
||||||
|
if(!is.null(res)) return(res)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is.null(res)) return(NA)
|
||||||
|
}
|
||||||
|
|
||||||
|
#' @export
|
||||||
|
get_table_with_data_validation_info <- function(schm, con) {
|
||||||
|
|
||||||
|
# итерациям по всем таблицам
|
||||||
|
purrr::map(
|
||||||
|
purrr::set_names(schm$all_tables_names),
|
||||||
|
.f = \(table_name) {
|
||||||
|
|
||||||
|
scheme <- schm$get_scheme(table_name)
|
||||||
|
data <- DBI::dbReadTable(con, table_name)
|
||||||
|
|
||||||
|
inputs_simple_list <- schm$get_id_type_list(table_name)
|
||||||
|
|
||||||
|
main_key <- schm$get_main_key_id
|
||||||
|
key <- schm$get_key_id(table_name)
|
||||||
|
|
||||||
|
# итерация по всем form_id в текущей таблице
|
||||||
|
ff <- purrr::map2(
|
||||||
|
.x = names(inputs_simple_list),
|
||||||
|
.y = unname(inputs_simple_list),
|
||||||
|
.f = \(x_input_id, y_form_type) {
|
||||||
|
|
||||||
|
this_id_scheme <- dplyr::filter(scheme, form_id == {{x_input_id}})
|
||||||
|
|
||||||
|
choices <- this_id_scheme$choices
|
||||||
|
val_required <- unique(this_id_scheme$required)
|
||||||
|
|
||||||
|
# extract data
|
||||||
|
data_to_check <- data[[x_input_id]]
|
||||||
|
main_keys <- data[[main_key]]
|
||||||
|
keys <- data[[key]]
|
||||||
|
iter <- purrr::set_names(data_to_check, keys)
|
||||||
|
|
||||||
|
# cli::cli_inform("~ input_id: {x_input_id} | type: {form_type} | value: {data_to_check}")
|
||||||
|
validation_info <- purrr::map(iter, validate_value_for_form, y_form_type, choices, val_required)
|
||||||
|
|
||||||
|
df_with_result_and_validation_for_id <- tibble::enframe(validation_info, name = key, value = "value") |>
|
||||||
|
tidyr::unnest(cols = c(value))
|
||||||
|
|
||||||
|
# если главный ключ и ключ для таблицы не одно и тоже, добавление главного ключа в таблицу
|
||||||
|
if (main_key != key) {
|
||||||
|
df_with_result_and_validation_for_id[main_key] <- main_keys
|
||||||
|
}
|
||||||
|
|
||||||
|
df_with_result_and_validation_for_id |>
|
||||||
|
dplyr::mutate(form_id = x_input_id)
|
||||||
|
|
||||||
|
}) |>
|
||||||
|
purrr::list_rbind()
|
||||||
|
|
||||||
|
ff |>
|
||||||
|
dplyr::distinct() |>
|
||||||
|
dplyr::filter(!is.na(value)) |>
|
||||||
|
# данные схемы для 'читабельности информации'
|
||||||
|
dplyr::left_join(
|
||||||
|
y = scheme |> dplyr::distinct(form_id, form_label) |> dplyr::mutate(nr = dplyr::row_number()),
|
||||||
|
by = dplyr::join_by(form_id),
|
||||||
|
) |>
|
||||||
|
# сортировка (main_key, затем id формы - по порядку в схеме)
|
||||||
|
dplyr::arrange(!!rlang::sym(main_key), !!rlang::sym(main_key), nr) |>
|
||||||
|
dplyr::select(
|
||||||
|
!!rlang::sym(main_key), !!rlang::sym(main_key),
|
||||||
|
form_id,
|
||||||
|
form_label,
|
||||||
|
value
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
50
app.R
50
app.R
@@ -157,6 +157,7 @@ server <- function(input, output, session) {
|
|||||||
strong("Дополнительные опции:"),
|
strong("Дополнительные опции:"),
|
||||||
verticalLayout(
|
verticalLayout(
|
||||||
actionButton("logs-show_last_actions", "Все действия", icon("scroll", lib = "font-awesome"), style = "width: 250px; margin-top: 10px"),
|
actionButton("logs-show_last_actions", "Все действия", icon("scroll", lib = "font-awesome"), style = "width: 250px; margin-top: 10px"),
|
||||||
|
downloadButton("download_data_validation_info", "Некорректно заполненные данные (.xlsx)", icon("scroll", lib = "font-awesome"), style = "width: 250px; margin-top: 10px"),
|
||||||
fluid = FALSE
|
fluid = FALSE
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -1279,7 +1280,7 @@ server <- function(input, output, session) {
|
|||||||
keys_to_delete <- all_existed_keys[all_existed_keys %in% all_new_keys]
|
keys_to_delete <- all_existed_keys[all_existed_keys %in% all_new_keys]
|
||||||
keys_to_delete <- paste0("'", keys_to_delete, "'", collapse = ", ")
|
keys_to_delete <- paste0("'", keys_to_delete, "'", collapse = ", ")
|
||||||
|
|
||||||
DBI::dbExecute(connection(), glue::glue("DELETE FROM {table_name} WHERE \"{main_key_id}\" IN ({keys_to_delete})"))
|
DBI::dbExecute(con, glue::glue("DELETE FROM {table_name} WHERE \"{main_key_id}\" IN ({keys_to_delete})"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1336,6 +1337,7 @@ server <- function(input, output, session) {
|
|||||||
"loading data",
|
"loading data",
|
||||||
"creating new key",
|
"creating new key",
|
||||||
"exporting data to xlsx",
|
"exporting data to xlsx",
|
||||||
|
"export validation dataset",
|
||||||
"importing data from xlsx"
|
"importing data from xlsx"
|
||||||
),
|
),
|
||||||
key = NA,
|
key = NA,
|
||||||
@@ -1363,6 +1365,52 @@ server <- function(input, output, session) {
|
|||||||
# SHOW LOGS -----------------------------------
|
# SHOW LOGS -----------------------------------
|
||||||
logs$server("logs", values, scheme, mhcs)
|
logs$server("logs", values, scheme, mhcs)
|
||||||
|
|
||||||
|
# экспорт таблицы с информации о валидации данных -------------------
|
||||||
|
output$download_data_validation_info <- downloadHandler(
|
||||||
|
filename = function(){
|
||||||
|
paste0("dvinfo_", isolate(scheme()), "_", format(Sys.time(), "%Y%m%d_%H%M%S"), ".xlsx")
|
||||||
|
},
|
||||||
|
content = function(file) {
|
||||||
|
req(main_form_is_empty() != "empty")
|
||||||
|
|
||||||
|
box::use(
|
||||||
|
R/modules/data_validation[get_table_with_data_validation_info]
|
||||||
|
)
|
||||||
|
|
||||||
|
con <- db$make_db_connection(isolate(scheme()),"download_data_validation_info")
|
||||||
|
on.exit(db$close_db_connection(con, "download_data_validation_info"), add = TRUE)
|
||||||
|
|
||||||
|
list_of_df <- get_table_with_data_validation_info(mhcs(), con)
|
||||||
|
|
||||||
|
# добавить мета информацию
|
||||||
|
list_of_df[["meta"]] <- dplyr::tribble(
|
||||||
|
~`Параметр` , ~`Значение`,
|
||||||
|
"Пользователь" , values$current_user,
|
||||||
|
"Название базы" , names(ENABLED_SCHEMES)[ENABLED_SCHEMES == scheme()],
|
||||||
|
"id базы" , scheme(),
|
||||||
|
"id формы" , config::get("form_id"),
|
||||||
|
"ver формы" , config::get("form_app_version"),
|
||||||
|
"Время выгрузки" , format(Sys.time(), "%d.%m.%Y %H:%M:%S"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# set date params
|
||||||
|
options("openxlsx2.dateFormat" = "dd.mm.yyyy")
|
||||||
|
|
||||||
|
cli::cli_alert_success("Данные успешно экспортированы")
|
||||||
|
showNotification("Данные успешно экспортированы", type = "message")
|
||||||
|
log_action_to_db("export validation dataset", con = con)
|
||||||
|
|
||||||
|
# pass tables to export
|
||||||
|
openxlsx2::write_xlsx(
|
||||||
|
purrr::compact(list_of_df),
|
||||||
|
file,
|
||||||
|
na.strings = "",
|
||||||
|
as_table = TRUE,
|
||||||
|
col_widths = 20
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app <- shiny::shinyApp(ui = ui, server = server)
|
app <- shiny::shinyApp(ui = ui, server = server)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
default:
|
default:
|
||||||
form_app_version: 0.18.2
|
form_app_version: 0.18.3
|
||||||
form_id: formy
|
form_id: formy
|
||||||
form_name: FORMY
|
form_name: FORMY
|
||||||
Reference in New Issue
Block a user