diff --git a/.gitignore b/.gitignore index 1a38f03..69fa24b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,8 @@ /renv /temp +/_devel scheme.rds -configs/schemas/d2tra_t.xlsx -configs/schemas/antifib.xlsx -/_devel .Renviron .DS_Store .lintr diff --git a/README.md b/README.md index 074806e..6291e1b 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,45 @@ ... +# Quick start + +## локально: + +Копирование содержимого репозитория +```bash +git clone https://gitea.madelirihs.ru/madeliri/shiny_form.git +``` + +Восстановление окружения +```r +renv::init() +``` + +# Насторйки + +## переменные окружения + +### работа с авторизацией + +Пароль базы данных с авторизацией необходимо указать в `.Renviron`: +``` +AUTH_DB_KEY = "this_is_your_password" +``` + +### бэкапы локальных баз + +Для создания бэкапов локальных баз данных, необходимо указать путь куда будут сохранятся бэкапы в переменной окружения: +``` +FORM_APP_LOCAL_DB_BACKUP_PATH="path_to_backups" +``` + +Проверка осуществляется при каждом запуске приложения, бэкапы создаются раз в день (при первом запуске). + +Количество сохраняемых бэкапов: +``` +FORM_APP_LOCAL_DB_BACKUP_LIMITS=3 +``` + # Cтруктура `schema.xlsx` @@ -41,11 +80,6 @@ ## Авторизация -Пароль базы данных с авторизацией необходимо указать в `.Renviron`: - -``` -AUTH_DB_KEY = "this_is_your_password" -``` # trade-ofs diff --git a/config.yml b/config.yml index f4f9f7f..5d07fb3 100644 --- a/config.yml +++ b/config.yml @@ -1,15 +1,13 @@ default: form_app_version: 0.15.0 + form_id: new_formy + form_name: NEW FORMY prod: form_app_configure_path: "." form_auth_enabled: true - form_id: new_formy - form_name: NEW FORMY devel: form_app_configure_path: _devel/d2tra form_auth_enabled: false - form_id: new_formy - form_name: NEW FORMY form_app_version: 0.15.0 dev \ No newline at end of file diff --git a/modules/db.R b/modules/db.R index fa7bc2c..563d054 100644 --- a/modules/db.R +++ b/modules/db.R @@ -336,3 +336,71 @@ excel_to_db_dates_converter = function(date) { fin_date <- as.character(format(fin_date, "%Y-%m-%d")) fin_date } + +#' @export +local_db_backup <- function( + db_name, + backups_paths = Sys.getenv("FORM_APP_LOCAL_DB_BACKUP_PATH"), + backups_limit = as.integer(Sys.getenv("FORM_APP_LOCAL_DB_BACKUP_LIMITS", 5)) +) { + + db_path <- fs::path(config::get("form_app_configure_path"), "db") + db_full_path <- fs::path(db_path, db_name, ext = "sqlite") + + backup_folder <- fs::path(backups_paths, db_name) + + if (!dir.exists(backup_folder)) dir.create(backup_folder, recursive = TRUE) + + date_mark <- format(Sys.time(), "%Y%m%d") + + schedule <- c( + daily = 1, + weekly = 7, + monthly = 28 + ) + + purrr::walk2( + .x = schedule, + .y = names(schedule), + .f = \(schedule_days, schedule_name) { + + # daily + daily_folder <- fs::path(backup_folder, schedule_name) + todays_backup <- fs::path(daily_folder, paste0(db_name, "_", format(Sys.time(), "%Y%m%d")), ext = "sqlite") + + if (!dir.exists(daily_folder)) dir.create(daily_folder) + + existed_files <- fs::dir_ls(daily_folder, regexp = "((?:19|20)\\d\\d)(0?[1-9]|1[012])([12][0-9]|3[01]|0?[1-9])") + existed_files <- sort(existed_files, decreasing = TRUE) + + # если бэкап для сегодняшнего дня есть - скипаем процедуру + if (todays_backup %in% existed_files) { + return() + } + + # парсим даты + dates <- stringr::str_extract(existed_files, "((?:19|20)\\d\\d)(0?[1-9]|1[012])([12][0-9]|3[01]|0?[1-9])") + dates <- as.Date(dates, "%Y%m%d") + + # если количество существующих бэкапов значимо превышает установленный лимит, удаляем лишнее + if (length(existed_files) > backups_limit) { + file.remove(utils::tail(existed_files, length(existed_files) - backups_limit)) + } + + # если количество существующих бэкапов равно имеющемуся и пора делать бэкап - делаем бэкап, удаляем послендий файл + if (length(existed_files) >= backups_limit & dates[1] + schedule_days == Sys.Date()) { + + file.remove(utils::tail(existed_files, 1)) + file.copy(db_full_path, todays_backup) + + } else if(length(existed_files) == 0) { + + file.copy(db_full_path, todays_backup) + + } + + } + ) + +} + diff --git a/modules/global_options.R b/modules/global_options.R index 840dd96..2f06e4a 100644 --- a/modules/global_options.R +++ b/modules/global_options.R @@ -40,9 +40,13 @@ check_and_init_scheme = function() { cli::cli_inform(c("*" = "проверка схемы...")) + options(box.path = here::here()) + box::use(modules/db[local_db_backup]) + options(box.path = config::get("form_app_configure_path")) box::use(configs/enabled_schemes[enabled_schemes]) + # список файлов, изменение которых, приведут к переинициализиации схемы files_to_watch <- c( fs::path(config::get("form_app_configure_path"), "configs", "enabled_schemes.R"), "modules/scheme_generator.R", @@ -53,7 +57,9 @@ check_and_init_scheme = function() { scheme_file <- paste0(config::get("form_app_configure_path"), "/configs/schemas/", scheme_names, ".xlsx") scheme_file <- stats::setNames(scheme_file, scheme_names) - if (!all(file.exists(scheme_file))) cli::cli_abort(c("Отсутствуют файлы схем для следующих наименований:", paste("-", names(scheme_file)[!file.exists(scheme_file)]))) + if (!all(file.exists(scheme_file))) { + cli::cli_abort(c("Отсутствуют файлы схем для следующих наименований:", paste("-", names(scheme_file)[!file.exists(scheme_file)]))) + } db_files <- paste0(config::get("form_app_configure_path"), "/db/", scheme_names, ".sqlite") @@ -71,8 +77,6 @@ check_and_init_scheme = function() { } else { saved_hash <- readRDS(hash_file) - print(exist_hash) - print(saved_hash) # если данные были изменены проводим реинициализацию таблицы и схемы if (!all(exist_hash == saved_hash)) { @@ -85,6 +89,13 @@ check_and_init_scheme = function() { } } + # MAKING BACKUPS + if (Sys.getenv("FORM_APP_LOCAL_DB_BACKUP_PATH") != "") { + cli::cli_inform(c("*" = "создание бэкапов баз данных...")) + purrr::walk(scheme_names, local_db_backup) + + } + # перезаписываем файл if (!dir.exists("temp")) dir.create("temp") saveRDS(exist_hash, hash_file)