├── .github ├── .gitignore ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ └── R-CMD-check.yaml ├── inst ├── binder │ ├── .gitignore │ ├── apt.txt │ └── install.R ├── joss │ ├── .gitignore │ └── paper.bib ├── extdoc │ └── ruODK.pdf ├── extdata │ ├── I8n_no_lang.xls │ ├── I8n_label_lang.xls │ ├── I8n_label_choices.xls │ ├── I8n_lang_choicefilter.xlsx │ └── I8n_no_lang_choicefilter.xlsx ├── rmarkdown │ └── templates │ │ └── odata │ │ └── template.yaml ├── CITATION └── schemaorg.json ├── tests ├── testthat │ ├── .gitignore │ ├── test-submission_get_audit.R │ ├── test-utils-lifecycle.R │ ├── test-prepend_uuid.R │ ├── test-strip_uuid.R │ ├── test-odata_metadata_get.R │ ├── test-odata_service_get.R │ ├── test-ru_msg.R │ ├── test-encryption_key_list.R │ ├── test-project_create.R │ ├── test-handle_ru_datetimes.R │ ├── test-form_detail.R │ ├── test-attachment_list.R │ ├── test-submission_detail.R │ ├── test-entity_list.R │ ├── test-form_xml.R │ ├── test-audit_get.R │ ├── test-entitylist_list.R │ ├── test-form_list.R │ ├── test-odata_submission_parse.R │ ├── test-entitylist_update.R │ ├── test-attachment_link.R │ ├── test-handle_ru_attachments.R │ ├── test-submission_list.R │ ├── test-entitylist_detail.R │ ├── test-drop_null_coords.R │ ├── test-form_schema_parse.R │ ├── test-user_list.R │ └── test-entity_detail.R └── testthat.R ├── .gitattributes ├── data ├── fs_v7.rda ├── fq_data.rda ├── fq_meta.rda ├── fq_raw.rda ├── fq_svc.rda ├── geo_fs.rda ├── geo_gj.rda ├── geo_wkt.rda ├── fs_v7_raw.rda ├── geo_gj88.rda ├── geo_gj_raw.rda ├── geo_wkt88.rda ├── fq_data_taxa.rda ├── fq_form_list.rda ├── fq_form_xml.rda ├── fq_raw_taxa.rda ├── fq_zip_data.rda ├── fq_zip_taxa.rda ├── geo_wkt_raw.rda ├── fq_attachments.rda ├── fq_data_strata.rda ├── fq_form_detail.rda ├── fq_form_schema.rda ├── fq_project_list.rda ├── fq_raw_strata.rda ├── fq_submissions.rda ├── fq_zip_strata.rda ├── fq_project_detail.rda └── fq_submission_list.rda ├── man ├── figures │ ├── bcs.png │ ├── logo.jpg │ ├── dbca_bcs.png │ ├── ruODK2.png │ ├── lifecycle-defunct.svg │ ├── lifecycle-retired.svg │ ├── lifecycle-archived.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-soft-deprecated.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-superseded.svg │ ├── lifecycle-experimental.svg │ └── lifecycle-stable.svg ├── pipe.Rd ├── lifecycle_shim.Rd ├── listcol_names.Rd ├── ru_msg_abort.Rd ├── ru_msg_info.Rd ├── ru_msg_noop.Rd ├── ru_msg_success.Rd ├── ru_msg_warn.Rd ├── odata_svc_parse.Rd ├── yell_if_error.Rd ├── semver_lt.Rd ├── semver_gt.Rd ├── fq_form_list.Rd ├── ruODK-package.Rd ├── fq_project_list.Rd ├── fs_v7_raw.Rd ├── fs_v7.Rd ├── tidyeval.Rd ├── fq_form_xml.Rd ├── fq_form_detail.Rd ├── fq_project_detail.Rd ├── fq_submission_list.Rd ├── fq_attachments.Rd ├── fq_zip_data.Rd ├── fq_zip_taxa.Rd ├── fq_zip_strata.Rd ├── geo_gj_raw.Rd ├── geo_wkt_raw.Rd ├── geo_fs.Rd ├── fq_submissions.Rd ├── geo_wkt.Rd ├── geo_gj.Rd ├── prepend_uuid.Rd ├── strip_uuid.Rd ├── fq_meta.Rd ├── fq_svc.Rd ├── predict_ruodk_name.Rd ├── geo_wkt88.Rd ├── geo_gj88.Rd ├── project_create.Rd ├── fq_raw_strata.Rd ├── parse_odkc_version.Rd ├── fq_form_schema.Rd ├── fq_raw.Rd ├── yell_if_missing.Rd ├── fq_raw_taxa.Rd ├── fq_data_strata.Rd ├── fq_data.Rd ├── isodt_to_local.Rd ├── odata_service_get.Rd ├── fq_data_taxa.Rd └── odata_metadata_get.Rd ├── .Rinstignore ├── vignettes ├── media │ ├── 1701678074209.jpg │ ├── 1701678107041.jpg │ ├── 1701678512568.jpg │ ├── 1701678535420.jpg │ └── 1701678592627.jpg └── .gitignore ├── man-roxygen ├── param-iid.R ├── param-wkt.R ├── tpl-auth-missing.R ├── tpl-rusetup.R ├── tpl-names-cleaned-top-level.R ├── tpl-compat-2022-3.R ├── param-did.R ├── param-eid.R ├── param-retries.R ├── param-orders.R ├── param-tz.R ├── param-verbose.R ├── param-pp.R ├── tpl-def-entitylist.R ├── param-pid.R ├── param-url.R ├── param-fid.R ├── tpl-entitylist-dataset.R ├── param-fs.R ├── tpl-structure-nested.R ├── param-auth.R └── param-odkcv.R ├── .gitignore ├── .lintr ├── data-raw ├── record_asciicast.R ├── make_logo.R └── make_asciicast.R ├── R ├── utils-pipe.R ├── utils-lifecycle.R ├── ruODK-package.R ├── utils-tidy-eval.R ├── isodt_to_local.R ├── odata_metadata_get.R ├── odata_service_get.R ├── form_xml.R ├── project_create.R ├── handle_ru_datetimes.R ├── drop_null_coords.R ├── entitylist_list.R ├── project_detail.R ├── project_list.R ├── attachment_link.R ├── handle_ru_geopoints.R └── submission_detail.R ├── codecov.yml ├── ruODK.Rproj ├── .Rbuildignore ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── Dockerfile ├── appveyor.yml ├── CODE_OF_CONDUCT.md ├── cran-comments.md └── .pre-commit-config.yaml /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /inst/binder/.gitignore: -------------------------------------------------------------------------------- 1 | README.html 2 | -------------------------------------------------------------------------------- /inst/joss/.gitignore: -------------------------------------------------------------------------------- 1 | paper.html 2 | paper.pdf 3 | -------------------------------------------------------------------------------- /tests/testthat/.gitignore: -------------------------------------------------------------------------------- 1 | media 2 | _snaps 3 | R 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | tests/fixtures/**/* -diff 3 | -------------------------------------------------------------------------------- /data/fs_v7.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fs_v7.rda -------------------------------------------------------------------------------- /data/fq_data.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_data.rda -------------------------------------------------------------------------------- /data/fq_meta.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_meta.rda -------------------------------------------------------------------------------- /data/fq_raw.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_raw.rda -------------------------------------------------------------------------------- /data/fq_svc.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_svc.rda -------------------------------------------------------------------------------- /data/geo_fs.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/geo_fs.rda -------------------------------------------------------------------------------- /data/geo_gj.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/geo_gj.rda -------------------------------------------------------------------------------- /data/geo_wkt.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/geo_wkt.rda -------------------------------------------------------------------------------- /data/fs_v7_raw.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fs_v7_raw.rda -------------------------------------------------------------------------------- /data/geo_gj88.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/geo_gj88.rda -------------------------------------------------------------------------------- /data/geo_gj_raw.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/geo_gj_raw.rda -------------------------------------------------------------------------------- /data/geo_wkt88.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/geo_wkt88.rda -------------------------------------------------------------------------------- /man/figures/bcs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/man/figures/bcs.png -------------------------------------------------------------------------------- /.Rinstignore: -------------------------------------------------------------------------------- 1 | tests/files/.*[.]csv$ 2 | tests/files/.*[.]zip$ 3 | tests/files/.*[.]jpg$ 4 | -------------------------------------------------------------------------------- /data/fq_data_taxa.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_data_taxa.rda -------------------------------------------------------------------------------- /data/fq_form_list.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_form_list.rda -------------------------------------------------------------------------------- /data/fq_form_xml.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_form_xml.rda -------------------------------------------------------------------------------- /data/fq_raw_taxa.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_raw_taxa.rda -------------------------------------------------------------------------------- /data/fq_zip_data.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_zip_data.rda -------------------------------------------------------------------------------- /data/fq_zip_taxa.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_zip_taxa.rda -------------------------------------------------------------------------------- /data/geo_wkt_raw.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/geo_wkt_raw.rda -------------------------------------------------------------------------------- /inst/extdoc/ruODK.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/inst/extdoc/ruODK.pdf -------------------------------------------------------------------------------- /man/figures/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/man/figures/logo.jpg -------------------------------------------------------------------------------- /data/fq_attachments.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_attachments.rda -------------------------------------------------------------------------------- /data/fq_data_strata.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_data_strata.rda -------------------------------------------------------------------------------- /data/fq_form_detail.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_form_detail.rda -------------------------------------------------------------------------------- /data/fq_form_schema.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_form_schema.rda -------------------------------------------------------------------------------- /data/fq_project_list.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_project_list.rda -------------------------------------------------------------------------------- /data/fq_raw_strata.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_raw_strata.rda -------------------------------------------------------------------------------- /data/fq_submissions.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_submissions.rda -------------------------------------------------------------------------------- /data/fq_zip_strata.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_zip_strata.rda -------------------------------------------------------------------------------- /man/figures/dbca_bcs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/man/figures/dbca_bcs.png -------------------------------------------------------------------------------- /man/figures/ruODK2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/man/figures/ruODK2.png -------------------------------------------------------------------------------- /data/fq_project_detail.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_project_detail.rda -------------------------------------------------------------------------------- /data/fq_submission_list.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/data/fq_submission_list.rda -------------------------------------------------------------------------------- /inst/extdata/I8n_no_lang.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/inst/extdata/I8n_no_lang.xls -------------------------------------------------------------------------------- /inst/extdata/I8n_label_lang.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/inst/extdata/I8n_label_lang.xls -------------------------------------------------------------------------------- /inst/extdata/I8n_label_choices.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/inst/extdata/I8n_label_choices.xls -------------------------------------------------------------------------------- /vignettes/media/1701678074209.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/vignettes/media/1701678074209.jpg -------------------------------------------------------------------------------- /vignettes/media/1701678107041.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/vignettes/media/1701678107041.jpg -------------------------------------------------------------------------------- /vignettes/media/1701678512568.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/vignettes/media/1701678512568.jpg -------------------------------------------------------------------------------- /vignettes/media/1701678535420.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/vignettes/media/1701678535420.jpg -------------------------------------------------------------------------------- /vignettes/media/1701678592627.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/vignettes/media/1701678592627.jpg -------------------------------------------------------------------------------- /man-roxygen/param-iid.R: -------------------------------------------------------------------------------- 1 | #' @param iid The `instance_id`, a UUID, as returned by 2 | #' \code{\link{submission_list}}. 3 | -------------------------------------------------------------------------------- /inst/extdata/I8n_lang_choicefilter.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/inst/extdata/I8n_lang_choicefilter.xlsx -------------------------------------------------------------------------------- /tests/testthat/test-submission_get_audit.R: -------------------------------------------------------------------------------- 1 | test_that("submission_get_audit works", { 2 | expect_equal(2 * 2, 4) 3 | }) 4 | -------------------------------------------------------------------------------- /man-roxygen/param-wkt.R: -------------------------------------------------------------------------------- 1 | #' @param wkt Whether geofields are GeoJSON (if FALSE) or WKT 2 | #' strings (if TRUE), default: FALSE. 3 | -------------------------------------------------------------------------------- /inst/extdata/I8n_no_lang_choicefilter.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ropensci/ruODK/HEAD/inst/extdata/I8n_no_lang_choicefilter.xlsx -------------------------------------------------------------------------------- /man-roxygen/tpl-auth-missing.R: -------------------------------------------------------------------------------- 1 | #' ## Authentication 2 | #' This function will fail with incorrect or missing authentication. 3 | #' 4 | -------------------------------------------------------------------------------- /man-roxygen/tpl-rusetup.R: -------------------------------------------------------------------------------- 1 | #' # See vignette("setup") for setup and authentication options 2 | #' # ruODK::ru_setup(svc = "... .svc", un = "...", pw = "...") 3 | -------------------------------------------------------------------------------- /man-roxygen/tpl-names-cleaned-top-level.R: -------------------------------------------------------------------------------- 1 | #' ## Names 2 | #' Names are cleaned at the top level only. List columns contain original 3 | #' `camelCase` names. 4 | #' 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | inst/doc/* 6 | *.RData 7 | manual.tex 8 | manual-concordance.tex 9 | docs/ 10 | inst/doc 11 | -------------------------------------------------------------------------------- /inst/rmarkdown/templates/odata/template.yaml: -------------------------------------------------------------------------------- 1 | name: ODK Central via OData 2 | description: > 3 | Access data captured with OpenDataKit through the ODK Central OData API 4 | -------------------------------------------------------------------------------- /man-roxygen/tpl-compat-2022-3.R: -------------------------------------------------------------------------------- 1 | #' ## Compatibility 2 | #' This function is supported from ODK Central v2022.3 and will warn if the 3 | #' given `odkc_version` is lower. 4 | #' 5 | -------------------------------------------------------------------------------- /man-roxygen/param-did.R: -------------------------------------------------------------------------------- 1 | #' @param did (chr) The name of the Entity List, internally called Dataset. 2 | #' The function will error if this parameter is not given. 3 | #' Default: "". 4 | -------------------------------------------------------------------------------- /tests/testthat/test-utils-lifecycle.R: -------------------------------------------------------------------------------- 1 | test_that("lifecycle_shim does nothing as expected", { 2 | testthat::capture_warning(ruODK:::lifecycle_shim()) 3 | testthat::expect_true(TRUE) 4 | }) 5 | -------------------------------------------------------------------------------- /.lintr: -------------------------------------------------------------------------------- 1 | linters: linters_with_defaults( 2 | line_length_linter(120), 3 | object_name_linter = NULL, 4 | line_length_linter = NULL, 5 | commented_code_linter = NULL 6 | ) 7 | exclusions: list() 8 | -------------------------------------------------------------------------------- /man-roxygen/param-eid.R: -------------------------------------------------------------------------------- 1 | #' @param eid (chr) The UUID of an Entity, which can be retrieved by 2 | #' `entity_list()`. 3 | #' The function will error if this parameter is not given. 4 | #' Default: "". 5 | -------------------------------------------------------------------------------- /man-roxygen/param-retries.R: -------------------------------------------------------------------------------- 1 | #' @param retries The number of attempts to retrieve a web resource. 2 | #' 3 | #' This parameter is given to \code{\link[httr]{RETRY}(times = retries)}. 4 | #' 5 | #' Default: 3. 6 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(ruODK) 3 | 4 | if (Sys.getenv("ODKC_TEST_URL") == "") { 5 | ru_msg_info("Test server not configured, skipping tests.") 6 | } else { 7 | test_check("ruODK") 8 | } 9 | -------------------------------------------------------------------------------- /man-roxygen/param-orders.R: -------------------------------------------------------------------------------- 1 | #' @param orders (vector of character) Orders of datetime elements for 2 | #' lubridate. 3 | #' 4 | #' Default: 5 | #' \code{c("YmdHMS", "YmdHMSz", "Ymd HMS", "Ymd HMSz", "Ymd", "ymd")}. 6 | -------------------------------------------------------------------------------- /man-roxygen/param-tz.R: -------------------------------------------------------------------------------- 1 | #' @param tz A timezone to convert dates and times to. 2 | #' 3 | #' Read `vignette("setup", package = "ruODK")` to learn how `ruODK`'s 4 | #' timezone can be set globally or per function. 5 | -------------------------------------------------------------------------------- /man-roxygen/param-verbose.R: -------------------------------------------------------------------------------- 1 | #' @param verbose Whether to display debug messages or not. 2 | #' 3 | #' Read `vignette("setup", package = "ruODK")` to learn how `ruODK`'s 4 | #' verbosity can be set globally or per function. 5 | -------------------------------------------------------------------------------- /man-roxygen/param-pp.R: -------------------------------------------------------------------------------- 1 | #' @param pp The passphrase for an encrypted form. 2 | #' 3 | #' Default: NULL. 4 | #' 5 | #' Passphrases can be stored e.g. as environment variables. 6 | #' 7 | #' See \code{vignette("Setup", package = "ruODK")}. 8 | -------------------------------------------------------------------------------- /data-raw/record_asciicast.R: -------------------------------------------------------------------------------- 1 | cast <- asciicast::record(here::here("data-raw/make_asciicast.R")) 2 | asciicast::write_json(cast, here::here("data-raw/odata.json")) 3 | asciicast::write_svg(cast, here::here("man", "figures", "odata.svg")) 4 | asciicast::play(cast) 5 | -------------------------------------------------------------------------------- /man-roxygen/tpl-def-entitylist.R: -------------------------------------------------------------------------------- 1 | #' An Entity List is a named collection of Entities that have the same properties. 2 | #' An Entity List can be linked to Forms as Attachments. 3 | #' This will make it available to clients as an automatically-updating CSV. 4 | #' 5 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | manual.log 3 | manual-concordance.tex 4 | manual.synctex.gz 5 | manual.tex 6 | *.R 7 | manual.Rnw 8 | comparison_files 9 | *.aux 10 | *.pdf 11 | odata-api_files 12 | restful-api_files 13 | setup_files 14 | spatial_files 15 | -------------------------------------------------------------------------------- /R/utils-pipe.R: -------------------------------------------------------------------------------- 1 | #' Pipe operator 2 | #' 3 | #' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. 4 | #' 5 | #' @name %>% 6 | #' @rdname pipe 7 | #' @keywords internal 8 | #' @export 9 | #' @importFrom magrittr %>% 10 | #' @usage lhs \%>\% rhs 11 | NULL 12 | -------------------------------------------------------------------------------- /man-roxygen/param-pid.R: -------------------------------------------------------------------------------- 1 | #' @param pid The numeric ID of the project, e.g.: 2. 2 | #' 3 | #' Default: \code{\link{get_default_pid}}. 4 | #' 5 | #' Set default \code{pid} through \code{ru_setup(pid="...")}. 6 | #' 7 | #' See \code{vignette("Setup", package = "ruODK")}. 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: ruODK is missing something 4 | title: '' 5 | labels: feature 6 | assignees: florianm 7 | 8 | --- 9 | 10 | ## Feature 11 | 12 | -------------------------------------------------------------------------------- /man-roxygen/param-url.R: -------------------------------------------------------------------------------- 1 | #' @param url The ODK Central base URL without trailing slash. 2 | #' 3 | #' Default: \code{\link{get_default_url}}. 4 | #' 5 | #' Set default \code{url} through \code{ru_setup(url="...")}. 6 | #' 7 | #' See \code{vignette("Setup", package = "ruODK")}. 8 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | patch: 10 | default: 11 | target: auto 12 | threshold: 1% 13 | ignore: 14 | - "R/utils-lifecycle.R" 15 | -------------------------------------------------------------------------------- /man-roxygen/param-fid.R: -------------------------------------------------------------------------------- 1 | #' @param fid The alphanumeric form ID, e.g. "build_Spotlighting-0-8_1559885147". 2 | #' 3 | #' Default: \code{\link{get_default_fid}}. 4 | #' 5 | #' Set default \code{fid} through \code{ru_setup(fid="...")}. 6 | #' 7 | #' See \code{vignette("Setup", package = "ruODK")}. 8 | -------------------------------------------------------------------------------- /man-roxygen/tpl-entitylist-dataset.R: -------------------------------------------------------------------------------- 1 | #' ## Entity Lists are Datasets 2 | #' ODK Central calls Entity Lists internally Datasets. `ruODK` chooses the term 3 | #' Entity Lists as it is used in the ODK Central user interface and conveys 4 | #' its relation to Entities better than the term Dataset. 5 | #' 6 | -------------------------------------------------------------------------------- /man/pipe.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-pipe.R 3 | \name{\%>\%} 4 | \alias{\%>\%} 5 | \title{Pipe operator} 6 | \usage{ 7 | lhs \%>\% rhs 8 | } 9 | \description{ 10 | See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man-roxygen/param-fs.R: -------------------------------------------------------------------------------- 1 | #' @param form_schema An optional form_schema, 2 | #' like the output of \code{\link{form_schema}}. If a form schema is supplied, 3 | #' location fields will not be unnested. While WKT location fields contain 4 | #' plain text and will never be unnested, GeoJSON location fields would cause 5 | #' errors during unnesting. 6 | -------------------------------------------------------------------------------- /R/utils-lifecycle.R: -------------------------------------------------------------------------------- 1 | #' Shim to allow Import of lifecycle, required for building docs. 2 | #' 3 | #' HT Jim Hester, Lionel Henry, Jenny Bryan for advice 4 | #' @importFrom lifecycle deprecate_soft 5 | #' @keywords internal 6 | lifecycle_shim <- function() { 7 | lifecycle::deprecate_soft(when = "1.0", what = "lifecycle_shim()") 8 | } 9 | 10 | # usethis::use_test("utils-lifecycle") # nolint 11 | -------------------------------------------------------------------------------- /man/lifecycle_shim.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-lifecycle.R 3 | \name{lifecycle_shim} 4 | \alias{lifecycle_shim} 5 | \title{Shim to allow Import of lifecycle, required for building docs.} 6 | \usage{ 7 | lifecycle_shim() 8 | } 9 | \description{ 10 | HT Jim Hester, Lionel Henry, Jenny Bryan for advice 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /inst/binder/apt.txt: -------------------------------------------------------------------------------- 1 | libxml2-dev 2 | libjq-dev 3 | libudunits2-dev 4 | libgdal-dev 5 | libgeos-dev 6 | libproj-dev 7 | libicu-dev 8 | libv8-dev 9 | libjq-dev 10 | libprotobuf-dev 11 | protobuf-compiler 12 | libgit2-dev 13 | rsync 14 | mdbtools 15 | cargo 16 | libavfilter-dev 17 | libfontconfig1-dev 18 | libopenblas-dev 19 | libct4 20 | libsybdb5 21 | freetds-bin 22 | freetds-common 23 | freetds-dev 24 | libsybdb5 25 | tdsodbc 26 | unixodbc 27 | -------------------------------------------------------------------------------- /tests/testthat/test-prepend_uuid.R: -------------------------------------------------------------------------------- 1 | test_that("prepend_uuid works", { 2 | stuff <- "sdfsdf" 3 | uuid_stuff <- glue::glue("uuid:{stuff}") %>% as.character(.) 4 | expect_equal(uuid_stuff, prepend_uuid(stuff)) 5 | }) 6 | 7 | 8 | test_that("prepend_uuid undoes strip_uuid", { 9 | stuff <- "sdfsdf" 10 | uuid_stuff <- prepend_uuid(stuff) 11 | uuid_stuff_stripped <- strip_uuid(uuid_stuff) 12 | expect_equal(stuff, uuid_stuff_stripped) 13 | }) 14 | -------------------------------------------------------------------------------- /man-roxygen/tpl-structure-nested.R: -------------------------------------------------------------------------------- 1 | #' ## Structure 2 | #' The response from ODK Central from this endpoint is irregular and dynamic. 3 | #' Depending on the life history of records in ODK Central, some parts may be 4 | #' populated with deeply nested structures, empty, or missing. 5 | #' `ruODK` preserves the original structure as not to introduce additional 6 | #' complexity. If a use case exists to decompose the original structure further 7 | #' please create a GitHub issue. 8 | #' 9 | -------------------------------------------------------------------------------- /tests/testthat/test-strip_uuid.R: -------------------------------------------------------------------------------- 1 | test_that("strip_uuid works", { 2 | expect_equal( 3 | "c0f9ce58-4388-4e7b-98d7-feac459d2e12", 4 | strip_uuid("uuid:c0f9ce58-4388-4e7b-98d7-feac459d2e12") 5 | ) 6 | }) 7 | 8 | test_that("strip_uuid does its job even with weird clients", { 9 | expect_equal( 10 | "4e7b-98d7-feac459d2e12", 11 | strip_uuid("uuid:uuid:uuid:4e7b-uuid:98d7-feac459d2e12uuid:uuid:") 12 | ) 13 | }) 14 | 15 | # usethis::use_r("attachment_get") # nolint 16 | -------------------------------------------------------------------------------- /ruODK.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: No 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | StripTrailingWhitespace: Yes 16 | 17 | BuildType: Package 18 | PackageUseDevtools: Yes 19 | PackageInstallArgs: --no-multiarch --with-keep.source 20 | PackageCheckArgs: --as-cran 21 | PackageRoxygenize: rd,collate,namespace,vignette 22 | -------------------------------------------------------------------------------- /man-roxygen/param-auth.R: -------------------------------------------------------------------------------- 1 | #' @param un The ODK Central username (an email address). 2 | #' Default: \code{\link{get_default_un}}. 3 | #' Set default \code{un} through \code{ru_setup(un="...")}. 4 | #' See \code{vignette("Setup", package = "ruODK")}. 5 | #' @param pw The ODK Central password. 6 | #' Default: \code{\link{get_default_pw}}. 7 | #' Set default \code{pw} through \code{ru_setup(pw="...")}. 8 | #' See \code{vignette("Setup", package = "ruODK")}. 9 | -------------------------------------------------------------------------------- /tests/testthat/test-odata_metadata_get.R: -------------------------------------------------------------------------------- 1 | context("test-odata_metadata_get.R") 2 | 3 | test_that("odata_metadata_get works", { 4 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 5 | message = "Test server not configured" 6 | ) 7 | 8 | md <- odata_metadata_get( 9 | get_test_pid(), 10 | get_test_fid(), 11 | url = get_test_url(), 12 | un = get_test_un(), 13 | pw = get_test_pw() 14 | ) 15 | testthat::expect_equal(class(md), "list") 16 | }) 17 | 18 | # usethis::use_r("odata_metadata_get") # nolint 19 | -------------------------------------------------------------------------------- /inst/CITATION: -------------------------------------------------------------------------------- 1 | citHeader("To cite ruODK in publications use (with the correct version number:") 2 | 3 | bibentry( 4 | bibtype = "Misc", 5 | title = "ruODK: Client for the ODK Central API", 6 | author = "Florian W. Mayer", 7 | note = "R package version X.X.X", 8 | year = 2020, 9 | url = "https://github.com/ropensci/ruODK", 10 | textVersion = paste( 11 | "Mayer, Florian Wendelin. (2020, Nov 19). ", 12 | "ruODK: An R Client for the ODK Central API (Version X.X.X). ", 13 | "Zenodo. https://doi.org/10.5281/zenodo.5559164" 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /man-roxygen/param-odkcv.R: -------------------------------------------------------------------------------- 1 | #' @param odkc_version The ODK Central version as a semantic version string 2 | #' (year.minor.patch), e.g. "2023.5.1". The version is shown on ODK Central's 3 | #' version page `/version.txt`. Discard the "v". 4 | #' `ruODK` uses this parameter to adjust for breaking changes in ODK Central. 5 | #' 6 | #' Default: \code{\link{get_default_odkc_version}} or "2023.5.1" if unset. 7 | #' 8 | #' Set default \code{get_default_odkc_version} through 9 | #' \code{ru_setup(odkc_version="2023.5.1")}. 10 | #' 11 | #' See \code{vignette("Setup", package = "ruODK")}. 12 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^README\.Rmd$ 5 | ^docs$ 6 | ^CODE_OF_CONDUCT\.md$ 7 | ^data-raw$ 8 | ^\.travis\.yml$ 9 | ^codecov\.yml$ 10 | ^\_pkgdown\.yml$ 11 | ^CONTRIBUTING\.md$ 12 | ^ISSUE_TEMPLATE\.md$ 13 | ^SUPPORT\.md$ 14 | ^man-roxygen$ 15 | ^appveyor\.yml$ 16 | codemeta.json 17 | ^inst/joss/paper\.html$ 18 | ^inst/joss/paper\.pdf$ 19 | ^install\.R$ 20 | ^cran-comments\.md$ 21 | ^\.ccache$ 22 | ^clang-.* 23 | ^gfortran.* 24 | ^tic\.R$ 25 | ^Dockerfile$ 26 | ^codemeta\.json$ 27 | ^\.devcontainer 28 | ^\.github 29 | ^\.vscode 30 | ^.lintr 31 | ^\.pre-commit-config\.yaml$ 32 | -------------------------------------------------------------------------------- /man/listcol_names.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/odata_submission_rectangle.R 3 | \name{listcol_names} 4 | \alias{listcol_names} 5 | \title{A functional to extract names of list columns from a tibble.} 6 | \usage{ 7 | listcol_names(tbl) 8 | } 9 | \arguments{ 10 | \item{tbl}{A tibble, possibly with list columns} 11 | } 12 | \value{ 13 | A vector of list column names 14 | } 15 | \description{ 16 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /tests/testthat/test-odata_service_get.R: -------------------------------------------------------------------------------- 1 | context("test-odata_service_get.R") 2 | 3 | test_that("odata_service_get works", { 4 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 5 | message = "Test server not configured" 6 | ) 7 | 8 | svc <- odata_service_get( 9 | get_test_pid(), 10 | get_test_fid(), 11 | url = get_test_url(), 12 | un = get_test_un(), 13 | pw = get_test_pw() 14 | ) 15 | 16 | testthat::expect_equal(class(svc), c("tbl_df", "tbl", "data.frame")) 17 | cn <- c("name", "kind", "url") 18 | testthat::expect_equal(names(svc), cn) 19 | }) 20 | 21 | # usethis::use_r("odata_service_get") # nolint 22 | -------------------------------------------------------------------------------- /tests/testthat/test-ru_msg.R: -------------------------------------------------------------------------------- 1 | test_that("ru_msg_* output silent if not verbose", { 2 | # Messages can be hidden 3 | expect_message(ru_msg_success("Test", verbose = TRUE), "Test") 4 | expect_silent(ru_msg_success("Test", verbose = FALSE)) 5 | expect_message(ru_msg_noop("Test", verbose = TRUE), "Test") 6 | expect_silent(ru_msg_noop("Test", verbose = FALSE)) 7 | expect_message(ru_msg_info("Test", verbose = TRUE), "Test") 8 | expect_silent(ru_msg_info("Test", verbose = FALSE)) 9 | 10 | # Warnings can be hidden 11 | expect_warning(ru_msg_warn("Test", verbose = TRUE), "Test") 12 | expect_silent(ru_msg_warn("Test", verbose = FALSE)) 13 | 14 | # Errors can't be hidden 15 | expect_error(ru_msg_abort("Test")) 16 | }) 17 | -------------------------------------------------------------------------------- /R/ruODK-package.R: -------------------------------------------------------------------------------- 1 | #' @description \code{\link{ruODK}} is an R Client for the ODK Central API. 2 | #' 3 | #' Please see the `ruODK` website for full documentation: 4 | #' 5 | #' 6 | #' `ruODK` is "pipe-friendly" and re-exports `\%>\%` and `\%||\%`, but does not 7 | #' require their use. 8 | #' 9 | #' @keywords internal 10 | "_PACKAGE" 11 | 12 | utils::globalVariables(c( 13 | ".", 14 | "archived", 15 | "children", 16 | "id", 17 | "name", 18 | "path", 19 | "type", 20 | "variable", 21 | "xx", 22 | "xml_form_id" 23 | )) 24 | 25 | ## usethis namespace: start 26 | #' @import rlang 27 | #' @importFrom glue glue 28 | #' @importFrom lifecycle deprecated 29 | ## usethis namespace: end 30 | NULL 31 | -------------------------------------------------------------------------------- /R/utils-tidy-eval.R: -------------------------------------------------------------------------------- 1 | #' Tidy eval helpers 2 | #' 3 | #' These functions provide tidy eval-compatible ways to capture 4 | #' symbols (`sym()`, `syms()`, `ensym()`), expressions (`expr()`, 5 | #' `exprs()`, `enexpr()`), and quosures (`quo()`, `quos()`, `enquo()`). 6 | #' 7 | #' @name tidyeval 8 | #' @keywords internal 9 | #' @family utilities 10 | #' @aliases quo quos enquo sym syms ensym expr exprs enexpr quo_name 11 | #' @importFrom rlang quo quos enquo sym syms ensym expr exprs enexpr quo_name 12 | #' @importFrom dplyr all_of any_of one_of contains ends_with starts_with 13 | #' @importFrom dplyr everything 14 | #' @importFrom rlang UQ UQS .data := %||% 15 | #' @export quo quos enquo sym syms ensym expr exprs enexpr quo_name 16 | NULL 17 | -------------------------------------------------------------------------------- /tests/testthat/test-encryption_key_list.R: -------------------------------------------------------------------------------- 1 | test_that("encryption_key_list works", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | x <- encryption_key_list( 7 | pid = Sys.getenv("ODKC_TEST_PID_ENC"), 8 | fid = Sys.getenv("ODKC_TEST_FID_ENC"), 9 | url = get_test_url(), 10 | un = get_test_un(), 11 | pw = get_test_pw() 12 | ) 13 | 14 | cn <- c( 15 | "id", 16 | "public", 17 | "managed", 18 | "hint", 19 | "created_at" 20 | ) 21 | 22 | purrr::map( 23 | cn, 24 | ~ testthat::expect_true( 25 | . %in% names(x), 26 | label = glue::glue("Column {.} present in encryption_key_list") 27 | ) 28 | ) 29 | }) 30 | 31 | 32 | # usethis::use_r("encryption_key_list") # nolint 33 | -------------------------------------------------------------------------------- /man/ru_msg_abort.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_msg.R 3 | \name{ru_msg_abort} 4 | \alias{ru_msg_abort} 5 | \title{rlang::abort() with a red error message with a cross symbol.} 6 | \usage{ 7 | ru_msg_abort(message) 8 | } 9 | \arguments{ 10 | \item{message}{(chr) A message to print} 11 | } 12 | \description{ 13 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 14 | } 15 | \examples{ 16 | \dontrun{ 17 | ru_msg_abort("This is an error, abort.") 18 | } 19 | } 20 | \seealso{ 21 | Other messaging: 22 | \code{\link{ru_msg_info}()}, 23 | \code{\link{ru_msg_noop}()}, 24 | \code{\link{ru_msg_success}()}, 25 | \code{\link{ru_msg_warn}()} 26 | } 27 | \concept{messaging} 28 | -------------------------------------------------------------------------------- /inst/binder/install.R: -------------------------------------------------------------------------------- 1 | options(repos = c(ropensci = "https://ropensci.r-universe.dev", 2 | MRAN = "https://mran.microsoft.com/snapshot/2020-07-16", 3 | CRAN = "https://cloud.r-project.org")) 4 | 5 | # install.packages("remotes") 6 | # install.packages("rmarkdown") 7 | install.packages("mapview") 8 | install.packages("gt") 9 | install.packages("reactable") 10 | 11 | install.packages("leaflet") 12 | install.packages("leaflet.extras") 13 | install.packages("leaflet.providers") 14 | install.packages("leaftime") 15 | install.packages("caTools") 16 | install.packages("bitops") 17 | install.packages("ckanr") 18 | install.packages("googledrive") 19 | 20 | install.packages("ruODK") 21 | # remotes::install_github( 22 | # 'ropensci/ruODK@main', 23 | # force = TRUE, 24 | # ask=FALSE, 25 | # upgrade='never', 26 | # dependencies = c('Depends', 'Imports', 'Suggests') 27 | # ) 28 | -------------------------------------------------------------------------------- /tests/testthat/test-project_create.R: -------------------------------------------------------------------------------- 1 | test_that("project_create works", { 2 | # nolint start 3 | # p <- project_create( 4 | # "Test Project", 5 | # url = Sys.getenv("ODKC_TEST_URL"), 6 | # un = Sys.getenv("ODKC_TEST_UN"), 7 | # pw = Sys.getenv("ODKC_TEST_PW") 8 | # ) 9 | # testthat::expect_equal(nrow(p), 1) 10 | # 11 | # # project_create returns a tibble 12 | # testthat::expect_equal(class(p), c("tbl_df", "tbl", "data.frame")) 13 | # 14 | # # Project metadata (some) are the tibble's columns 15 | # cn <- c( 16 | # "id", "name", "archived" 17 | # ) 18 | # testthat::expect_equal(names(p), cn) 19 | # nolint end 20 | 21 | testthat::expect_warning( 22 | project_create( 23 | "Test Project", 24 | url = get_test_url(), 25 | un = get_test_un(), 26 | pw = get_test_pw() 27 | ), "Not implemented." 28 | ) 29 | }) 30 | 31 | # usethis::use_r("project_create") # nolint 32 | -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycledefunctdefunct 2 | -------------------------------------------------------------------------------- /man/figures/lifecycle-retired.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycleretiredretired 2 | -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclearchivedarchived 2 | -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclematuringmaturing 2 | -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclequestioningquestioning 2 | -------------------------------------------------------------------------------- /man/figures/lifecycle-soft-deprecated.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclesoft-deprecatedsoft-deprecated 2 | -------------------------------------------------------------------------------- /man/ru_msg_info.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_msg.R 3 | \name{ru_msg_info} 4 | \alias{ru_msg_info} 5 | \title{Print a blue info message with an info symbol.} 6 | \usage{ 7 | ru_msg_info(message, verbose = get_ru_verbose()) 8 | } 9 | \arguments{ 10 | \item{message}{(chr) A message to print} 11 | 12 | \item{verbose}{Whether to display debug messages or not. 13 | 14 | Read \code{vignette("setup", package = "ruODK")} to learn how \code{ruODK}'s 15 | verbosity can be set globally or per function.} 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 19 | } 20 | \examples{ 21 | ru_msg_info("This is an info message.") 22 | } 23 | \seealso{ 24 | Other messaging: 25 | \code{\link{ru_msg_abort}()}, 26 | \code{\link{ru_msg_noop}()}, 27 | \code{\link{ru_msg_success}()}, 28 | \code{\link{ru_msg_warn}()} 29 | } 30 | \concept{messaging} 31 | -------------------------------------------------------------------------------- /man/ru_msg_noop.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_msg.R 3 | \name{ru_msg_noop} 4 | \alias{ru_msg_noop} 5 | \title{Print a green noop message with a filled circle symbol.} 6 | \usage{ 7 | ru_msg_noop(message, verbose = get_ru_verbose()) 8 | } 9 | \arguments{ 10 | \item{message}{(chr) A message to print} 11 | 12 | \item{verbose}{Whether to display debug messages or not. 13 | 14 | Read \code{vignette("setup", package = "ruODK")} to learn how \code{ruODK}'s 15 | verbosity can be set globally or per function.} 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 19 | } 20 | \examples{ 21 | ru_msg_noop("This is a noop message.") 22 | } 23 | \seealso{ 24 | Other messaging: 25 | \code{\link{ru_msg_abort}()}, 26 | \code{\link{ru_msg_info}()}, 27 | \code{\link{ru_msg_success}()}, 28 | \code{\link{ru_msg_warn}()} 29 | } 30 | \concept{messaging} 31 | -------------------------------------------------------------------------------- /man/ru_msg_success.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_msg.R 3 | \name{ru_msg_success} 4 | \alias{ru_msg_success} 5 | \title{Print a green success message with a tick symbol.} 6 | \usage{ 7 | ru_msg_success(message, verbose = get_ru_verbose()) 8 | } 9 | \arguments{ 10 | \item{message}{(chr) A message to print} 11 | 12 | \item{verbose}{Whether to display debug messages or not. 13 | 14 | Read \code{vignette("setup", package = "ruODK")} to learn how \code{ruODK}'s 15 | verbosity can be set globally or per function.} 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 19 | } 20 | \examples{ 21 | ru_msg_success("This is a success message.") 22 | } 23 | \seealso{ 24 | Other messaging: 25 | \code{\link{ru_msg_abort}()}, 26 | \code{\link{ru_msg_info}()}, 27 | \code{\link{ru_msg_noop}()}, 28 | \code{\link{ru_msg_warn}()} 29 | } 30 | \concept{messaging} 31 | -------------------------------------------------------------------------------- /man/ru_msg_warn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_msg.R 3 | \name{ru_msg_warn} 4 | \alias{ru_msg_warn} 5 | \title{rlang::warn() with a yellow warning message with a warning symbol.} 6 | \usage{ 7 | ru_msg_warn(message, verbose = get_ru_verbose()) 8 | } 9 | \arguments{ 10 | \item{message}{(chr) A message to print} 11 | 12 | \item{verbose}{Whether to display debug messages or not. 13 | 14 | Read \code{vignette("setup", package = "ruODK")} to learn how \code{ruODK}'s 15 | verbosity can be set globally or per function.} 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 19 | } 20 | \examples{ 21 | \dontrun{ 22 | ru_msg_warn("This is a warning.") 23 | } 24 | } 25 | \seealso{ 26 | Other messaging: 27 | \code{\link{ru_msg_abort}()}, 28 | \code{\link{ru_msg_info}()}, 29 | \code{\link{ru_msg_noop}()}, 30 | \code{\link{ru_msg_success}()} 31 | } 32 | \concept{messaging} 33 | -------------------------------------------------------------------------------- /tests/testthat/test-handle_ru_datetimes.R: -------------------------------------------------------------------------------- 1 | test_that("handle_ru_datetimes produces datetimes", { 2 | data("fq_raw") 3 | data("fq_form_schema") 4 | 5 | fq_with_dates <- fq_raw %>% 6 | ruODK::odata_submission_rectangle() %>% 7 | ruODK::handle_ru_datetimes(form_schema = fq_form_schema) 8 | 9 | # nolint start 10 | # fq_with_dates %>% purrr::map(class) 11 | # nolint end 12 | 13 | date_time_fields <- fq_form_schema %>% 14 | dplyr::filter(type == "dateTime") %>% 15 | magrittr::extract2("ruodk_name") 16 | 17 | if (length(date_time_fields) == 0) { 18 | rlang::warn( 19 | glue::glue( 20 | "test-handle_ru_datetimes needs test data", 21 | "with at least one dateTime field. Form schema:\n\n", 22 | "{knitr::kable(fq_form_schema)}" 23 | ) 24 | ) 25 | } 26 | 27 | # Is this a date? 28 | # https://i.imgur.com/NKRMXW4.jpg 29 | testthat::expect_equal( 30 | fq_with_dates %>% magrittr::extract2(date_time_fields[[1]]) %>% class(), 31 | c("POSIXct", "POSIXt") 32 | ) 33 | }) 34 | 35 | # usethis::use_r("handle_ru_datetimess") # nolint 36 | -------------------------------------------------------------------------------- /tests/testthat/test-form_detail.R: -------------------------------------------------------------------------------- 1 | test_that("form_detail works", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | # The test project has a list of forms 7 | fl <- form_list( 8 | get_test_pid(), 9 | url = get_test_url(), 10 | un = get_test_un(), 11 | pw = get_test_pw() 12 | ) 13 | 14 | # The first form in the test project 15 | f <- form_detail( 16 | get_test_pid(), 17 | fl$fid[[1]], 18 | url = get_test_url(), 19 | un = get_test_un(), 20 | pw = get_test_pw() 21 | ) 22 | 23 | # form_detail returns exactly one row 24 | testthat::expect_true(nrow(f) == 1) 25 | 26 | # Columns: name, xmlFormId, and more 27 | testthat::expect_true("name" %in% names(f)) 28 | testthat::expect_true("fid" %in% names(f)) 29 | cn <- c( 30 | "name", "fid", "version", "state", "submissions", "created_at", 31 | "created_by_id", "created_by", "updated_at", "published_at", 32 | "last_submission", "hash" 33 | ) 34 | testthat::expect_equal(names(f), cn) 35 | }) 36 | 37 | # usethis::use_r("form_detail") # nolint 38 | -------------------------------------------------------------------------------- /tests/testthat/test-attachment_list.R: -------------------------------------------------------------------------------- 1 | test_that("attachment_list works", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | sl <- submission_list( 7 | pid = get_test_pid(), 8 | fid = get_test_fid(), 9 | url = get_test_url(), 10 | un = get_test_un(), 11 | pw = get_test_pw() 12 | ) 13 | 14 | al <- get_one_submission_att_list( 15 | sl$instance_id[[1]], 16 | pid = get_test_pid(), 17 | fid = get_test_fid(), 18 | url = get_test_url(), 19 | un = get_test_un(), 20 | pw = get_test_pw() 21 | ) 22 | 23 | all <- attachment_list( 24 | sl$instance_id, 25 | pid = get_test_pid(), 26 | fid = get_test_fid(), 27 | url = get_test_url(), 28 | un = get_test_un(), 29 | pw = get_test_pw() 30 | ) 31 | 32 | # attachment_list returns a tibble 33 | testthat::expect_equal(class(al), c("tbl_df", "tbl", "data.frame")) 34 | 35 | # Attachment attributes are the tibble's columns 36 | cn <- c("name", "exists") 37 | testthat::expect_equal(names(al), cn) 38 | }) 39 | 40 | # usethis::use_r("attachment_list") # nolint 41 | -------------------------------------------------------------------------------- /tests/testthat/test-submission_detail.R: -------------------------------------------------------------------------------- 1 | test_that("submission_detail works", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | sl <- submission_list( 7 | pid = get_test_pid(), 8 | fid = get_test_fid(), 9 | url = get_test_url(), 10 | un = get_test_un(), 11 | pw = get_test_pw() 12 | ) 13 | 14 | sub <- submission_detail( 15 | sl$instance_id[[1]], 16 | pid = get_test_pid(), 17 | fid = get_test_fid(), 18 | url = get_test_url(), 19 | un = get_test_un(), 20 | pw = get_test_pw() 21 | ) 22 | 23 | # submission_detail returns a tibble 24 | testthat::expect_equal(class(sub), c("tbl_df", "tbl", "data.frame")) 25 | 26 | 27 | # The details for one submission return exactly one row 28 | testthat::expect_equal(nrow(sub), 1) 29 | 30 | # The columns are metadata, plus the submission data in column 'xml` 31 | # names(sub) # nolint 32 | cn <- c( 33 | "instance_id", "submitter_id", "submitter", "created_at", "updated_at" 34 | ) 35 | testthat::expect_equal(names(sub), cn) 36 | }) 37 | 38 | # usethis::use_r("submission_detail") # nolint 39 | -------------------------------------------------------------------------------- /man/odata_svc_parse.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_setup.R 3 | \name{odata_svc_parse} 4 | \alias{odata_svc_parse} 5 | \title{Retrieve URL, project ID, and form ID from an ODK Central OData service URL.} 6 | \usage{ 7 | odata_svc_parse(svc) 8 | } 9 | \arguments{ 10 | \item{svc}{(character) The OData service URL of a form as provided by the 11 | ODK Central form submissions tab. 12 | Example: "https://URL/v1/projects/PID/forms/FID.svc"} 13 | } 14 | \value{ 15 | A named list with three components (all of type character): 16 | \itemize{ 17 | \item \code{url} The ODK Central base URL. 18 | \item \code{pid} The project ID. 19 | \item\code{fid} The form ID. 20 | } 21 | } 22 | \description{ 23 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 24 | } 25 | \seealso{ 26 | Other ru_settings: 27 | \code{\link{parse_odkc_version}()}, 28 | \code{\link{ru_settings}()}, 29 | \code{\link{ru_setup}()}, 30 | \code{\link{semver_gt}()}, 31 | \code{\link{semver_lt}()}, 32 | \code{\link{yell_if_error}()}, 33 | \code{\link{yell_if_missing}()} 34 | } 35 | \concept{ru_settings} 36 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/rocker-org/devcontainer/r-ver:4.2 2 | 3 | # non interactive frontend for locales 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | # installing texlive and utils 7 | RUN apt-get update && \ 8 | apt-get -y install --no-install-recommends \ 9 | libudunits2-dev libxtst6 libxt6 libmagick++-dev \ 10 | libxml2-dev libjq-dev libudunits2-dev libgdal-dev libgeos-dev libproj-dev \ 11 | libicu-dev libv8-dev libjq-dev libprotobuf-dev protobuf-compiler libgit2-dev \ 12 | rsync mdbtools cargo libavfilter-dev libfontconfig1-dev libopenblas-dev \ 13 | freetds-common libct4 libsybdb5 freetds-bin freetds-dev libsybdb5 tdsodbc \ 14 | unixodbc make git procps locales curl && \ 15 | rm -rf /var/lib/apt/lists/* 16 | 17 | # generating locales 18 | RUN sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen && \ 19 | dpkg-reconfigure --frontend=noninteractive locales && \ 20 | update-locale LANG=en_GB.UTF-8 21 | ENV LANGUAGE=en_GB.UTF-8 LANG=en_GB.UTF-8 LC_ALL=en_GB.UTF-8 22 | 23 | # installing cpanm & missing latexindent dependencies 24 | RUN curl -L http://cpanmin.us | perl - --self-upgrade && \ 25 | cpanm Log::Dispatch::File YAML::Tiny File::HomeDir 26 | -------------------------------------------------------------------------------- /tests/testthat/test-entity_list.R: -------------------------------------------------------------------------------- 1 | test_that("entity_list works", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | ru_setup( 7 | pid = get_test_pid(), 8 | url = get_test_url(), 9 | un = get_test_un(), 10 | pw = get_test_pw(), 11 | odkc_version = get_test_odkc_version() 12 | ) 13 | 14 | el <- entitylist_list() 15 | did <- el$name[1] 16 | en <- entity_list(did = el$name[1]) 17 | eid <- en$uuid[1] 18 | 19 | testthat::expect_s3_class(en, "tbl_df") 20 | 21 | cn <- c( 22 | "uuid", 23 | "creator_id", 24 | "created_at", 25 | "updated_at", 26 | "deleted_at", 27 | "current_version_current", 28 | "current_version_label", 29 | "current_version_creator_id", 30 | "current_version_user_agent", 31 | "current_version_version", 32 | "current_version_base_version", 33 | "current_version_conflicting_properties", 34 | "current_version_created_at", 35 | "current_version_branch_id", 36 | "current_version_trunk_version", 37 | "current_version_branch_base_version" 38 | ) 39 | 40 | testthat::expect_equal(names(en), cn) 41 | }) 42 | 43 | # usethis::use_r("entity_list") # nolint 44 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rocker/binder:4.1.3 as base 2 | LABEL maintainer=Florian.Mayer@dbca.wa.gov.au 3 | LABEL description="rocker/binder:4.1.3 with ruODK" 4 | # Build this image with 5 | # docker build . -t dbcawa/ruodk:latest --build-arg GITHUB_PAT="..." 6 | # Run this image as Jupyter Notebook with 7 | # docker run -p 8888:8888 dbcawa/ruodk:latest 8 | # Open URL, then select New > Rstudio 9 | 10 | # Build args ------------------------------------------------------------------# 11 | ARG NB_USER 12 | ARG NB_UID 13 | ARG GITHUB_PAT 14 | ENV GITHUB_PAT=$GITHUB_PAT 15 | 16 | # Home directory --------------------------------------------------------------# 17 | USER root 18 | COPY inst/binder ${HOME} 19 | RUN chown -R ${NB_USER} ${HOME} 20 | 21 | # System dependencies ---------------------------------------------------------# 22 | RUN apt-get update --fix-missing && apt remove -y libvorbis0a && \ 23 | xargs -a apt.txt apt-get -y install --no-install-recommends && \ 24 | apt-get purge && apt-get clean && rm -rf /var/lib/apt/lists/* 25 | 26 | # R packages ------------------------------------------------------------------# 27 | FROM base as r_libs 28 | USER ${NB_USER} 29 | RUN if [ -f install.R ]; then R --quiet -f install.R; fi 30 | -------------------------------------------------------------------------------- /R/isodt_to_local.R: -------------------------------------------------------------------------------- 1 | #' Parse an ISO8601 datetime string to a timezone aware datetime. 2 | #' 3 | #' `r lifecycle::badge("stable")` 4 | #' 5 | #' This function is used internally by `ruODK` to parse ISO timestamps 6 | #' to timezone-aware local times. 7 | #' 8 | #' Warnings are suppressed through `lubridate::parse_date_time(quiet=TRUE)`. 9 | #' 10 | #' @param datetime_string (character) An ISO8601 datetime string as produced by 11 | #' XForms exported from ODK Central. 12 | #' @param orders (vector of character) Orders of datetime elements for 13 | #' `lubridate`. 14 | #' Default: \code{c("YmdHMS", "YmdHMSz", "Ymd HMS", "Ymd HMSz")}. 15 | #' @template param-tz 16 | #' @param quiet (lgl) Used in `lubridate::parse_date_time(quiet=quiet)` to 17 | #' suppress warnings from attempting to parse all empty values or columns. 18 | #' Run with `quiet=FALSE` to show any `lubridate` warnings. 19 | #' @return A `lubridate` PosixCT datetime in the given timezone. 20 | #' @family utilities 21 | #' @keywords internal 22 | isodt_to_local <- function(datetime_string, 23 | orders = c("YmdHMS", "YmdHMSz"), 24 | tz = get_default_tz(), 25 | quiet = TRUE) { 26 | datetime_string %>% 27 | lubridate::parse_date_time(orders = orders, quiet = quiet) %>% 28 | lubridate::with_tz(., tzone = tz) 29 | } 30 | -------------------------------------------------------------------------------- /tests/testthat/test-form_xml.R: -------------------------------------------------------------------------------- 1 | test_that("form_xml returns a nested list with parse defaults", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | fxml <- form_xml( 7 | pid = get_test_pid(), 8 | fid = get_test_fid(), 9 | url = get_test_url(), 10 | un = get_test_un(), 11 | pw = get_test_pw() 12 | ) 13 | testthat::expect_equal(class(fxml), "list") 14 | }) 15 | 16 | test_that("form_xml returns a nested list with parse=TRUE", { 17 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 18 | message = "Test server not configured" 19 | ) 20 | 21 | fxml <- form_xml( 22 | parse = TRUE, 23 | pid = get_test_pid(), 24 | fid = get_test_fid(), 25 | url = get_test_url(), 26 | un = get_test_un(), 27 | pw = get_test_pw() 28 | ) 29 | testthat::expect_equal(class(fxml), "list") 30 | }) 31 | 32 | test_that("form_xml returns an xml_document with parse=FALSE", { 33 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 34 | message = "Test server not configured" 35 | ) 36 | 37 | fxml <- form_xml( 38 | parse = FALSE, 39 | pid = get_test_pid(), 40 | fid = get_test_fid(), 41 | url = get_test_url(), 42 | un = get_test_un(), 43 | pw = get_test_pw() 44 | ) 45 | testthat::expect_equal(class(fxml), c("xml_document", "xml_node")) 46 | }) 47 | 48 | # usethis::use_r("form_xml") # nolint 49 | -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: deprecated 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | deprecated 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: superseded 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | superseded 20 | 21 | 22 | -------------------------------------------------------------------------------- /tests/testthat/test-audit_get.R: -------------------------------------------------------------------------------- 1 | test_that("audit_get works", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | logs <- audit_get( 7 | url = get_test_url(), 8 | un = get_test_un(), 9 | pw = get_test_pw() 10 | ) 11 | 12 | # With search parameters 13 | logs_pars <- audit_get( 14 | action = "project.update", 15 | start = "2019-08-01Z", 16 | end = "2019-08-31Z", 17 | limit = 100, 18 | offset = 0, 19 | url = get_test_url(), 20 | un = get_test_un(), 21 | pw = get_test_pw() 22 | ) 23 | 24 | logs_part <- audit_get( 25 | action = "project.update", 26 | limit = 100, 27 | offset = 0, 28 | url = get_test_url(), 29 | un = get_test_un(), 30 | pw = get_test_pw() 31 | ) 32 | 33 | # submission_list returns a tibble 34 | testthat::expect_equal(class(logs), c("tbl_df", "tbl", "data.frame")) 35 | testthat::expect_equal(class(logs_pars), c("tbl_df", "tbl", "data.frame")) 36 | testthat::expect_equal(class(logs_part), c("tbl_df", "tbl", "data.frame")) 37 | 38 | # Submission attributes are the tibble's columns 39 | cn <- c("actor_id", "action", "actee_id", "details", "logged_at") 40 | testthat::expect_equal(names(logs), cn) 41 | testthat::expect_equal(names(logs_pars), cn) 42 | testthat::expect_equal(names(logs_part), cn) 43 | }) 44 | 45 | # usethis::use_r("audit_get") # nolint 46 | -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: experimental 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | experimental 20 | 21 | 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | environment: 17 | NOT_CRAN: true 18 | # env vars that may need to be set, at least temporarily, from time to time 19 | # see https://github.com/krlmlr/r-appveyor#readme for details 20 | USE_RTOOLS: true 21 | # https://github.com/krlmlr/r-appveyor/issues/135 22 | # Fix error "cannot remove prior installation of package 'curl'" 23 | R_REMOTES_STANDALONE: true 24 | 25 | # Adapt as necessary starting from here 26 | 27 | build_script: 28 | - travis-tool.sh install_deps 29 | 30 | test_script: 31 | - travis-tool.sh run_tests 32 | 33 | on_failure: 34 | - 7z a failure.zip *.Rcheck\* 35 | - appveyor PushArtifact failure.zip 36 | 37 | artifacts: 38 | - path: '*.Rcheck\**\*.log' 39 | name: Logs 40 | 41 | - path: '*.Rcheck\**\*.out' 42 | name: Logs 43 | 44 | - path: '*.Rcheck\**\*.fail' 45 | name: Logs 46 | 47 | - path: '*.Rcheck\**\*.Rout' 48 | name: Logs 49 | 50 | - path: '\*_*.tar.gz' 51 | name: Bits 52 | 53 | - path: '\*_*.zip' 54 | name: Bits 55 | -------------------------------------------------------------------------------- /data-raw/make_logo.R: -------------------------------------------------------------------------------- 1 | # -----------------------------------------------------------------------------# 2 | # Hex sticker 3 | # 4 | # remotes::install_github("GuangchuangYu/hexSticker") 5 | library(hexSticker) 6 | library(showtext) 7 | sysfonts::font_add_google("Knewave", "knewave") 8 | # sysfonts::font_add_google("Prosto One", "prosto") 9 | # sysfonts::font_add_google("Concert One", "concert") 10 | turtle <- here::here("man", "figures", "turtle.png") 11 | logo <- here::here("man", "figures", "logo.jpg") 12 | ruodklogo <- here::here("man", "figures", "ruODK.png") 13 | ruodklogo2 <- here::here("man", "figures", "ruODK2.png") 14 | darkred <- "#a50b0b" 15 | # logo s_, text p_, bg h_ 16 | hexSticker::sticker( 17 | turtle, 18 | # asp = 0.684, dpi = 300, 19 | s_x = 1.0, s_y = 1.00, s_width = 1.1, # s_height = 0.1, 20 | package = "ruODK", p_x = 1, p_y = 0.43, p_size = 24, 21 | p_family = "knewave", p_color = darkred, 22 | h_fill = "#aaaaaa", h_color = darkred, 23 | # url = "docs.ropensci.org/ruODK", u_size = 4, u_color = "#ffffff", 24 | white_around_sticker = TRUE, 25 | filename = ruodklogo 26 | ) 27 | 28 | hexSticker::sticker( 29 | logo, 30 | s_x = 1.0, s_y = 1.05, s_width = 1.05, 31 | package = "", p_x = 1, p_y = 0.43, p_size = 24, 32 | h_fill = "#000000", h_color = "#000000", 33 | url = "docs.ropensci.org/ruODK", 34 | u_size = 6, u_color = "#ffffff", u_x = 1.05, u_y = 0.1, 35 | white_around_sticker = TRUE, 36 | filename = ruodklogo2 37 | ) 38 | -------------------------------------------------------------------------------- /man/yell_if_error.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_setup.R 3 | \name{yell_if_error} 4 | \alias{yell_if_error} 5 | \title{Warn about failed web requests and give helpful troubleshooting tips.} 6 | \usage{ 7 | yell_if_error(response, url, un, pw, pid = NULL, fid = NULL) 8 | } 9 | \arguments{ 10 | \item{response}{A httr response object} 11 | 12 | \item{url}{A URL (character)} 13 | 14 | \item{un}{A username (character)} 15 | 16 | \item{pw}{A password (character)} 17 | 18 | \item{pid}{A project ID (numeric, optional)} 19 | 20 | \item{fid}{A form ID (character, optional)} 21 | } 22 | \value{ 23 | The response object 24 | } 25 | \description{ 26 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 27 | } 28 | \details{ 29 | A wrapper around \code{httr::stop_for_status} with a more helpful error 30 | message. 31 | Examples: see tests for \code{\link{project_list}}. 32 | This function is used internally but may be useful for debugging and 33 | \code{\link{ruODK}} development. 34 | } 35 | \seealso{ 36 | Other ru_settings: 37 | \code{\link{odata_svc_parse}()}, 38 | \code{\link{parse_odkc_version}()}, 39 | \code{\link{ru_settings}()}, 40 | \code{\link{ru_setup}()}, 41 | \code{\link{semver_gt}()}, 42 | \code{\link{semver_lt}()}, 43 | \code{\link{yell_if_missing}()} 44 | } 45 | \concept{ru_settings} 46 | \keyword{internal} 47 | -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: stable 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | lifecycle 21 | 22 | 25 | 26 | stable 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who 4 | contribute through reporting issues, posting feature requests, updating documentation, 5 | submitting pull requests or patches, and other activities. 6 | 7 | We are committed to making participation in this project a harassment-free experience for 8 | everyone, regardless of level of experience, gender, gender identity and expression, 9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 10 | 11 | Examples of unacceptable behaviour by participants include the use of sexual language or 12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment, 13 | insults, or other unprofessional conduct. 14 | 15 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed 18 | from the project team. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behaviour may be reported by 21 | opening an issue or contacting one or more of the project maintainers. 22 | 23 | This Code of Conduct is adapted from the Contributor Covenant 24 | (), version 1.0.0, available at 25 | 26 | -------------------------------------------------------------------------------- /man/semver_lt.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_setup.R 3 | \name{semver_lt} 4 | \alias{semver_lt} 5 | \title{Show whether a given semver is lesser than a baseline version.} 6 | \usage{ 7 | semver_lt(sv = get_default_odkc_version(), to = "1.5.0") 8 | } 9 | \arguments{ 10 | \item{sv}{The semver to compare as character 11 | ("2023.5.1", "1.5.0", "1.5"), or numeric (1.5). 12 | The value is always parsed with \code{semver::parse_semver()}. 13 | Default: get_default_odkc_version().} 14 | 15 | \item{to}{The semver to compare to as string. Although semver can parse 16 | complete version strings, \code{to} is still parsed by \code{parse_odkc_version()} 17 | to ensure it is complete with major, minor, and patch version components.} 18 | } 19 | \value{ 20 | A boolean indicating whether the given semver \code{sv} is greater than 21 | the baseline semver \code{to}. 22 | } 23 | \description{ 24 | Show whether a given semver is lesser than a baseline version. 25 | } 26 | \examples{ 27 | get_default_odkc_version() |> semver_lt("0.8.0") 28 | "2024.1.1" |> semver_lt("2024.1.0") 29 | "2024.1.1" |> semver_lt("2024.1.1") 30 | "2024.1.1" |> semver_lt("2024.1.2") 31 | } 32 | \seealso{ 33 | Other ru_settings: 34 | \code{\link{odata_svc_parse}()}, 35 | \code{\link{parse_odkc_version}()}, 36 | \code{\link{ru_settings}()}, 37 | \code{\link{ru_setup}()}, 38 | \code{\link{semver_gt}()}, 39 | \code{\link{yell_if_error}()}, 40 | \code{\link{yell_if_missing}()} 41 | } 42 | \concept{ru_settings} 43 | -------------------------------------------------------------------------------- /tests/testthat/test-entitylist_list.R: -------------------------------------------------------------------------------- 1 | test_that("entitylist_list works", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | ru_setup( 7 | pid = get_test_pid(), 8 | url = get_test_url(), 9 | un = get_test_un(), 10 | pw = get_test_pw(), 11 | odkc_version = get_test_odkc_version() 12 | ) 13 | 14 | ds <- entitylist_list() 15 | testthat::expect_true(nrow(ds) > 0) 16 | testthat::expect_true("name" %in% names(ds)) 17 | 18 | # function returns a tibble 19 | testthat::expect_s3_class(ds, "tbl_df") 20 | 21 | # Expected column names 22 | cn <- c( 23 | "name", 24 | "created_at", 25 | "project_id", 26 | "approval_required", 27 | "owner_only", 28 | "entities", 29 | "last_entity", 30 | "conflicts" 31 | ) 32 | testthat::expect_equal(names(ds), cn) 33 | }) 34 | 35 | 36 | test_that("entitylist_list warns if odkc_version too low", { 37 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 38 | message = "Test server not configured" 39 | ) 40 | 41 | ru_setup( 42 | pid = get_test_pid(), 43 | url = get_test_url(), 44 | un = get_test_un(), 45 | pw = get_test_pw(), 46 | odkc_version = get_test_odkc_version() 47 | ) 48 | 49 | ds <- entitylist_list() 50 | did <- ds$name[1] 51 | 52 | ds1 <- entitylist_list() 53 | 54 | testthat::expect_warning( 55 | ds1 <- entitylist_list(odkc_version = "1.5.3") 56 | ) 57 | }) 58 | 59 | # usethis::use_r("entitylist_list") # nolint 60 | -------------------------------------------------------------------------------- /man/semver_gt.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_setup.R 3 | \name{semver_gt} 4 | \alias{semver_gt} 5 | \title{Show whether a given semver is greater than a baseline version.} 6 | \usage{ 7 | semver_gt(sv = get_default_odkc_version(), to = "1.5.0") 8 | } 9 | \arguments{ 10 | \item{sv}{The semver to compare as character 11 | ("2023.5.1", "1.5.0", "1.5"), or numeric (1.5). 12 | The value is always parsed with \code{semver::parse_semver()}. 13 | Default: get_default_odkc_version().} 14 | 15 | \item{to}{The semver to compare to as string. Although semver can parse 16 | complete version strings, \code{to} is still parsed by \code{parse_odkc_version()} 17 | to ensure it is complete with major, minor, and patch version components.} 18 | } 19 | \value{ 20 | A boolean indicating whether the given semver \code{sv} is greater than 21 | the baseline semver \code{to}. 22 | } 23 | \description{ 24 | Show whether a given semver is greater than a baseline version. 25 | } 26 | \examples{ 27 | get_default_odkc_version() |> semver_gt("0.8.0") 28 | "2024.1.1" |> semver_gt("2024.1.0") 29 | "2024.1.1" |> semver_gt("2024.1.1") 30 | "2024.1.1" |> semver_gt("2024.1.2") 31 | } 32 | \seealso{ 33 | Other ru_settings: 34 | \code{\link{odata_svc_parse}()}, 35 | \code{\link{parse_odkc_version}()}, 36 | \code{\link{ru_settings}()}, 37 | \code{\link{ru_setup}()}, 38 | \code{\link{semver_lt}()}, 39 | \code{\link{yell_if_error}()}, 40 | \code{\link{yell_if_missing}()} 41 | } 42 | \concept{ru_settings} 43 | -------------------------------------------------------------------------------- /data-raw/make_asciicast.R: -------------------------------------------------------------------------------- 1 | #' Title: ruODK walkthough 2 | #' Author_img_url: ../man/figures/ruODK2.png 3 | #' Cols: 120 4 | #' Typing_speed: 0.05 5 | #' Empty_wait: 1 6 | #' End_wait: 20 7 | 8 | # << 9 | # Use your form's OData Service URL (Form > Submissions > Analyse data) 10 | # Read vignette("setup") on setting username and password via .Renviron 11 | # << 12 | suppressMessages(library(tidyverse)) 13 | library(ruODK) 14 | ruODK::ru_setup( 15 | svc = Sys.getenv("ODKC_TEST_SVC"), 16 | un = ruODK::get_test_un(), 17 | pw = ruODK::get_test_pw() 18 | ) 19 | 20 | # << 21 | # List available submission data tables 22 | # << 23 | fq_svc <- ruODK::odata_service_get() 24 | fq_svc 25 | 26 | # << 27 | # Download main submissions and attachments 28 | # << 29 | fq_data <- ruODK::odata_submission_get( 30 | table = fq_svc$name[1], wkt = TRUE, verbose = TRUE 31 | ) 32 | 33 | # << 34 | # Download first nested subtable, join to main submissions 35 | # << 36 | fq_data_strata <- ruODK::odata_submission_get( 37 | table = fq_svc$name[2], wkt = TRUE, verbose = TRUE 38 | ) %>% 39 | dplyr::left_join(fq_data, by = c("submissions_id" = "id")) 40 | 41 | # << 42 | # Download second nested subtable, join to main submissions 43 | # << 44 | fq_data_taxa <- ruODK::odata_submission_get( 45 | table = fq_svc$name[3], wkt = TRUE, verbose = TRUE 46 | ) %>% 47 | dplyr::left_join(fq_data, by = c("submissions_id" = "id")) 48 | 49 | # << 50 | # View data 51 | # << 52 | names(fq_data) 53 | head(fq_data) 54 | head(fq_data_strata) 55 | head(fq_data_taxa) 56 | -------------------------------------------------------------------------------- /man/fq_form_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_form_list} 6 | \alias{fq_form_list} 7 | \title{A tibble of forms.} 8 | \format{ 9 | A tibble of forms 10 | } 11 | \source{ 12 | The output of \code{\link{form_list}}. 13 | run on the project. 14 | } 15 | \usage{ 16 | fq_form_list 17 | } 18 | \description{ 19 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 20 | } 21 | \seealso{ 22 | Other included: 23 | \code{\link{fq_attachments}}, 24 | \code{\link{fq_data}}, 25 | \code{\link{fq_data_strata}}, 26 | \code{\link{fq_data_taxa}}, 27 | \code{\link{fq_form_detail}}, 28 | \code{\link{fq_form_schema}}, 29 | \code{\link{fq_form_xml}}, 30 | \code{\link{fq_meta}}, 31 | \code{\link{fq_project_detail}}, 32 | \code{\link{fq_project_list}}, 33 | \code{\link{fq_raw}}, 34 | \code{\link{fq_raw_strata}}, 35 | \code{\link{fq_raw_taxa}}, 36 | \code{\link{fq_submission_list}}, 37 | \code{\link{fq_submissions}}, 38 | \code{\link{fq_svc}}, 39 | \code{\link{fq_zip_data}}, 40 | \code{\link{fq_zip_strata}}, 41 | \code{\link{fq_zip_taxa}}, 42 | \code{\link{fs_v7}}, 43 | \code{\link{fs_v7_raw}}, 44 | \code{\link{geo_fs}}, 45 | \code{\link{geo_gj}}, 46 | \code{\link{geo_gj88}}, 47 | \code{\link{geo_gj_raw}}, 48 | \code{\link{geo_wkt}}, 49 | \code{\link{geo_wkt88}}, 50 | \code{\link{geo_wkt_raw}} 51 | } 52 | \concept{included} 53 | \keyword{datasets} 54 | -------------------------------------------------------------------------------- /tests/testthat/test-form_list.R: -------------------------------------------------------------------------------- 1 | test_that("form_list works", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | fl <- form_list( 7 | get_test_pid(), 8 | url = get_test_url(), 9 | un = get_test_un(), 10 | pw = get_test_pw() 11 | ) 12 | testthat::expect_equal(class(fl), c("tbl_df", "tbl", "data.frame")) 13 | cn <- c( 14 | "project_id", "xml_form_id", "state", "enketo_id", "enketo_once_id", 15 | "created_at", "updated_at", "webforms_enabled", "key_id", "version", "hash", 16 | "sha", "sha256", "draft_token", "published_at", "name", 17 | "submissions", "entity_related", "review_states_received", 18 | "review_states_has_issues", "review_states_edited", "last_submission", 19 | "excel_content_type", "public_links", "created_by_id", "created_by_type", 20 | "created_by_display_name", "created_by_created_at", 21 | "created_by_updated_at", "created_by_deleted_at", "fid" 22 | ) 23 | testthat::expect_equal(names(fl), cn) 24 | 25 | # Testing #86 form_list should work with draft forms present. 26 | # The above call to form_list worked so we test here that 27 | # the test forms contain a draft form. 28 | # Update: https://github.com/ropensci/ruODK/issues/119 29 | # Draft forms, and any forms from older Central versions 30 | # have published_at = NA. 31 | fl %>% 32 | dplyr::filter(is.na(published_at)) %>% 33 | nrow() %>% 34 | testthat::expect_gt(0) 35 | }) 36 | 37 | # usethis::use_r("form_list") # nolint 38 | -------------------------------------------------------------------------------- /tests/testthat/test-odata_submission_parse.R: -------------------------------------------------------------------------------- 1 | context("test-odata_submission_rectangle.R") 2 | 3 | test_that("odata_submission_rectangle works with gaps in first submission", { 4 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 5 | message = "Test server not configured" 6 | ) 7 | 8 | t <- tempdir() 9 | 10 | fresh_raw <- odata_submission_get( 11 | pid = get_test_pid(), 12 | fid = get_test_fid_gap(), 13 | url = get_test_url(), 14 | un = get_test_un(), 15 | pw = get_test_pw(), 16 | odkc_version = get_test_odkc_version(), 17 | download = FALSE, 18 | parse = FALSE, 19 | verbose = TRUE 20 | ) 21 | 22 | fresh_raw_parsed <- odata_submission_get( 23 | pid = get_test_pid(), 24 | fid = get_test_fid_gap(), 25 | url = get_test_url(), 26 | un = get_test_un(), 27 | pw = get_test_pw(), 28 | odkc_version = get_test_odkc_version(), 29 | download = FALSE, 30 | parse = TRUE, 31 | verbose = TRUE, 32 | local_dir = t 33 | ) 34 | 35 | fresh_parsed <- fresh_raw %>% odata_submission_rectangle(verbose = TRUE) 36 | testthat::expect_gte(nrow(fresh_parsed), length(fresh_raw$value)) 37 | testthat::expect_gte(nrow(fresh_parsed), nrow(fresh_raw_parsed)) 38 | 39 | # TODO update to new test data 40 | # testthat::expect_equal( 41 | # class(fresh_raw_parsed$encounter_start_datetime[1]), 42 | # c("POSIXct", "POSIXt") 43 | # ) 44 | }) 45 | 46 | # nolint start 47 | # usethis::use_r("odata_submission_get") 48 | # usethis::use_r("odata_submission_rectangle") 49 | # nolint end 50 | -------------------------------------------------------------------------------- /man/ruODK-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ruODK-package.R 3 | \docType{package} 4 | \name{ruODK-package} 5 | \alias{ruODK} 6 | \alias{ruODK-package} 7 | \title{ruODK: An R Client for the ODK Central API} 8 | \description{ 9 | \code{\link{ruODK}} is an R Client for the ODK Central API. 10 | 11 | Please see the \code{ruODK} website for full documentation: 12 | \url{https://docs.ropensci.org/ruODK/} 13 | 14 | \code{ruODK} is "pipe-friendly" and re-exports \verb{\\\%>\\\%} and \verb{\\\%||\\\%}, but does not 15 | require their use. 16 | } 17 | \seealso{ 18 | Useful links: 19 | \itemize{ 20 | \item \url{https://docs.ropensci.org/ruODK} 21 | \item \url{https://github.com/ropensci/ruODK} 22 | \item Report bugs at \url{https://github.com/ropensci/ruODK/issues} 23 | } 24 | 25 | } 26 | \author{ 27 | \strong{Maintainer}: Florian W. Mayer \email{Florian.Mayer@dpc.wa.gov.au} (\href{https://orcid.org/0000-0003-4269-4242}{ORCID}) 28 | 29 | Other contributors: 30 | \itemize{ 31 | \item Maëlle Salmon \email{maelle.salmon@yahoo.se} (\href{https://orcid.org/0000-0002-2815-0399}{ORCID}) [reviewer] 32 | \item Karissa Whiting (\href{https://orcid.org/0000-0002-4683-1868}{ORCID}) [reviewer] 33 | \item Jason Taylor [reviewer] 34 | \item Marcelo Tyszler (\href{https://orcid.org/0000-0002-4573-0002}{ORCID}) [contributor] 35 | \item Hélène Langet (\href{https://orcid.org/0000-0002-6758-2397}{ORCID}) [contributor] 36 | \item DBCA [copyright holder, funder] 37 | \item NWSFTCP [funder] 38 | } 39 | 40 | } 41 | \keyword{internal} 42 | -------------------------------------------------------------------------------- /man/fq_project_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_project_list} 6 | \alias{fq_project_list} 7 | \title{A tibble of project metadata.} 8 | \format{ 9 | A tibble of project metadata. 10 | } 11 | \source{ 12 | The output of \code{\link{project_list}} 13 | run on all projects on the configured ODK Central server. 14 | } 15 | \usage{ 16 | fq_project_list 17 | } 18 | \description{ 19 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 20 | } 21 | \seealso{ 22 | Other included: 23 | \code{\link{fq_attachments}}, 24 | \code{\link{fq_data}}, 25 | \code{\link{fq_data_strata}}, 26 | \code{\link{fq_data_taxa}}, 27 | \code{\link{fq_form_detail}}, 28 | \code{\link{fq_form_list}}, 29 | \code{\link{fq_form_schema}}, 30 | \code{\link{fq_form_xml}}, 31 | \code{\link{fq_meta}}, 32 | \code{\link{fq_project_detail}}, 33 | \code{\link{fq_raw}}, 34 | \code{\link{fq_raw_strata}}, 35 | \code{\link{fq_raw_taxa}}, 36 | \code{\link{fq_submission_list}}, 37 | \code{\link{fq_submissions}}, 38 | \code{\link{fq_svc}}, 39 | \code{\link{fq_zip_data}}, 40 | \code{\link{fq_zip_strata}}, 41 | \code{\link{fq_zip_taxa}}, 42 | \code{\link{fs_v7}}, 43 | \code{\link{fs_v7_raw}}, 44 | \code{\link{geo_fs}}, 45 | \code{\link{geo_gj}}, 46 | \code{\link{geo_gj88}}, 47 | \code{\link{geo_gj_raw}}, 48 | \code{\link{geo_wkt}}, 49 | \code{\link{geo_wkt88}}, 50 | \code{\link{geo_wkt_raw}} 51 | } 52 | \concept{included} 53 | \keyword{datasets} 54 | -------------------------------------------------------------------------------- /man/fs_v7_raw.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fs_v7_raw} 6 | \alias{fs_v7_raw} 7 | \title{The unparsed XML form_schema of a form from ODK Central v0.6 as nested list.} 8 | \format{ 9 | An object of class \code{list} of length 6. 10 | } 11 | \source{ 12 | \code{\link{form_schema}(odkc_version = 0.7, parse = FALSE)} 13 | } 14 | \usage{ 15 | fs_v7_raw 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 19 | } 20 | \seealso{ 21 | Other included: 22 | \code{\link{fq_attachments}}, 23 | \code{\link{fq_data}}, 24 | \code{\link{fq_data_strata}}, 25 | \code{\link{fq_data_taxa}}, 26 | \code{\link{fq_form_detail}}, 27 | \code{\link{fq_form_list}}, 28 | \code{\link{fq_form_schema}}, 29 | \code{\link{fq_form_xml}}, 30 | \code{\link{fq_meta}}, 31 | \code{\link{fq_project_detail}}, 32 | \code{\link{fq_project_list}}, 33 | \code{\link{fq_raw}}, 34 | \code{\link{fq_raw_strata}}, 35 | \code{\link{fq_raw_taxa}}, 36 | \code{\link{fq_submission_list}}, 37 | \code{\link{fq_submissions}}, 38 | \code{\link{fq_svc}}, 39 | \code{\link{fq_zip_data}}, 40 | \code{\link{fq_zip_strata}}, 41 | \code{\link{fq_zip_taxa}}, 42 | \code{\link{fs_v7}}, 43 | \code{\link{geo_fs}}, 44 | \code{\link{geo_gj}}, 45 | \code{\link{geo_gj88}}, 46 | \code{\link{geo_gj_raw}}, 47 | \code{\link{geo_wkt}}, 48 | \code{\link{geo_wkt88}}, 49 | \code{\link{geo_wkt_raw}} 50 | } 51 | \concept{included} 52 | \keyword{datasets} 53 | -------------------------------------------------------------------------------- /man/fs_v7.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fs_v7} 6 | \alias{fs_v7} 7 | \title{The parsed XML form_schema of a form from ODK Central v0.6.} 8 | \format{ 9 | An object of class \code{tbl_df} (inherits from \code{tbl}, \code{data.frame}) with 12 rows and 3 columns. 10 | } 11 | \source{ 12 | \code{\link{form_schema_parse}(fs_v7_raw)} 13 | } 14 | \usage{ 15 | fs_v7 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 19 | } 20 | \seealso{ 21 | Other included: 22 | \code{\link{fq_attachments}}, 23 | \code{\link{fq_data}}, 24 | \code{\link{fq_data_strata}}, 25 | \code{\link{fq_data_taxa}}, 26 | \code{\link{fq_form_detail}}, 27 | \code{\link{fq_form_list}}, 28 | \code{\link{fq_form_schema}}, 29 | \code{\link{fq_form_xml}}, 30 | \code{\link{fq_meta}}, 31 | \code{\link{fq_project_detail}}, 32 | \code{\link{fq_project_list}}, 33 | \code{\link{fq_raw}}, 34 | \code{\link{fq_raw_strata}}, 35 | \code{\link{fq_raw_taxa}}, 36 | \code{\link{fq_submission_list}}, 37 | \code{\link{fq_submissions}}, 38 | \code{\link{fq_svc}}, 39 | \code{\link{fq_zip_data}}, 40 | \code{\link{fq_zip_strata}}, 41 | \code{\link{fq_zip_taxa}}, 42 | \code{\link{fs_v7_raw}}, 43 | \code{\link{geo_fs}}, 44 | \code{\link{geo_gj}}, 45 | \code{\link{geo_gj88}}, 46 | \code{\link{geo_gj_raw}}, 47 | \code{\link{geo_wkt}}, 48 | \code{\link{geo_wkt88}}, 49 | \code{\link{geo_wkt_raw}} 50 | } 51 | \concept{included} 52 | \keyword{datasets} 53 | -------------------------------------------------------------------------------- /man/tidyeval.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils-tidy-eval.R 3 | \name{tidyeval} 4 | \alias{tidyeval} 5 | \alias{quo} 6 | \alias{quos} 7 | \alias{enquo} 8 | \alias{sym} 9 | \alias{syms} 10 | \alias{ensym} 11 | \alias{expr} 12 | \alias{exprs} 13 | \alias{enexpr} 14 | \alias{quo_name} 15 | \title{Tidy eval helpers} 16 | \description{ 17 | These functions provide tidy eval-compatible ways to capture 18 | symbols (\code{sym()}, \code{syms()}, \code{ensym()}), expressions (\code{expr()}, 19 | \code{exprs()}, \code{enexpr()}), and quosures (\code{quo()}, \code{quos()}, \code{enquo()}). 20 | } 21 | \seealso{ 22 | Other utilities: 23 | \code{\link{attachment_get}()}, 24 | \code{\link{attachment_link}()}, 25 | \code{\link{attachment_url}()}, 26 | \code{\link{drop_null_coords}()}, 27 | \code{\link{form_schema_parse}()}, 28 | \code{\link{get_one_attachment}()}, 29 | \code{\link{get_one_submission}()}, 30 | \code{\link{get_one_submission_att_list}()}, 31 | \code{\link{get_one_submission_audit}()}, 32 | \code{\link{handle_ru_attachments}()}, 33 | \code{\link{handle_ru_datetimes}()}, 34 | \code{\link{handle_ru_geopoints}()}, 35 | \code{\link{handle_ru_geoshapes}()}, 36 | \code{\link{handle_ru_geotraces}()}, 37 | \code{\link{isodt_to_local}()}, 38 | \code{\link{odata_submission_rectangle}()}, 39 | \code{\link{predict_ruodk_name}()}, 40 | \code{\link{prepend_uuid}()}, 41 | \code{\link{split_geopoint}()}, 42 | \code{\link{split_geoshape}()}, 43 | \code{\link{split_geotrace}()}, 44 | \code{\link{strip_uuid}()}, 45 | \code{\link{unnest_all}()} 46 | } 47 | \concept{utilities} 48 | \keyword{internal} 49 | -------------------------------------------------------------------------------- /man/fq_form_xml.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_form_xml} 6 | \alias{fq_form_xml} 7 | \title{A nested list of a form definition.} 8 | \format{ 9 | A nested list of a form definition. 10 | } 11 | \source{ 12 | The output of \code{\link{form_xml}} 13 | run on the test form 14 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | fq_form_xml 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_meta}}, 32 | \code{\link{fq_project_detail}}, 33 | \code{\link{fq_project_list}}, 34 | \code{\link{fq_raw}}, 35 | \code{\link{fq_raw_strata}}, 36 | \code{\link{fq_raw_taxa}}, 37 | \code{\link{fq_submission_list}}, 38 | \code{\link{fq_submissions}}, 39 | \code{\link{fq_svc}}, 40 | \code{\link{fq_zip_data}}, 41 | \code{\link{fq_zip_strata}}, 42 | \code{\link{fq_zip_taxa}}, 43 | \code{\link{fs_v7}}, 44 | \code{\link{fs_v7_raw}}, 45 | \code{\link{geo_fs}}, 46 | \code{\link{geo_gj}}, 47 | \code{\link{geo_gj88}}, 48 | \code{\link{geo_gj_raw}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/fq_form_detail.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_form_detail} 6 | \alias{fq_form_detail} 7 | \title{A tibble of form metadata.} 8 | \format{ 9 | A tibble of form metadata. 10 | } 11 | \source{ 12 | The output of \code{\link{form_detail}} 13 | run on submissions of the test form 14 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | fq_form_detail 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_list}}, 29 | \code{\link{fq_form_schema}}, 30 | \code{\link{fq_form_xml}}, 31 | \code{\link{fq_meta}}, 32 | \code{\link{fq_project_detail}}, 33 | \code{\link{fq_project_list}}, 34 | \code{\link{fq_raw}}, 35 | \code{\link{fq_raw_strata}}, 36 | \code{\link{fq_raw_taxa}}, 37 | \code{\link{fq_submission_list}}, 38 | \code{\link{fq_submissions}}, 39 | \code{\link{fq_svc}}, 40 | \code{\link{fq_zip_data}}, 41 | \code{\link{fq_zip_strata}}, 42 | \code{\link{fq_zip_taxa}}, 43 | \code{\link{fs_v7}}, 44 | \code{\link{fs_v7_raw}}, 45 | \code{\link{geo_fs}}, 46 | \code{\link{geo_gj}}, 47 | \code{\link{geo_gj88}}, 48 | \code{\link{geo_gj_raw}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/fq_project_detail.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_project_detail} 5 | \alias{fq_project_detail} 6 | \title{A tibble of project metadata.} 7 | \format{ 8 | A tibble of project metadata. 9 | } 10 | \source{ 11 | The output of \code{\link{project_detail}} 12 | run on the project containing the test form 13 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")}. 14 | } 15 | \usage{ 16 | fq_project_detail 17 | } 18 | \description{ 19 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 20 | } 21 | \seealso{ 22 | Other included: 23 | \code{\link{fq_attachments}}, 24 | \code{\link{fq_data}}, 25 | \code{\link{fq_data_strata}}, 26 | \code{\link{fq_data_taxa}}, 27 | \code{\link{fq_form_detail}}, 28 | \code{\link{fq_form_list}}, 29 | \code{\link{fq_form_schema}}, 30 | \code{\link{fq_form_xml}}, 31 | \code{\link{fq_meta}}, 32 | \code{\link{fq_project_list}}, 33 | \code{\link{fq_raw}}, 34 | \code{\link{fq_raw_strata}}, 35 | \code{\link{fq_raw_taxa}}, 36 | \code{\link{fq_submission_list}}, 37 | \code{\link{fq_submissions}}, 38 | \code{\link{fq_svc}}, 39 | \code{\link{fq_zip_data}}, 40 | \code{\link{fq_zip_strata}}, 41 | \code{\link{fq_zip_taxa}}, 42 | \code{\link{fs_v7}}, 43 | \code{\link{fs_v7_raw}}, 44 | \code{\link{geo_fs}}, 45 | \code{\link{geo_gj}}, 46 | \code{\link{geo_gj88}}, 47 | \code{\link{geo_gj_raw}}, 48 | \code{\link{geo_wkt}}, 49 | \code{\link{geo_wkt88}}, 50 | \code{\link{geo_wkt_raw}} 51 | } 52 | \concept{included} 53 | \keyword{datasets} 54 | -------------------------------------------------------------------------------- /man/fq_submission_list.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_submission_list} 6 | \alias{fq_submission_list} 7 | \title{A tibble of submission metadata.} 8 | \format{ 9 | A tibble of submission metadata. 10 | } 11 | \source{ 12 | The output of \code{\link{submission_list}} 13 | run on the test form 14 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | fq_submission_list 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_form_xml}}, 32 | \code{\link{fq_meta}}, 33 | \code{\link{fq_project_detail}}, 34 | \code{\link{fq_project_list}}, 35 | \code{\link{fq_raw}}, 36 | \code{\link{fq_raw_strata}}, 37 | \code{\link{fq_raw_taxa}}, 38 | \code{\link{fq_submissions}}, 39 | \code{\link{fq_svc}}, 40 | \code{\link{fq_zip_data}}, 41 | \code{\link{fq_zip_strata}}, 42 | \code{\link{fq_zip_taxa}}, 43 | \code{\link{fs_v7}}, 44 | \code{\link{fs_v7_raw}}, 45 | \code{\link{geo_fs}}, 46 | \code{\link{geo_gj}}, 47 | \code{\link{geo_gj88}}, 48 | \code{\link{geo_gj_raw}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/fq_attachments.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_attachments} 6 | \alias{fq_attachments} 7 | \title{A tibble of submission attachments.} 8 | \format{ 9 | A tibble of submission attachments. 10 | } 11 | \source{ 12 | The output of \code{\link{attachment_list}} 13 | run on submissions of the test form 14 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | fq_attachments 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_data}}, 25 | \code{\link{fq_data_strata}}, 26 | \code{\link{fq_data_taxa}}, 27 | \code{\link{fq_form_detail}}, 28 | \code{\link{fq_form_list}}, 29 | \code{\link{fq_form_schema}}, 30 | \code{\link{fq_form_xml}}, 31 | \code{\link{fq_meta}}, 32 | \code{\link{fq_project_detail}}, 33 | \code{\link{fq_project_list}}, 34 | \code{\link{fq_raw}}, 35 | \code{\link{fq_raw_strata}}, 36 | \code{\link{fq_raw_taxa}}, 37 | \code{\link{fq_submission_list}}, 38 | \code{\link{fq_submissions}}, 39 | \code{\link{fq_svc}}, 40 | \code{\link{fq_zip_data}}, 41 | \code{\link{fq_zip_strata}}, 42 | \code{\link{fq_zip_taxa}}, 43 | \code{\link{fs_v7}}, 44 | \code{\link{fs_v7_raw}}, 45 | \code{\link{geo_fs}}, 46 | \code{\link{geo_gj}}, 47 | \code{\link{geo_gj88}}, 48 | \code{\link{geo_gj_raw}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/fq_zip_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_zip_data} 6 | \alias{fq_zip_data} 7 | \title{A tibble of the main data table of records from a test form.} 8 | \format{ 9 | A tibble of main records from a test form. 10 | } 11 | \source{ 12 | \code{\link{submission_export}} 13 | run on the test form 14 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | fq_zip_data 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_form_xml}}, 32 | \code{\link{fq_meta}}, 33 | \code{\link{fq_project_detail}}, 34 | \code{\link{fq_project_list}}, 35 | \code{\link{fq_raw}}, 36 | \code{\link{fq_raw_strata}}, 37 | \code{\link{fq_raw_taxa}}, 38 | \code{\link{fq_submission_list}}, 39 | \code{\link{fq_submissions}}, 40 | \code{\link{fq_svc}}, 41 | \code{\link{fq_zip_strata}}, 42 | \code{\link{fq_zip_taxa}}, 43 | \code{\link{fs_v7}}, 44 | \code{\link{fs_v7_raw}}, 45 | \code{\link{geo_fs}}, 46 | \code{\link{geo_gj}}, 47 | \code{\link{geo_gj88}}, 48 | \code{\link{geo_gj_raw}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/fq_zip_taxa.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_zip_taxa} 6 | \alias{fq_zip_taxa} 7 | \title{A tibble of a repeated sub-group of records from a test form.} 8 | \format{ 9 | A tibble of repeated sub-group of records from a test form. 10 | } 11 | \source{ 12 | \code{\link{submission_export}} 13 | run on the test form 14 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | fq_zip_taxa 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_form_xml}}, 32 | \code{\link{fq_meta}}, 33 | \code{\link{fq_project_detail}}, 34 | \code{\link{fq_project_list}}, 35 | \code{\link{fq_raw}}, 36 | \code{\link{fq_raw_strata}}, 37 | \code{\link{fq_raw_taxa}}, 38 | \code{\link{fq_submission_list}}, 39 | \code{\link{fq_submissions}}, 40 | \code{\link{fq_svc}}, 41 | \code{\link{fq_zip_data}}, 42 | \code{\link{fq_zip_strata}}, 43 | \code{\link{fs_v7}}, 44 | \code{\link{fs_v7_raw}}, 45 | \code{\link{geo_fs}}, 46 | \code{\link{geo_gj}}, 47 | \code{\link{geo_gj88}}, 48 | \code{\link{geo_gj_raw}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/fq_zip_strata.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_zip_strata} 6 | \alias{fq_zip_strata} 7 | \title{A tibble of a repeated sub-group of records from a test form.} 8 | \format{ 9 | A tibble of repeated sub-group of records from a test form. 10 | } 11 | \source{ 12 | \code{\link{submission_export}} 13 | run on the test form 14 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | fq_zip_strata 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_form_xml}}, 32 | \code{\link{fq_meta}}, 33 | \code{\link{fq_project_detail}}, 34 | \code{\link{fq_project_list}}, 35 | \code{\link{fq_raw}}, 36 | \code{\link{fq_raw_strata}}, 37 | \code{\link{fq_raw_taxa}}, 38 | \code{\link{fq_submission_list}}, 39 | \code{\link{fq_submissions}}, 40 | \code{\link{fq_svc}}, 41 | \code{\link{fq_zip_data}}, 42 | \code{\link{fq_zip_taxa}}, 43 | \code{\link{fs_v7}}, 44 | \code{\link{fs_v7_raw}}, 45 | \code{\link{geo_fs}}, 46 | \code{\link{geo_gj}}, 47 | \code{\link{geo_gj88}}, 48 | \code{\link{geo_gj_raw}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/geo_gj_raw.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{geo_gj_raw} 6 | \alias{geo_gj_raw} 7 | \title{The unparsed submissions of a form containing geofields in GeoJSON.} 8 | \format{ 9 | An object of class \code{list} of length 2. 10 | } 11 | \source{ 12 | \code{\link{odata_submission_get}(wkt=FALSE, parse=FALSE)} 13 | run on the test form 14 | \code{system.file("extdata", "Locations.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | geo_gj_raw 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_form_xml}}, 32 | \code{\link{fq_meta}}, 33 | \code{\link{fq_project_detail}}, 34 | \code{\link{fq_project_list}}, 35 | \code{\link{fq_raw}}, 36 | \code{\link{fq_raw_strata}}, 37 | \code{\link{fq_raw_taxa}}, 38 | \code{\link{fq_submission_list}}, 39 | \code{\link{fq_submissions}}, 40 | \code{\link{fq_svc}}, 41 | \code{\link{fq_zip_data}}, 42 | \code{\link{fq_zip_strata}}, 43 | \code{\link{fq_zip_taxa}}, 44 | \code{\link{fs_v7}}, 45 | \code{\link{fs_v7_raw}}, 46 | \code{\link{geo_fs}}, 47 | \code{\link{geo_gj}}, 48 | \code{\link{geo_gj88}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/geo_wkt_raw.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{geo_wkt_raw} 6 | \alias{geo_wkt_raw} 7 | \title{The unparsed submissions of a form containing geofields in WKT.} 8 | \format{ 9 | An object of class \code{list} of length 2. 10 | } 11 | \source{ 12 | \code{\link{odata_submission_get}(wkt=TRUE, parse=FALSE)} 13 | run on the test form 14 | \code{system.file("extdata", "Locations.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | geo_wkt_raw 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_form_xml}}, 32 | \code{\link{fq_meta}}, 33 | \code{\link{fq_project_detail}}, 34 | \code{\link{fq_project_list}}, 35 | \code{\link{fq_raw}}, 36 | \code{\link{fq_raw_strata}}, 37 | \code{\link{fq_raw_taxa}}, 38 | \code{\link{fq_submission_list}}, 39 | \code{\link{fq_submissions}}, 40 | \code{\link{fq_svc}}, 41 | \code{\link{fq_zip_data}}, 42 | \code{\link{fq_zip_strata}}, 43 | \code{\link{fq_zip_taxa}}, 44 | \code{\link{fs_v7}}, 45 | \code{\link{fs_v7_raw}}, 46 | \code{\link{geo_fs}}, 47 | \code{\link{geo_gj}}, 48 | \code{\link{geo_gj88}}, 49 | \code{\link{geo_gj_raw}}, 50 | \code{\link{geo_wkt}}, 51 | \code{\link{geo_wkt88}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/geo_fs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{geo_fs} 6 | \alias{geo_fs} 7 | \title{The form_schema of a form containing geofields in GeoJSON.} 8 | \format{ 9 | An object of class \code{tbl_df} (inherits from \code{tbl}, \code{data.frame}) with 19 rows and 6 columns. 10 | } 11 | \source{ 12 | \code{\link{form_schema}} 13 | run on the test form 14 | \code{system.file("extdata", "Locations.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | geo_fs 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_form_xml}}, 32 | \code{\link{fq_meta}}, 33 | \code{\link{fq_project_detail}}, 34 | \code{\link{fq_project_list}}, 35 | \code{\link{fq_raw}}, 36 | \code{\link{fq_raw_strata}}, 37 | \code{\link{fq_raw_taxa}}, 38 | \code{\link{fq_submission_list}}, 39 | \code{\link{fq_submissions}}, 40 | \code{\link{fq_svc}}, 41 | \code{\link{fq_zip_data}}, 42 | \code{\link{fq_zip_strata}}, 43 | \code{\link{fq_zip_taxa}}, 44 | \code{\link{fs_v7}}, 45 | \code{\link{fs_v7_raw}}, 46 | \code{\link{geo_gj}}, 47 | \code{\link{geo_gj88}}, 48 | \code{\link{geo_gj_raw}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /man/fq_submissions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{fq_submissions} 6 | \alias{fq_submissions} 7 | \title{A nested list of submission data.} 8 | \format{ 9 | A nested list of submission data. 10 | } 11 | \source{ 12 | The output of \code{\link{submission_get}} 13 | run on the test form 14 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 15 | using submission instance IDs from \code{\link{submission_list}}. 16 | } 17 | \usage{ 18 | fq_submissions 19 | } 20 | \description{ 21 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 22 | } 23 | \seealso{ 24 | Other included: 25 | \code{\link{fq_attachments}}, 26 | \code{\link{fq_data}}, 27 | \code{\link{fq_data_strata}}, 28 | \code{\link{fq_data_taxa}}, 29 | \code{\link{fq_form_detail}}, 30 | \code{\link{fq_form_list}}, 31 | \code{\link{fq_form_schema}}, 32 | \code{\link{fq_form_xml}}, 33 | \code{\link{fq_meta}}, 34 | \code{\link{fq_project_detail}}, 35 | \code{\link{fq_project_list}}, 36 | \code{\link{fq_raw}}, 37 | \code{\link{fq_raw_strata}}, 38 | \code{\link{fq_raw_taxa}}, 39 | \code{\link{fq_submission_list}}, 40 | \code{\link{fq_svc}}, 41 | \code{\link{fq_zip_data}}, 42 | \code{\link{fq_zip_strata}}, 43 | \code{\link{fq_zip_taxa}}, 44 | \code{\link{fs_v7}}, 45 | \code{\link{fs_v7_raw}}, 46 | \code{\link{geo_fs}}, 47 | \code{\link{geo_gj}}, 48 | \code{\link{geo_gj88}}, 49 | \code{\link{geo_gj_raw}}, 50 | \code{\link{geo_wkt}}, 51 | \code{\link{geo_wkt88}}, 52 | \code{\link{geo_wkt_raw}} 53 | } 54 | \concept{included} 55 | \keyword{datasets} 56 | -------------------------------------------------------------------------------- /tests/testthat/test-entitylist_update.R: -------------------------------------------------------------------------------- 1 | test_that("entitylist_update works", { 2 | ru_setup( 3 | pid = get_test_pid(), 4 | url = get_test_url(), 5 | un = get_test_un(), 6 | pw = get_test_pw(), 7 | odkc_version = get_test_odkc_version() 8 | ) 9 | 10 | ds <- entitylist_list() 11 | 12 | ds1 <- entitylist_detail(did = ds$name[1]) 13 | 14 | did <- ds$name[1] 15 | 16 | # Update dataset with opposite approval_required 17 | ds2 <- entitylist_update(did = did, approval_required = !ds1$approval_required) 18 | testthat::expect_false(ds1$approval_required == ds2$approval_required) 19 | 20 | # Update dataset with opposite approval_required again 21 | ds3 <- entitylist_update(did = did, approval_required = !ds2$approval_required) 22 | testthat::expect_false(ds2$approval_required == ds3$approval_required) 23 | testthat::expect_true(ds1$approval_required == ds3$approval_required) 24 | }) 25 | 26 | test_that("entitylist_update errors if did is missing", { 27 | testthat::expect_error( 28 | entitylist_update() 29 | ) 30 | }) 31 | 32 | test_that("entitylist_update warns if odkc_version too low", { 33 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 34 | message = "Test server not configured" 35 | ) 36 | ru_setup( 37 | pid = get_test_pid(), 38 | url = get_test_url(), 39 | un = get_test_un(), 40 | pw = get_test_pw(), 41 | odkc_version = get_test_odkc_version() 42 | ) 43 | 44 | ds <- entitylist_list() 45 | did <- ds$name[1] 46 | 47 | ds1 <- entitylist_update(did = did) 48 | 49 | testthat::expect_warning( 50 | ds1 <- entitylist_update(did = did, odkc_version = "1.5.3") 51 | ) 52 | }) 53 | 54 | 55 | # usethis::use_r("entitylist_update") # nolint 56 | -------------------------------------------------------------------------------- /man/geo_wkt.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{geo_wkt} 6 | \alias{geo_wkt} 7 | \title{The parsed submissions of a form containing geofields in WKT.} 8 | \format{ 9 | An object of class \code{tbl_df} (inherits from \code{tbl}, \code{data.frame}) with 1 rows and 56 columns. 10 | } 11 | \source{ 12 | \code{\link{odata_submission_get}(wkt=TRUE, parse=TRUE)} 13 | run on the test form 14 | \code{system.file("extdata", "Locations.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | geo_wkt 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_form_xml}}, 32 | \code{\link{fq_meta}}, 33 | \code{\link{fq_project_detail}}, 34 | \code{\link{fq_project_list}}, 35 | \code{\link{fq_raw}}, 36 | \code{\link{fq_raw_strata}}, 37 | \code{\link{fq_raw_taxa}}, 38 | \code{\link{fq_submission_list}}, 39 | \code{\link{fq_submissions}}, 40 | \code{\link{fq_svc}}, 41 | \code{\link{fq_zip_data}}, 42 | \code{\link{fq_zip_strata}}, 43 | \code{\link{fq_zip_taxa}}, 44 | \code{\link{fs_v7}}, 45 | \code{\link{fs_v7_raw}}, 46 | \code{\link{geo_fs}}, 47 | \code{\link{geo_gj}}, 48 | \code{\link{geo_gj88}}, 49 | \code{\link{geo_gj_raw}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /tests/testthat/test-attachment_link.R: -------------------------------------------------------------------------------- 1 | test_that("submission_export works", { 2 | # This test downloads files 3 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 4 | message = "Test server not configured" 5 | ) 6 | 7 | 8 | # A fresh litterbox 9 | t <- tempdir() 10 | fid <- get_test_fid_att() # Form with one submission 11 | 12 | fid_csv <- fs::path(t, glue::glue("{fid}.csv")) 13 | 14 | # Download submissions of a form with media attachments 15 | se <- submission_export( 16 | local_dir = t, 17 | overwrite = TRUE, 18 | verbose = TRUE, 19 | pid = get_test_pid(), 20 | fid = fid, 21 | url = get_test_url(), 22 | un = get_test_un(), 23 | pw = get_test_pw(), 24 | pp = get_test_pp() 25 | ) 26 | 27 | fs <- form_schema( 28 | url = get_test_url(), 29 | un = get_test_un(), 30 | pw = get_test_pw(), 31 | pid = get_test_pid(), 32 | fid = fid, 33 | odkc_version = get_test_odkc_version() 34 | ) 35 | 36 | # Comb through the litterbox 37 | f <- unzip(se, exdir = t) 38 | 39 | # Find the payload 40 | testthat::expect_true(fid_csv %in% fs::dir_ls(t)) 41 | testthat::expect_true(fs::file_exists(fid_csv)) 42 | 43 | suppressWarnings( 44 | data_quadrat_csv <- fid_csv %>% 45 | readr::read_csv(na = c("", "NA", "na")) %>% 46 | janitor::clean_names(.) %>% 47 | handle_ru_datetimes(fs) %>% 48 | # handle_ru_geopoints(fs) %>% # no geopoints 49 | attachment_link(fs) 50 | ) 51 | 52 | # Test that filepath of attachment exists 53 | for (i in seq_len(nrow(data_quadrat_csv))) { 54 | testthat::expect_true( 55 | fs::path(t, data_quadrat_csv[i, ]$location_quadrat_photo) %>% 56 | fs::file_exists() 57 | ) 58 | } 59 | }) 60 | -------------------------------------------------------------------------------- /R/odata_metadata_get.R: -------------------------------------------------------------------------------- 1 | #' Retrieve metadata from an OData URL ending in .svc as list of lists. 2 | #' 3 | #' `r lifecycle::badge("stable")` 4 | #' 5 | #' @template param-pid 6 | #' @template param-fid 7 | #' @template param-url 8 | #' @template param-auth 9 | #' @template param-retries 10 | #' @return A nested list containing Edmx (dataset schema definition) and 11 | #' .attrs (Version). 12 | # nolint start 13 | #' @seealso \url{https://docs.getodk.org/central-api-odata-endpoints/#metadata-document} 14 | # nolint end 15 | #' @family odata-api 16 | #' @export 17 | #' @examples 18 | #' \dontrun{ 19 | #' # See vignette("setup") for setup and authentication options 20 | #' # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 21 | #' 22 | #' meta <- odata_metadata_get() 23 | #' listviewer::jsonedit(meta) 24 | #' } 25 | odata_metadata_get <- function(pid = get_default_pid(), 26 | fid = get_default_fid(), 27 | url = get_default_url(), 28 | un = get_default_un(), 29 | pw = get_default_pw(), 30 | retries = get_retries()) { 31 | yell_if_missing(url, un, pw) 32 | httr::RETRY( 33 | "GET", 34 | httr::modify_url( 35 | url, 36 | path = glue::glue( 37 | "v1/projects/{pid}/forms/", 38 | "{URLencode(fid, reserved = TRUE)}.svc/$metadata" 39 | ) 40 | ), 41 | httr::add_headers(Accept = "application/xml"), 42 | httr::authenticate(un, pw), 43 | times = retries 44 | ) %>% 45 | yell_if_error(., url, un, pw) %>% 46 | httr::content(.) %>% 47 | xml2::as_list(.) 48 | } 49 | 50 | # usethis::use_test("odata_metadata_get") # nolint 51 | -------------------------------------------------------------------------------- /man/geo_gj.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{geo_gj} 6 | \alias{geo_gj} 7 | \title{The parsed submissions of a form containing geofields in GeoJSON.} 8 | \format{ 9 | An object of class \code{tbl_df} (inherits from \code{tbl}, \code{data.frame}) with 1 rows and 59 columns. 10 | } 11 | \source{ 12 | \code{\link{odata_submission_get}(wkt=FALSE, parse=TRUE)} 13 | run on the test form 14 | \code{system.file("extdata", "Locations.xml", package = "ruODK")}. 15 | } 16 | \usage{ 17 | geo_gj 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \seealso{ 23 | Other included: 24 | \code{\link{fq_attachments}}, 25 | \code{\link{fq_data}}, 26 | \code{\link{fq_data_strata}}, 27 | \code{\link{fq_data_taxa}}, 28 | \code{\link{fq_form_detail}}, 29 | \code{\link{fq_form_list}}, 30 | \code{\link{fq_form_schema}}, 31 | \code{\link{fq_form_xml}}, 32 | \code{\link{fq_meta}}, 33 | \code{\link{fq_project_detail}}, 34 | \code{\link{fq_project_list}}, 35 | \code{\link{fq_raw}}, 36 | \code{\link{fq_raw_strata}}, 37 | \code{\link{fq_raw_taxa}}, 38 | \code{\link{fq_submission_list}}, 39 | \code{\link{fq_submissions}}, 40 | \code{\link{fq_svc}}, 41 | \code{\link{fq_zip_data}}, 42 | \code{\link{fq_zip_strata}}, 43 | \code{\link{fq_zip_taxa}}, 44 | \code{\link{fs_v7}}, 45 | \code{\link{fs_v7_raw}}, 46 | \code{\link{geo_fs}}, 47 | \code{\link{geo_gj88}}, 48 | \code{\link{geo_gj_raw}}, 49 | \code{\link{geo_wkt}}, 50 | \code{\link{geo_wkt88}}, 51 | \code{\link{geo_wkt_raw}} 52 | } 53 | \concept{included} 54 | \keyword{datasets} 55 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: ruODK is doing something wrong 4 | title: '' 5 | labels: bug 6 | assignees: florianm 7 | 8 | --- 9 | 10 | ## Problem 11 | 14 | ## ruODK function(s) used 15 | 18 | 19 | ## Unexpected behaviour 20 | 25 | 26 | ## Reproducible example 27 | 42 | 43 | ```{r} 44 | # insert reprex here 45 | ``` 46 | 47 |
48 | Session Info 49 | 50 | 53 | ODK Central version: 54 | 55 | 58 | ```{r} 59 | # utils::sessionInfo() 60 | ``` 61 |
62 | -------------------------------------------------------------------------------- /man/prepend_uuid.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/attachment_get.R 3 | \name{prepend_uuid} 4 | \alias{prepend_uuid} 5 | \title{Prepend a leading "uuid:" to any string, e.g. an md5 hash.} 6 | \usage{ 7 | prepend_uuid(md5hash) 8 | } 9 | \arguments{ 10 | \item{md5hash}{A string, e.g. an md5 hash.} 11 | } 12 | \value{ 13 | The string with a prepended "uuid:" 14 | } 15 | \description{ 16 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 17 | } 18 | \details{ 19 | This is the inverse of the helper function \code{\link{strip_uuid}}. 20 | } 21 | \examples{ 22 | \dontrun{ 23 | prepend_uuid("1234") 24 | prepend_uuid("d3bcefea-32a8-4dbc-80ca-4ecb0678e2b0") 25 | } 26 | } 27 | \seealso{ 28 | Other utilities: 29 | \code{\link{attachment_get}()}, 30 | \code{\link{attachment_link}()}, 31 | \code{\link{attachment_url}()}, 32 | \code{\link{drop_null_coords}()}, 33 | \code{\link{form_schema_parse}()}, 34 | \code{\link{get_one_attachment}()}, 35 | \code{\link{get_one_submission}()}, 36 | \code{\link{get_one_submission_att_list}()}, 37 | \code{\link{get_one_submission_audit}()}, 38 | \code{\link{handle_ru_attachments}()}, 39 | \code{\link{handle_ru_datetimes}()}, 40 | \code{\link{handle_ru_geopoints}()}, 41 | \code{\link{handle_ru_geoshapes}()}, 42 | \code{\link{handle_ru_geotraces}()}, 43 | \code{\link{isodt_to_local}()}, 44 | \code{\link{odata_submission_rectangle}()}, 45 | \code{\link{predict_ruodk_name}()}, 46 | \code{\link{split_geopoint}()}, 47 | \code{\link{split_geoshape}()}, 48 | \code{\link{split_geotrace}()}, 49 | \code{\link{strip_uuid}()}, 50 | \code{\link{tidyeval}}, 51 | \code{\link{unnest_all}()} 52 | } 53 | \concept{utilities} 54 | \keyword{internal} 55 | -------------------------------------------------------------------------------- /man/strip_uuid.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/attachment_get.R 3 | \name{strip_uuid} 4 | \alias{strip_uuid} 5 | \title{Strip the leading "uuid:" from a UUID hash.} 6 | \usage{ 7 | strip_uuid(uuid) 8 | } 9 | \arguments{ 10 | \item{uuid}{A string which may contain any number of "uuid:"} 11 | } 12 | \value{ 13 | The string with every occurrence of "uuid:" deleted. 14 | } 15 | \description{ 16 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 17 | } 18 | \details{ 19 | This is a helper function used by \code{\link{attachment_get}}. 20 | } 21 | \examples{ 22 | \dontrun{ 23 | strip_uuid("uuid:1234") 24 | strip_uuid("uuid:d3bcefea-32a8-4dbc-80ca-4ecb0678e2b0") 25 | } 26 | } 27 | \seealso{ 28 | Other utilities: 29 | \code{\link{attachment_get}()}, 30 | \code{\link{attachment_link}()}, 31 | \code{\link{attachment_url}()}, 32 | \code{\link{drop_null_coords}()}, 33 | \code{\link{form_schema_parse}()}, 34 | \code{\link{get_one_attachment}()}, 35 | \code{\link{get_one_submission}()}, 36 | \code{\link{get_one_submission_att_list}()}, 37 | \code{\link{get_one_submission_audit}()}, 38 | \code{\link{handle_ru_attachments}()}, 39 | \code{\link{handle_ru_datetimes}()}, 40 | \code{\link{handle_ru_geopoints}()}, 41 | \code{\link{handle_ru_geoshapes}()}, 42 | \code{\link{handle_ru_geotraces}()}, 43 | \code{\link{isodt_to_local}()}, 44 | \code{\link{odata_submission_rectangle}()}, 45 | \code{\link{predict_ruodk_name}()}, 46 | \code{\link{prepend_uuid}()}, 47 | \code{\link{split_geopoint}()}, 48 | \code{\link{split_geoshape}()}, 49 | \code{\link{split_geotrace}()}, 50 | \code{\link{tidyeval}}, 51 | \code{\link{unnest_all}()} 52 | } 53 | \concept{utilities} 54 | \keyword{internal} 55 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "R (rocker/r-ver base)", 3 | "dockerFile": "Dockerfile", 4 | "features": { 5 | "ghcr.io/rocker-org/devcontainer-features/quarto-cli:1": { 6 | "version": "prerelease" 7 | }, 8 | "ghcr.io/rocker-org/devcontainer-features/apt-packages:1": { 9 | "packages": "libudunits2-dev,libxtst6,libxt6,libmagick++-dev" 10 | }, 11 | "ghcr.io/rocker-org/devcontainer-features/r-packages:1": { 12 | "packages": "github::rstudio/renv,tidyverse,git2r,knitr,spelling,languageserver,precommit,clisymbols,crayon,dplyr,fs,glue,httr,httr2,janitor,lifecycle,lubridate,magrittr,purrr,readr,rlang,stringr,semver,tibble,tidyr,xml2,covr,DT,ggplot2,here,knitr,lattice,leaflet,listviewer,leafpop,leafem,mapview,rmarkdown,roxygen2,sf,terra,testthat,tmap,usethis" 13 | }, 14 | "ghcr.io/devcontainers-contrib/features/pre-commit:2": {} 15 | }, 16 | "mounts": [ 17 | "source=${localEnv:HOME}${localEnv:USERPROFILE}/.gitconfig,target=~/.gitconfig,type=bind,consistency=cached" 18 | ], 19 | "onCreateCommand": "pre-commit install && pre-commit run", 20 | "customizations": { 21 | "vscode": { 22 | "extensions": [ 23 | "mechatroner.rainbow-csv", 24 | "REditorSupport.r", 25 | "RDebugger.r-debugger", 26 | "ms-azuretools.vscode-docker", 27 | "usernamehw.errorlens", 28 | "christian-kohler.path-intellisense", 29 | "ms-vscode.live-server" 30 | ] 31 | }, 32 | "codespaces": { 33 | "openFiles": [ 34 | "DESCRIPTION", 35 | "NEWS.md", 36 | "data-raw/make_release.R" 37 | ] 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /inst/joss/paper.bib: -------------------------------------------------------------------------------- 1 | @Misc{ruodk, 2 | title = {ruODK: Client for the ODK Central API v0.9.0}, 3 | author = {Florian W. Mayer}, 4 | note = {R package version 0.9.0}, 5 | year = {2019}, 6 | url = {https://github.com/ropensci/ruODK}, 7 | } 8 | 9 | @online{github, 10 | author = {GitHub}, 11 | title = {GitHub.com}, 12 | year = 2008, 13 | url = {https://github.com}, 14 | urldate = {2024-03-08} 15 | } 16 | 17 | @online{odk, 18 | author = {OpenDataKit}, 19 | title = {getodk.org}, 20 | year = 2019, 21 | url = {https://getodk.org/}, 22 | urldate = {2024-03-08} 23 | } 24 | 25 | @online{odkdocs, 26 | author = {OpenDataKit Documentation}, 27 | title = {docs.getodk.org}, 28 | year = 2019, 29 | url = {https://docs.getodk.org/}, 30 | urldate = {2024-03-08} 31 | } 32 | 33 | @online{odkapi, 34 | author = {OpenDataKit API}, 35 | title = {docs.getodk.org/central-api/}, 36 | year = 2019, 37 | url = {https://docs.getodk.org/central-api/}, 38 | urldate = {2024-03-08} 39 | } 40 | 41 | @inproceedings{hartung, 42 | author = {Hartung, Carl and Lerer, Adam and Anokwa, Yaw and Tseng, Clint and Brunette, Waylon and Borriello, Gaetano}, 43 | title = {Open Data Kit: Tools to Build Information Services for Developing Regions}, 44 | booktitle = {Proceedings of the 4th ACM/IEEE International Conference on Information and Communication Technologies and Development}, 45 | series = {ICTD '10}, 46 | year = {2010}, 47 | isbn = {978-1-4503-0787-1}, 48 | location = {London, United Kingdom}, 49 | pages = {18:1--18:12}, 50 | articleno = {18}, 51 | numpages = {12}, 52 | url = {http://doi.acm.org/10.1145/2369220.2369236}, 53 | doi = {10.1145/2369220.2369236}, 54 | acmid = {2369236}, 55 | publisher = {ACM}, 56 | address = {New York, NY, USA}, 57 | keywords = {ICTD, client-server distributed systems, mobile computing, mobile phones}, 58 | } 59 | -------------------------------------------------------------------------------- /man/fq_meta.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_meta} 5 | \alias{fq_meta} 6 | \title{OData metadata document for an ODK Central form.} 7 | \format{ 8 | A list of lists 9 | } 10 | \source{ 11 | See \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 12 | } 13 | \usage{ 14 | fq_meta 15 | } 16 | \description{ 17 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 18 | } 19 | \details{ 20 | The OData response for the metadata of an ODK Central form. 21 | 22 | This data is kept up to date with the data used in vignettes and package 23 | tests. The data is comprised of test records with nonsensical data. 24 | The forms used to capture this data are development versions of real-world 25 | forms. 26 | } 27 | \seealso{ 28 | Other included: 29 | \code{\link{fq_attachments}}, 30 | \code{\link{fq_data}}, 31 | \code{\link{fq_data_strata}}, 32 | \code{\link{fq_data_taxa}}, 33 | \code{\link{fq_form_detail}}, 34 | \code{\link{fq_form_list}}, 35 | \code{\link{fq_form_schema}}, 36 | \code{\link{fq_form_xml}}, 37 | \code{\link{fq_project_detail}}, 38 | \code{\link{fq_project_list}}, 39 | \code{\link{fq_raw}}, 40 | \code{\link{fq_raw_strata}}, 41 | \code{\link{fq_raw_taxa}}, 42 | \code{\link{fq_submission_list}}, 43 | \code{\link{fq_submissions}}, 44 | \code{\link{fq_svc}}, 45 | \code{\link{fq_zip_data}}, 46 | \code{\link{fq_zip_strata}}, 47 | \code{\link{fq_zip_taxa}}, 48 | \code{\link{fs_v7}}, 49 | \code{\link{fs_v7_raw}}, 50 | \code{\link{geo_fs}}, 51 | \code{\link{geo_gj}}, 52 | \code{\link{geo_gj88}}, 53 | \code{\link{geo_gj_raw}}, 54 | \code{\link{geo_wkt}}, 55 | \code{\link{geo_wkt88}}, 56 | \code{\link{geo_wkt_raw}} 57 | } 58 | \concept{included} 59 | \keyword{datasets} 60 | -------------------------------------------------------------------------------- /tests/testthat/test-handle_ru_attachments.R: -------------------------------------------------------------------------------- 1 | test_that("handle_ru_attachments downloads files", { 2 | # This test downloads files 3 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 4 | message = "Test server not configured" 5 | ) 6 | 7 | data("fq_raw") 8 | data("fq_form_schema") 9 | 10 | t <- tempdir() 11 | fs::dir_ls(t) %>% fs::file_delete() 12 | 13 | fq_with_att <- fq_raw %>% 14 | ruODK::odata_submission_rectangle() %>% 15 | ruODK::handle_ru_attachments( 16 | form_schema = fq_form_schema, 17 | local_dir = t, 18 | pid = ruODK::get_test_pid(), 19 | fid = ruODK::get_test_fid(), 20 | url = ruODK::get_test_url(), 21 | un = ruODK::get_test_un(), 22 | pw = ruODK::get_test_pw(), 23 | verbose = TRUE 24 | ) 25 | 26 | # There should be files in local_dir 27 | testthat::expect_true(fs::dir_ls(t) %>% length() > 0) 28 | }) 29 | 30 | test_that("handle_ru_attachments downloads files from subtables", { 31 | # This test downloads files 32 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 33 | message = "Test server not configured" 34 | ) 35 | 36 | data("fq_raw") 37 | data("fq_raw_taxa") 38 | data("fq_form_schema") 39 | 40 | t <- tempdir() 41 | fs::dir_ls(t) %>% fs::file_delete() 42 | 43 | fq_with_att <- fq_raw_taxa %>% 44 | ruODK::odata_submission_rectangle() %>% 45 | ruODK::handle_ru_attachments( 46 | form_schema = fq_form_schema, 47 | local_dir = t, 48 | pid = ruODK::get_test_pid(), 49 | fid = ruODK::get_test_fid(), 50 | url = ruODK::get_test_url(), 51 | un = ruODK::get_test_un(), 52 | pw = ruODK::get_test_pw(), 53 | verbose = TRUE 54 | ) 55 | 56 | # There should be files in local_dir 57 | testthat::expect_true(fs::dir_ls(t) %>% length() > 0) 58 | }) 59 | 60 | # usethis::use_r("handle_ru_attachments") # nolint 61 | -------------------------------------------------------------------------------- /inst/schemaorg.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "https://schema.org", 3 | "type": "SoftwareSourceCode", 4 | "author": { 5 | "id": "https://orcid.org/0000-0003-4269-4242", 6 | "type": "Person", 7 | "email": "Florian.Mayer@dpc.wa.gov.au", 8 | "familyName": "Mayer", 9 | "givenName": [ 10 | "Florian", 11 | "W." 12 | ] 13 | }, 14 | "codeRepository": "https://github.com/ropensci/ruODK", 15 | "contributor": [ 16 | { 17 | "id": "https://orcid.org/0000-0002-4573-0002", 18 | "type": "Person", 19 | "familyName": "Tyszler", 20 | "givenName": "Marcelo" 21 | }, 22 | { 23 | "id": "https://orcid.org/0000-0002-6758-2397", 24 | "type": "Person", 25 | "familyName": "Langet", 26 | "givenName": "Hélène" 27 | } 28 | ], 29 | "copyrightHolder": { 30 | "type": "Organization", 31 | "name": "DBCA" 32 | }, 33 | "description": "Access and tidy up data from the 'ODK Central' API. 'ODK Central' is a clearinghouse for digitally captured data using ODK . It manages user accounts and permissions, stores form definitions, and allows data collection clients like 'ODK Collect' to connect to it for form download and submission upload. The 'ODK Central' API is documented at .", 34 | "funder": [ 35 | { 36 | "type": "Organization", 37 | "name": "DBCA" 38 | }, 39 | { 40 | "type": "Organization", 41 | "name": "NWSFTCP" 42 | } 43 | ], 44 | "license": "https://spdx.org/licenses/GPL-3.0", 45 | "name": "ruODK: An R Client for the ODK Central API", 46 | "programmingLanguage": { 47 | "type": "ComputerLanguage", 48 | "name": "R", 49 | "url": "https://r-project.org" 50 | }, 51 | "runtimePlatform": "R version 4.4.1 (2024-06-14 ucrt)", 52 | "version": "1.5.0" 53 | } 54 | -------------------------------------------------------------------------------- /R/odata_service_get.R: -------------------------------------------------------------------------------- 1 | #' Retrieve service metadata from an OData URL ending in .svc as tibble. 2 | #' 3 | #' `r lifecycle::badge("stable")` 4 | #' 5 | #' @template param-pid 6 | #' @template param-fid 7 | #' @template param-url 8 | #' @template param-auth 9 | #' @template param-retries 10 | #' @return A tibble with one row per submission data endpoint. 11 | #' Columns: name, kind, url. 12 | # nolint start 13 | #' @seealso \url{https://docs.getodk.org/central-api-odata-endpoints/#service-document} 14 | # nolint end 15 | #' @family odata-api 16 | #' @export 17 | #' @examples 18 | #' \dontrun{ 19 | #' # See vignette("setup") for setup and authentication options 20 | #' # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 21 | #' 22 | #' svc <- odata_service_get() 23 | #' svc 24 | #' } 25 | odata_service_get <- function(pid = get_default_pid(), 26 | fid = get_default_fid(), 27 | url = get_default_url(), 28 | un = get_default_un(), 29 | pw = get_default_pw(), 30 | retries = get_retries()) { 31 | yell_if_missing(url, un, pw) 32 | httr::RETRY( 33 | "GET", 34 | httr::modify_url( 35 | url, 36 | path = glue::glue( 37 | "v1/projects/{pid}/forms/{URLencode(fid, reserved = TRUE)}.svc" 38 | ) 39 | ), 40 | httr::add_headers(Accept = "application/json"), 41 | httr::authenticate(un, pw), 42 | times = retries 43 | ) %>% 44 | yell_if_error(., url, un, pw) %>% 45 | httr::content(.) %>% 46 | magrittr::extract2("value") %>% 47 | { # nolint 48 | tibble::tibble( 49 | name = purrr::map_chr(., "name"), 50 | kind = purrr::map_chr(., "kind"), 51 | url = purrr::map_chr(., "url") 52 | ) 53 | } 54 | } 55 | 56 | # usethis::use_test("odata_service_get") # nolint 57 | -------------------------------------------------------------------------------- /man/fq_svc.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_svc} 5 | \alias{fq_svc} 6 | \title{OData service document for an ODK Central form.} 7 | \format{ 8 | A tibble with one row per submission data endpoint. 9 | } 10 | \source{ 11 | OData service document for 12 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 13 | } 14 | \usage{ 15 | fq_svc 16 | } 17 | \description{ 18 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 19 | } 20 | \details{ 21 | The OData response for the metadata of an ODK Central form. 22 | 23 | This data is kept up to date with the data used in vignettes and package 24 | tests. The data is comprised of test records with nonsensical data. 25 | The forms used to capture this data are development versions of real-world 26 | forms. 27 | } 28 | \seealso{ 29 | Other included: 30 | \code{\link{fq_attachments}}, 31 | \code{\link{fq_data}}, 32 | \code{\link{fq_data_strata}}, 33 | \code{\link{fq_data_taxa}}, 34 | \code{\link{fq_form_detail}}, 35 | \code{\link{fq_form_list}}, 36 | \code{\link{fq_form_schema}}, 37 | \code{\link{fq_form_xml}}, 38 | \code{\link{fq_meta}}, 39 | \code{\link{fq_project_detail}}, 40 | \code{\link{fq_project_list}}, 41 | \code{\link{fq_raw}}, 42 | \code{\link{fq_raw_strata}}, 43 | \code{\link{fq_raw_taxa}}, 44 | \code{\link{fq_submission_list}}, 45 | \code{\link{fq_submissions}}, 46 | \code{\link{fq_zip_data}}, 47 | \code{\link{fq_zip_strata}}, 48 | \code{\link{fq_zip_taxa}}, 49 | \code{\link{fs_v7}}, 50 | \code{\link{fs_v7_raw}}, 51 | \code{\link{geo_fs}}, 52 | \code{\link{geo_gj}}, 53 | \code{\link{geo_gj88}}, 54 | \code{\link{geo_gj_raw}}, 55 | \code{\link{geo_wkt}}, 56 | \code{\link{geo_wkt88}}, 57 | \code{\link{geo_wkt_raw}} 58 | } 59 | \concept{included} 60 | \keyword{datasets} 61 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Test environments 2 | * Local machine 3 | * Running under: Ubuntu 20.04.2 LTS 4 | * Platform: x86_64-pc-linux-gnu (64-bit) 5 | * R version 4.0.4 (2021-02-15) 6 | * AppVeyor CI 7 | * Running under: Windows Server 2012 R2 x64 (build 9600) 8 | * Platform: x86_64-w64-mingw32/x64 (64-bit) 9 | * R version 4.0.3 Patched (2020-11-08 r79411) 10 | * GitHub Actions: R devel, release, oldrel for each of 11 | * Windows-latest (Windows Server 2019) 12 | * Windows Server 2016 13 | * MacOS-lastest (MacOS X Catalina 10.05) 14 | * Ubuntu 20.04 15 | * Ubuntu 18.04 16 | 17 | ## R CMD check results 18 | 19 | 0 errors | 0 warnings | 1 note 20 | 21 | * This is a new release. 22 | 23 | Resolved NOTE comments: 24 | * Possibly invalid URLs: 25 | * The package comparison section in the README contains Markdown badges with 26 | CRAN links to packages that are not yet or not any more on CRAN. These 27 | links are correct, and while they currently do not resolve, they will do so 28 | once the packages are (re-)submitted to CRAN. Currently removed. 29 | * The README contains an ODK Central form OData service URL to illustrate 30 | setting up ruODK. The URL redirects to a login screen if followed directly. 31 | This is expected behaviour. Currently not appearing as warning. 32 | * The PDF version of the manual is now included. 33 | * The example data contains UTF-8 strings. This is a realistic scenario. 34 | The note has disappeared after the R version 4 release. 35 | * Test coverage: All functionality supporting the current ODK Central release is 36 | covered by tests. 37 | The only exception is `form_schema{_parse}`, which supports a breaking 38 | change between ODK Central 0.7 and 0.8. The test server runs ODK Central 0.8, 39 | a production server (used by the package author, but not accessible to other 40 | maintainers) runs 0.7 successfully. The tests for v 0.7 use packaged data. 41 | -------------------------------------------------------------------------------- /tests/testthat/test-submission_list.R: -------------------------------------------------------------------------------- 1 | test_that("submission_list works", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | 6 | sl <- submission_list( 7 | get_test_pid(), 8 | get_test_fid(), 9 | url = get_test_url(), 10 | un = get_test_un(), 11 | pw = get_test_pw() 12 | ) 13 | 14 | fl <- form_list( 15 | get_test_pid(), 16 | url = get_test_url(), 17 | un = get_test_un(), 18 | pw = get_test_pw() 19 | ) 20 | # submission_list returns a tibble 21 | testthat::expect_equal(class(sl), c("tbl_df", "tbl", "data.frame")) 22 | 23 | # https://github.com/ropensci/ruODK/issues/138 24 | # review_state was incorrectly picked up by mutate_at looking for "_at" dates 25 | testthat::expect_equal(class(sl$review_state), "character") 26 | 27 | # Submission attributes are the tibble's columns 28 | cn <- c( 29 | "instance_id", 30 | "submitter_id", 31 | "device_id", 32 | "created_at", 33 | "updated_at", 34 | "review_state", 35 | "user_agent", 36 | "deleted_at", 37 | "submitter_id_2", 38 | "submitter_type", 39 | "submitter_display_name", 40 | "submitter_created_at", 41 | "submitter_updated_at", 42 | "submitter_deleted_at", 43 | "current_version" 44 | ) 45 | testthat::expect_equal(names(sl), cn) 46 | # testthat::expect_equal(class(sl$review_state), "logical") 47 | purrr::map( 48 | cn, 49 | ~ testthat::expect_true( 50 | . %in% names(sl), 51 | label = glue::glue("Column {.} in submission_list") 52 | ) 53 | ) 54 | 55 | # Number of submissions (rows) is same as advertised in form_list 56 | form_list_nsub <- fl %>% 57 | dplyr::filter(fid == get_test_fid()) %>% 58 | magrittr::extract2("submissions") %>% 59 | as.numeric() 60 | testthat::expect_equal(nrow(sl), form_list_nsub) 61 | }) 62 | 63 | # usethis::use_r("submission_list") # nolint 64 | -------------------------------------------------------------------------------- /man/predict_ruodk_name.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/form_schema_parse.R 3 | \name{predict_ruodk_name} 4 | \alias{predict_ruodk_name} 5 | \title{Predict a field name after \code{tidyr::unnest_wider(names_sep="_")} prefixes 6 | the form path.} 7 | \usage{ 8 | predict_ruodk_name(name_str, path_str) 9 | } 10 | \arguments{ 11 | \item{name_str}{An Xforms field name string.} 12 | 13 | \item{path_str}{A path string, 14 | e.g. "Submissions" or "Submissions.group_name".} 15 | } 16 | \value{ 17 | The name as built by \code{tidyr::unnest_wider(names_sep="_")}. 18 | } 19 | \description{ 20 | Predict a field name after \code{tidyr::unnest_wider(names_sep="_")} prefixes 21 | the form path. 22 | } 23 | \examples{ 24 | \dontrun{ 25 | predict_ruodk_name("bar", "Submissions.foo") 26 | # > "foo_bar" 27 | predict_ruodk_name("bar", "Submissions") 28 | # > "bar" 29 | predict_ruodk_name("rock", "Submissions.foo_fighters") 30 | # > "foo_fighters_rock" 31 | } 32 | } 33 | \seealso{ 34 | Other utilities: 35 | \code{\link{attachment_get}()}, 36 | \code{\link{attachment_link}()}, 37 | \code{\link{attachment_url}()}, 38 | \code{\link{drop_null_coords}()}, 39 | \code{\link{form_schema_parse}()}, 40 | \code{\link{get_one_attachment}()}, 41 | \code{\link{get_one_submission}()}, 42 | \code{\link{get_one_submission_att_list}()}, 43 | \code{\link{get_one_submission_audit}()}, 44 | \code{\link{handle_ru_attachments}()}, 45 | \code{\link{handle_ru_datetimes}()}, 46 | \code{\link{handle_ru_geopoints}()}, 47 | \code{\link{handle_ru_geoshapes}()}, 48 | \code{\link{handle_ru_geotraces}()}, 49 | \code{\link{isodt_to_local}()}, 50 | \code{\link{odata_submission_rectangle}()}, 51 | \code{\link{prepend_uuid}()}, 52 | \code{\link{split_geopoint}()}, 53 | \code{\link{split_geoshape}()}, 54 | \code{\link{split_geotrace}()}, 55 | \code{\link{strip_uuid}()}, 56 | \code{\link{tidyeval}}, 57 | \code{\link{unnest_all}()} 58 | } 59 | \concept{utilities} 60 | \keyword{internal} 61 | -------------------------------------------------------------------------------- /tests/testthat/test-entitylist_detail.R: -------------------------------------------------------------------------------- 1 | test_that("entitylist_detail works", { 2 | ru_setup( 3 | pid = get_test_pid(), 4 | url = get_test_url(), 5 | un = get_test_un(), 6 | pw = get_test_pw(), 7 | odkc_version = get_test_odkc_version() 8 | ) 9 | 10 | ds <- entitylist_list() 11 | did <- ds$name[1] 12 | 13 | ds1 <- entitylist_detail(did = did) 14 | 15 | # entitylist_detail returns a list 16 | testthat::expect_is(ds1, "list") 17 | 18 | # linked_forms contain form xmlFormId and name 19 | lf <- ds1$linked_forms |> 20 | purrr::list_transpose() |> 21 | tibble::as_tibble() 22 | testthat::expect_equal(names(lf), c("xmlFormId", "name")) 23 | 24 | # source_forms contain form xmlFormId and name 25 | sf <- ds1$source_forms |> 26 | purrr::list_transpose() |> 27 | tibble::as_tibble() 28 | testthat::expect_equal(names(sf), c("xmlFormId", "name")) 29 | 30 | # properties lists attributes of entities 31 | pr <- ds1$properties |> 32 | purrr::list_transpose() |> 33 | tibble::as_tibble() 34 | testthat::expect_equal( 35 | names(pr), 36 | c("name", "publishedAt", "odataName", "forms") 37 | ) 38 | }) 39 | 40 | test_that("entitylist_detail errors if did is missing", { 41 | testthat::expect_error( 42 | entitylist_detail() 43 | ) 44 | }) 45 | 46 | test_that("entitylist_detail warns if odkc_version too low", { 47 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 48 | message = "Test server not configured" 49 | ) 50 | 51 | ru_setup( 52 | pid = get_test_pid(), 53 | url = get_test_url(), 54 | un = get_test_un(), 55 | pw = get_test_pw(), 56 | odkc_version = get_test_odkc_version() 57 | ) 58 | 59 | ds <- entitylist_list() 60 | did <- ds$name[1] 61 | 62 | ds1 <- entitylist_detail(did = did) 63 | 64 | testthat::expect_warning( 65 | ds1 <- entitylist_detail(did = did, odkc_version = "1.5.3") 66 | ) 67 | }) 68 | 69 | 70 | # usethis::use_r("entitylist_detail") # nolint 71 | -------------------------------------------------------------------------------- /R/form_xml.R: -------------------------------------------------------------------------------- 1 | #' Show the XML representation of one form as list. 2 | #' 3 | #' `r lifecycle::badge("stable")` 4 | #' 5 | #' @param parse Whether to parse the XML into a nested list, default: TRUE 6 | #' @template param-pid 7 | #' @template param-fid 8 | #' @template param-url 9 | #' @template param-auth 10 | #' @template param-retries 11 | #' @return The form XML as a nested list. 12 | # nolint start 13 | #' @seealso \url{https://docs.getodk.org/central-api-form-management/#retrieving-form-xml} 14 | # nolint end 15 | #' @family form-management 16 | #' @export 17 | #' @examples 18 | #' \dontrun{ 19 | #' # See vignette("setup") for setup and authentication options 20 | #' # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 21 | #' 22 | #' # With explicit pid and fid 23 | #' fxml_defaults <- form_xml(1, "build_xformsId") 24 | #' 25 | #' # With defaults 26 | #' fxml <- form_xml() 27 | #' listviewer::jsonedit(fxml) 28 | #' 29 | #' # form_xml returns a nested list 30 | #' class(fxml) 31 | #' # > "list" 32 | #' } 33 | form_xml <- function(parse = TRUE, 34 | pid = get_default_pid(), 35 | fid = get_default_fid(), 36 | url = get_default_url(), 37 | un = get_default_un(), 38 | pw = get_default_pw(), 39 | retries = get_retries()) { 40 | yell_if_missing(url, un, pw, pid = pid, fid = fid) 41 | out <- httr::RETRY( 42 | "GET", 43 | httr::modify_url( 44 | url, 45 | path = glue::glue( 46 | "v1/projects/{pid}/forms/{URLencode(fid, reserved = TRUE)}.xml" 47 | ) 48 | ), 49 | httr::add_headers("Accept" = "application/xml"), 50 | httr::authenticate(un, pw), 51 | times = retries 52 | ) %>% 53 | yell_if_error(., url, un, pw) %>% 54 | httr::content(.) 55 | 56 | if (parse == FALSE) { 57 | return(out) 58 | } 59 | out %>% xml2::as_list(.) 60 | } 61 | 62 | # usethis::use_test("form_xml") # nolint 63 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | exclude: "/migrations/|^venv/|/email/subject/" 2 | default_stages: [pre-commit] 3 | 4 | repos: 5 | - repo: https://github.com/pre-commit/pre-commit-hooks 6 | rev: v5.0.0 7 | hooks: 8 | - id: trailing-whitespace 9 | name: Drop trailing whitespace 10 | exclude: man 11 | - id: end-of-file-fixer 12 | name: Fix end of files 13 | - id: check-yaml 14 | name: Check YAML syntax 15 | - id: check-toml 16 | name: Check TOML syntax 17 | # - id: pretty-format-json 18 | # name: Format JSON 19 | - id: check-added-large-files 20 | name: Prevent adding large files 21 | args: ['--maxkb=1024'] 22 | - id: check-merge-conflict 23 | name: Check for unhandled merge conflicts 24 | - id: debug-statements 25 | name: Check for debug statements 26 | - id: detect-private-key 27 | name: Detect private keys 28 | 29 | # https://lorenzwalthert.github.io/precommit/articles/available-hooks.html 30 | - repo: https://github.com/lorenzwalthert/precommit 31 | rev: v0.4.3.9003 32 | hooks: 33 | - id: style-files 34 | name: Style code to tidyverse conventions 35 | args: [--scope=spaces] 36 | - id: readme-rmd-rendered 37 | name: Ensure README.md is up to date 38 | - id: no-debug-statement 39 | name: Ensure that no debug() statement is committed 40 | - id: no-browser-statement 41 | name: Ensure that no browser() statement is committed 42 | # - id: spell-check 43 | # name: Spellcheck 44 | # - id: deps-in-desc 45 | # name: Ensure that DESCRIPTION lists all dependencies 46 | # args: [--allow_private_imports, --root=R] 47 | - id: use-tidy-description 48 | name: Format DESCRIPTION 49 | # - id: pkgdown 50 | # name: Validate pkgdown.yml 51 | # - id: lintr 52 | # name: Lint code but emit only warnings 53 | # args: [--warn_only] 54 | # verbose: true 55 | -------------------------------------------------------------------------------- /man/geo_wkt88.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{geo_wkt88} 6 | \alias{geo_wkt88} 7 | \title{The parsed submissions of a form containing geofields in WKT 8 | with trailing empty coordinates present.} 9 | \format{ 10 | An object of class \code{tbl_df} (inherits from \code{tbl}, \code{data.frame}) with 1 rows and 48 columns. 11 | } 12 | \source{ 13 | \code{\link{odata_submission_get}(wkt=TRUE, parse=TRUE)} 14 | run on the test form 15 | \code{system.file("extdata", "Locations.xml", package = "ruODK")}. 16 | } 17 | \usage{ 18 | geo_wkt88 19 | } 20 | \description{ 21 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 22 | } 23 | \details{ 24 | This issue was fixed in #88. 25 | ODK Central versions 0.7 - 0.9 export geotraces and geoshapes with trailing 26 | empty coordinates. ruODK has a patch to drop trailing empty coordinates. 27 | This dataset is used to test the patch in ruODK. 28 | } 29 | \seealso{ 30 | Other included: 31 | \code{\link{fq_attachments}}, 32 | \code{\link{fq_data}}, 33 | \code{\link{fq_data_strata}}, 34 | \code{\link{fq_data_taxa}}, 35 | \code{\link{fq_form_detail}}, 36 | \code{\link{fq_form_list}}, 37 | \code{\link{fq_form_schema}}, 38 | \code{\link{fq_form_xml}}, 39 | \code{\link{fq_meta}}, 40 | \code{\link{fq_project_detail}}, 41 | \code{\link{fq_project_list}}, 42 | \code{\link{fq_raw}}, 43 | \code{\link{fq_raw_strata}}, 44 | \code{\link{fq_raw_taxa}}, 45 | \code{\link{fq_submission_list}}, 46 | \code{\link{fq_submissions}}, 47 | \code{\link{fq_svc}}, 48 | \code{\link{fq_zip_data}}, 49 | \code{\link{fq_zip_strata}}, 50 | \code{\link{fq_zip_taxa}}, 51 | \code{\link{fs_v7}}, 52 | \code{\link{fs_v7_raw}}, 53 | \code{\link{geo_fs}}, 54 | \code{\link{geo_gj}}, 55 | \code{\link{geo_gj88}}, 56 | \code{\link{geo_gj_raw}}, 57 | \code{\link{geo_wkt}}, 58 | \code{\link{geo_wkt_raw}} 59 | } 60 | \concept{included} 61 | \keyword{datasets} 62 | -------------------------------------------------------------------------------- /man/geo_gj88.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \encoding{UTF-8} 5 | \name{geo_gj88} 6 | \alias{geo_gj88} 7 | \title{The parsed submissions of a form containing geofields in GeoJSON 8 | with trailing empty coordinates present.} 9 | \format{ 10 | An object of class \code{tbl_df} (inherits from \code{tbl}, \code{data.frame}) with 1 rows and 51 columns. 11 | } 12 | \source{ 13 | \code{\link{odata_submission_get}(wkt=FALSE, parse=TRUE)} 14 | run on the test form 15 | \code{system.file("extdata", "Locations.xml", package = "ruODK")}. 16 | } 17 | \usage{ 18 | geo_gj88 19 | } 20 | \description{ 21 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 22 | } 23 | \details{ 24 | This issue was fixed in #88. 25 | ODK Central versions 0.7 - 0.9 export geotraces and geoshapes with trailing 26 | empty coordinates. ruODK has a patch to drop trailing empty coordinates. 27 | This dataset is used to test the patch in ruODK. 28 | } 29 | \seealso{ 30 | Other included: 31 | \code{\link{fq_attachments}}, 32 | \code{\link{fq_data}}, 33 | \code{\link{fq_data_strata}}, 34 | \code{\link{fq_data_taxa}}, 35 | \code{\link{fq_form_detail}}, 36 | \code{\link{fq_form_list}}, 37 | \code{\link{fq_form_schema}}, 38 | \code{\link{fq_form_xml}}, 39 | \code{\link{fq_meta}}, 40 | \code{\link{fq_project_detail}}, 41 | \code{\link{fq_project_list}}, 42 | \code{\link{fq_raw}}, 43 | \code{\link{fq_raw_strata}}, 44 | \code{\link{fq_raw_taxa}}, 45 | \code{\link{fq_submission_list}}, 46 | \code{\link{fq_submissions}}, 47 | \code{\link{fq_svc}}, 48 | \code{\link{fq_zip_data}}, 49 | \code{\link{fq_zip_strata}}, 50 | \code{\link{fq_zip_taxa}}, 51 | \code{\link{fs_v7}}, 52 | \code{\link{fs_v7_raw}}, 53 | \code{\link{geo_fs}}, 54 | \code{\link{geo_gj}}, 55 | \code{\link{geo_gj_raw}}, 56 | \code{\link{geo_wkt}}, 57 | \code{\link{geo_wkt88}}, 58 | \code{\link{geo_wkt_raw}} 59 | } 60 | \concept{included} 61 | \keyword{datasets} 62 | -------------------------------------------------------------------------------- /R/project_create.R: -------------------------------------------------------------------------------- 1 | #' Create a new project. 2 | #' 3 | #' `r lifecycle::badge('experimental')` 4 | #' 5 | #' @param name The desired name of the project. Can contain whitespace. 6 | #' @template param-url 7 | #' @template param-auth 8 | #' @return A tibble with one row per project and all project metadata 9 | #' as columns as per ODK Central API docs. 10 | # nolint start 11 | #' @seealso \url{https://docs.getodk.org/central-api-project-management/#creating-a-project} 12 | # nolint end 13 | #' @family project-management 14 | #' @export 15 | #' @examples 16 | #' \dontrun{ 17 | #' # See vignette("setup") for setup and authentication options 18 | #' # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 19 | #' 20 | #' p <- project_create("Test Project") 21 | #' knitr::kable(p) 22 | #' 23 | #' # project_create returns a tibble 24 | #' class(p) 25 | #' # > "tbl_df" "tbl" "data.frame" 26 | #' 27 | #' # columns are project metadata 28 | #' names(p) 29 | #' # > "id" "name" "archived" 30 | #' } 31 | project_create <- function(name, 32 | url = get_default_url(), 33 | un = get_default_un(), 34 | pw = get_default_pw()) { 35 | ru_msg_warn("Not implemented.") 36 | 37 | # nolint start 38 | # has_internet() 39 | # glue::glue("{url}/v1/projects/") %>% 40 | # httr::POST( 41 | # config = list( 42 | # httr::add_headers("Content-Type" = "application/json"), 43 | # httr::authenticate(un, pw) 44 | # ), 45 | # body = jsonlite::toJSON(list(name = "x"), auto_unbox = T), 46 | # encode = "json" 47 | # ) %>% 48 | # httr::stop_for_status( 49 | # task = glue::glue("create a project with name {name}") 50 | # ) %>% 51 | # httr::content(.) %>% 52 | # { 53 | # tibble::tibble( 54 | # id = purrr::map_int(., "id"), 55 | # name = purrr::map_chr(., "name"), 56 | # archived = ifelse(is.null(.$archived), FALSE, TRUE) 57 | # ) 58 | # } 59 | # nolint end 60 | } 61 | 62 | # usethis::use_test("project_create") # nolint 63 | -------------------------------------------------------------------------------- /R/handle_ru_datetimes.R: -------------------------------------------------------------------------------- 1 | #' Parse datetimes of submission data according to a form schema. 2 | #' 3 | #' `r lifecycle::badge("stable")` 4 | #' 5 | #' @details For a given tibble of submissions, parse all columns which are 6 | #' marked in the form schema as type "date" or "dateTime" using a set of 7 | #' lubridate orders and a given timezone. 8 | #' @param data Submissions rectangled into a tibble. E.g. the output of 9 | #' ``` 10 | #' ruODK::odata_submission_get(parse = FALSE) %>% 11 | #' ruODK::odata_submission_rectangle() 12 | #' ``` 13 | #' @param form_schema The `form_schema` for the submissions. 14 | #' E.g. the output of `ruODK::form_schema()`. 15 | #' @template param-orders 16 | #' @template param-tz 17 | #' @template param-verbose 18 | #' @return The submissions tibble with all date/dateTime columns mutated as 19 | #' lubridate datetimes. 20 | #' @export 21 | #' @family utilities 22 | #' @examples 23 | #' \dontrun{ 24 | #' library(magrittr) 25 | #' data("fq_raw") 26 | #' data("fq_form_schema") 27 | #' 28 | #' fq_with_dates <- fq_raw %>% 29 | #' ruODK::odata_submission_rectangle() %>% 30 | #' ruODK::handle_ru_datetimes(form_schema = fq_form_schema) 31 | #' 32 | #' dplyr::glimpse(fq_with_dates) 33 | #' } 34 | handle_ru_datetimes <- function(data, 35 | form_schema, 36 | orders = get_default_orders(), 37 | tz = get_default_tz(), 38 | verbose = get_ru_verbose()) { 39 | # Find all date/time columns in form_schema 40 | dttm_cols <- form_schema %>% 41 | dplyr::filter(type %in% c("dateTime", "date")) %>% 42 | magrittr::extract2("ruodk_name") %>% 43 | intersect(names(data)) 44 | 45 | x <- paste(dttm_cols, collapse = ", ") # nolint 46 | "Found date/times: {x}." %>% 47 | glue::glue() %>% 48 | ru_msg_info(verbose = verbose) 49 | 50 | data %>% 51 | dplyr::mutate_at( 52 | dplyr::vars(dplyr::all_of(dttm_cols)), 53 | ~ isodt_to_local(., orders = orders, tz = tz) 54 | ) 55 | } 56 | 57 | # usethis::use_test("handle_ru_datetimes") # nolint 58 | -------------------------------------------------------------------------------- /man/project_create.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/project_create.R 3 | \name{project_create} 4 | \alias{project_create} 5 | \title{Create a new project.} 6 | \usage{ 7 | project_create( 8 | name, 9 | url = get_default_url(), 10 | un = get_default_un(), 11 | pw = get_default_pw() 12 | ) 13 | } 14 | \arguments{ 15 | \item{name}{The desired name of the project. Can contain whitespace.} 16 | 17 | \item{url}{The ODK Central base URL without trailing slash. 18 | 19 | Default: \code{\link{get_default_url}}. 20 | 21 | Set default \code{url} through \code{ru_setup(url="...")}. 22 | 23 | See \code{vignette("Setup", package = "ruODK")}.} 24 | 25 | \item{un}{The ODK Central username (an email address). 26 | Default: \code{\link{get_default_un}}. 27 | Set default \code{un} through \code{ru_setup(un="...")}. 28 | See \code{vignette("Setup", package = "ruODK")}.} 29 | 30 | \item{pw}{The ODK Central password. 31 | Default: \code{\link{get_default_pw}}. 32 | Set default \code{pw} through \code{ru_setup(pw="...")}. 33 | See \code{vignette("Setup", package = "ruODK")}.} 34 | } 35 | \value{ 36 | A tibble with one row per project and all project metadata 37 | as columns as per ODK Central API docs. 38 | } 39 | \description{ 40 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#experimental}{\figure{lifecycle-experimental.svg}{options: alt='[Experimental]'}}}{\strong{[Experimental]}} 41 | } 42 | \examples{ 43 | \dontrun{ 44 | # See vignette("setup") for setup and authentication options 45 | # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 46 | 47 | p <- project_create("Test Project") 48 | knitr::kable(p) 49 | 50 | # project_create returns a tibble 51 | class(p) 52 | # > "tbl_df" "tbl" "data.frame" 53 | 54 | # columns are project metadata 55 | names(p) 56 | # > "id" "name" "archived" 57 | } 58 | } 59 | \seealso{ 60 | \url{https://docs.getodk.org/central-api-project-management/#creating-a-project} 61 | 62 | Other project-management: 63 | \code{\link{project_detail}()}, 64 | \code{\link{project_list}()} 65 | } 66 | \concept{project-management} 67 | -------------------------------------------------------------------------------- /tests/testthat/test-drop_null_coords.R: -------------------------------------------------------------------------------- 1 | test_that("drop_null_coords works on data with empty last coords ", { 2 | # This test will break once the ODK Central Sandbox has fixed 3 | # issue https://github.com/getodk/central-backend/issues/282 4 | # through https://github.com/getodk/central-backend/pull/283 5 | # and ruODK's package data have been updated. 6 | # We therefore have included a snapshot of test data exhibiting the problem. 7 | # The data uses "bad" coordinates from the ODK Sandbox and an unpatched ruODK. 8 | # The data "geo_gj" uses "bad" coordinates (soon: good coordinates) from the 9 | # ODK Sandbox and a patched ruODK. 10 | data("geo_gj88") 11 | 12 | len_coords <- length(geo_gj88$path_location_path_gps[[1]]$coordinates) 13 | 14 | length(geo_gj88$path_location_path_gps[[1]]$coordinates[[len_coords]]) %>% 15 | testthat::expect_equal(2) 16 | 17 | geo_gj88$path_location_path_gps[[1]]$coordinates[[len_coords]][[1]] %>% 18 | testthat::expect_null() 19 | 20 | geo_gj88$path_location_path_gps[[1]]$coordinates[[len_coords]][[2]] %>% 21 | testthat::expect_null() 22 | 23 | geo_gj_repaired <- geo_gj88 %>% 24 | dplyr::mutate( 25 | path_location_path_gps = path_location_path_gps %>% 26 | purrr::map(drop_null_coords) 27 | ) 28 | 29 | len_coords_repaired <- length( 30 | geo_gj_repaired$path_location_path_gps[[1]]$coordinates 31 | ) 32 | testthat::expect_equal(len_coords_repaired + 1, len_coords) 33 | }) 34 | 35 | test_that("drop_null_coords works on data without empty last coords ", { 36 | data("geo_gj") 37 | 38 | len_coords <- length(geo_gj$path_location_path_gps[[1]]$coordinates) 39 | 40 | geo_gj_repaired <- geo_gj %>% 41 | dplyr::mutate( 42 | path_location_path_gps = path_location_path_gps %>% 43 | purrr::map(drop_null_coords) 44 | ) 45 | 46 | len_coords_repaired <- length( 47 | geo_gj_repaired$path_location_path_gps[[1]]$coordinates 48 | ) 49 | 50 | # No coordinates were harmed in the making of this test 51 | testthat::expect_equal(len_coords_repaired, len_coords) 52 | }) 53 | 54 | 55 | # usethis::use_r("drop_null_coords") # nolint 56 | -------------------------------------------------------------------------------- /man/fq_raw_strata.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_raw_strata} 5 | \alias{fq_raw_strata} 6 | \title{OData submission data for a subgroup of an ODK Central form.} 7 | \format{ 8 | A list of lists 9 | } 10 | \source{ 11 | See \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 12 | } 13 | \usage{ 14 | fq_raw_strata 15 | } 16 | \description{ 17 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 18 | } 19 | \details{ 20 | The OData response for the subgroup of an ODK Central form. 21 | 22 | This subgroup represents vegetation strata as per the NVIS classification. 23 | A vegetation stratum is a layer of plants with the same height, and dominated 24 | by one or few plant taxa. Plant communities can be made of up to five strata, 25 | with two to three being most common. 26 | 27 | This data is kept up to date with the data used in vignettes and package 28 | tests. The data is comprised of test records with nonsensical data. 29 | The forms used to capture this data are development versions of real-world 30 | forms. 31 | } 32 | \seealso{ 33 | Other included: 34 | \code{\link{fq_attachments}}, 35 | \code{\link{fq_data}}, 36 | \code{\link{fq_data_strata}}, 37 | \code{\link{fq_data_taxa}}, 38 | \code{\link{fq_form_detail}}, 39 | \code{\link{fq_form_list}}, 40 | \code{\link{fq_form_schema}}, 41 | \code{\link{fq_form_xml}}, 42 | \code{\link{fq_meta}}, 43 | \code{\link{fq_project_detail}}, 44 | \code{\link{fq_project_list}}, 45 | \code{\link{fq_raw}}, 46 | \code{\link{fq_raw_taxa}}, 47 | \code{\link{fq_submission_list}}, 48 | \code{\link{fq_submissions}}, 49 | \code{\link{fq_svc}}, 50 | \code{\link{fq_zip_data}}, 51 | \code{\link{fq_zip_strata}}, 52 | \code{\link{fq_zip_taxa}}, 53 | \code{\link{fs_v7}}, 54 | \code{\link{fs_v7_raw}}, 55 | \code{\link{geo_fs}}, 56 | \code{\link{geo_gj}}, 57 | \code{\link{geo_gj88}}, 58 | \code{\link{geo_gj_raw}}, 59 | \code{\link{geo_wkt}}, 60 | \code{\link{geo_wkt88}}, 61 | \code{\link{geo_wkt_raw}} 62 | } 63 | \concept{included} 64 | \keyword{datasets} 65 | -------------------------------------------------------------------------------- /man/parse_odkc_version.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_setup.R 3 | \name{parse_odkc_version} 4 | \alias{parse_odkc_version} 5 | \title{Parse a given ODK Central version string or number into a \code{semver}.} 6 | \usage{ 7 | parse_odkc_version(v, env_var = "ODKC_VERSION") 8 | } 9 | \arguments{ 10 | \item{v}{A string (e.g. "ODKC_VERSION=") or number (e.g. 0.8, 1.5) of a 11 | complete or partial semver, or a semver of class "svlist".} 12 | 13 | \item{env_var}{A string indicating which environment variable was targeted. 14 | This is used in the warning to advise which environment variable to update. 15 | If set to an empty string, the warning message is suppressed. 16 | Default: "ODKC_VERSION".} 17 | } 18 | \value{ 19 | semver::svlist The version as semver of major, minor, and patch. 20 | } 21 | \description{ 22 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 23 | } 24 | \details{ 25 | Past versions of ruODK advised to set ODKC_VERSION to a floating point number 26 | indicating major and minor versions, e.g. \code{ODKC_VERSION=0.7} or 27 | \code{ODKC_VERSION=1.5}. 28 | 29 | ODK Central has since switched to semantic versioning, e.g. 30 | \verb{ODKC_VERSION=ODKC_VERSION=}. 31 | 32 | To preserve backwards compatibility, ruODK handles both formats gracefully, 33 | but emits a helpful warning to update the version string if the older format 34 | is detected, or the version string is missing the minor or patch version. 35 | } 36 | \examples{ 37 | parse_odkc_version("1.2.3") 38 | 39 | # Warn: too short 40 | parse_odkc_version("1") 41 | parse_odkc_version("1.2") 42 | 43 | # Warn: too long 44 | parse_odkc_version("1.2.3.4") 45 | 46 | # Warn: otherwise invalid 47 | parse_odkc_version("1.2.") 48 | parse_odkc_version(".2.3") 49 | 50 | } 51 | \seealso{ 52 | Other ru_settings: 53 | \code{\link{odata_svc_parse}()}, 54 | \code{\link{ru_settings}()}, 55 | \code{\link{ru_setup}()}, 56 | \code{\link{semver_gt}()}, 57 | \code{\link{semver_lt}()}, 58 | \code{\link{yell_if_error}()}, 59 | \code{\link{yell_if_missing}()} 60 | } 61 | \concept{ru_settings} 62 | -------------------------------------------------------------------------------- /man/fq_form_schema.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_form_schema} 5 | \alias{fq_form_schema} 6 | \title{JSON form schema for an ODK Central form.} 7 | \format{ 8 | The output of \code{ruODK::form_schema()}, a tibble with columns "type", 9 | "name" and "path" and one row per form field. 10 | } 11 | \source{ 12 | See \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 13 | and \code{ruODK::form_schema()}. 14 | } 15 | \usage{ 16 | fq_form_schema 17 | } 18 | \description{ 19 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 20 | } 21 | \details{ 22 | The parsed form schema of an ODK Central form. 23 | 24 | This data is kept up to date with the data used in vignettes and package 25 | tests. The data is comprised of test records with nonsensical data. 26 | The forms used to capture this data are development versions of real-world 27 | forms. 28 | 29 | This data is used to build vignettes offline and without the need for 30 | credentials to an ODK Central server. The test suite ensures that the 31 | "canned" data is identical to the "live" data. 32 | } 33 | \seealso{ 34 | Other included: 35 | \code{\link{fq_attachments}}, 36 | \code{\link{fq_data}}, 37 | \code{\link{fq_data_strata}}, 38 | \code{\link{fq_data_taxa}}, 39 | \code{\link{fq_form_detail}}, 40 | \code{\link{fq_form_list}}, 41 | \code{\link{fq_form_xml}}, 42 | \code{\link{fq_meta}}, 43 | \code{\link{fq_project_detail}}, 44 | \code{\link{fq_project_list}}, 45 | \code{\link{fq_raw}}, 46 | \code{\link{fq_raw_strata}}, 47 | \code{\link{fq_raw_taxa}}, 48 | \code{\link{fq_submission_list}}, 49 | \code{\link{fq_submissions}}, 50 | \code{\link{fq_svc}}, 51 | \code{\link{fq_zip_data}}, 52 | \code{\link{fq_zip_strata}}, 53 | \code{\link{fq_zip_taxa}}, 54 | \code{\link{fs_v7}}, 55 | \code{\link{fs_v7_raw}}, 56 | \code{\link{geo_fs}}, 57 | \code{\link{geo_gj}}, 58 | \code{\link{geo_gj88}}, 59 | \code{\link{geo_gj_raw}}, 60 | \code{\link{geo_wkt}}, 61 | \code{\link{geo_wkt88}}, 62 | \code{\link{geo_wkt_raw}} 63 | } 64 | \concept{included} 65 | \keyword{datasets} 66 | -------------------------------------------------------------------------------- /man/fq_raw.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_raw} 5 | \alias{fq_raw} 6 | \title{OData submission data for an ODK Central form.} 7 | \format{ 8 | A list of lists 9 | } 10 | \source{ 11 | See \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 12 | } 13 | \usage{ 14 | fq_raw 15 | } 16 | \description{ 17 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 18 | } 19 | \details{ 20 | The OData response for the submissions of an ODK Central form. 21 | This form represents a Flora Quadrat, which is a ca 50 by 50 m quadrat of 22 | a uniform plant community. 23 | 24 | The XML and .odkbuild versions for this form are available as 25 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 26 | and \code{system.file("extdata", "FloraQuadrat04.odkbuild", package = "ruODK")}, 27 | respectively. 28 | 29 | This data is kept up to date with the data used in vignettes and package 30 | tests. The data is comprised of test records with nonsensical data. 31 | The forms used to capture this data are development versions of real-world 32 | forms. 33 | } 34 | \seealso{ 35 | Other included: 36 | \code{\link{fq_attachments}}, 37 | \code{\link{fq_data}}, 38 | \code{\link{fq_data_strata}}, 39 | \code{\link{fq_data_taxa}}, 40 | \code{\link{fq_form_detail}}, 41 | \code{\link{fq_form_list}}, 42 | \code{\link{fq_form_schema}}, 43 | \code{\link{fq_form_xml}}, 44 | \code{\link{fq_meta}}, 45 | \code{\link{fq_project_detail}}, 46 | \code{\link{fq_project_list}}, 47 | \code{\link{fq_raw_strata}}, 48 | \code{\link{fq_raw_taxa}}, 49 | \code{\link{fq_submission_list}}, 50 | \code{\link{fq_submissions}}, 51 | \code{\link{fq_svc}}, 52 | \code{\link{fq_zip_data}}, 53 | \code{\link{fq_zip_strata}}, 54 | \code{\link{fq_zip_taxa}}, 55 | \code{\link{fs_v7}}, 56 | \code{\link{fs_v7_raw}}, 57 | \code{\link{geo_fs}}, 58 | \code{\link{geo_gj}}, 59 | \code{\link{geo_gj88}}, 60 | \code{\link{geo_gj_raw}}, 61 | \code{\link{geo_wkt}}, 62 | \code{\link{geo_wkt88}}, 63 | \code{\link{geo_wkt_raw}} 64 | } 65 | \concept{included} 66 | \keyword{datasets} 67 | -------------------------------------------------------------------------------- /man/yell_if_missing.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ru_setup.R 3 | \name{yell_if_missing} 4 | \alias{yell_if_missing} 5 | \title{Abort on missing ODK Central credentials (url, username, password).} 6 | \usage{ 7 | yell_if_missing( 8 | url, 9 | un, 10 | pw, 11 | pid = NULL, 12 | fid = NULL, 13 | iid = NULL, 14 | did = NULL, 15 | eid = NULL 16 | ) 17 | } 18 | \arguments{ 19 | \item{url}{A URL (character)} 20 | 21 | \item{un}{A username (character)} 22 | 23 | \item{pw}{A password (character)} 24 | 25 | \item{pid}{A project ID (numeric, optional)} 26 | 27 | \item{fid}{A form ID (character, optional)} 28 | 29 | \item{iid}{A submission instance ID (character, optional)} 30 | 31 | \item{did}{An Entity List (dataset) name (character, optional)} 32 | 33 | \item{eid}{An Entity UUID (character, optional)} 34 | } 35 | \description{ 36 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 37 | } 38 | \details{ 39 | This is a helper function to pat down \code{\link{ruODK}} functions 40 | for missing credentials and stop with a loud but informative yell. 41 | } 42 | \examples{ 43 | testthat::expect_error(yell_if_missing("", "username", "password")) 44 | testthat::expect_error(yell_if_missing("url", "", "password")) 45 | testthat::expect_error(yell_if_missing("url", "username", "")) 46 | testthat::expect_error(yell_if_missing(NULL, "", "")) 47 | testthat::expect_error(yell_if_missing("", "", "")) 48 | testthat::expect_error(yell_if_missing("", "", "", "")) 49 | testthat::expect_error(yell_if_missing("", "", "", "", "")) 50 | testthat::expect_error(yell_if_missing("", "", "", "", "", "")) 51 | testthat::expect_error(yell_if_missing("", "", "", "", "", "", "")) 52 | testthat::expect_error(yell_if_missing("", "", "", "", "", "", "", "")) 53 | } 54 | \seealso{ 55 | Other ru_settings: 56 | \code{\link{odata_svc_parse}()}, 57 | \code{\link{parse_odkc_version}()}, 58 | \code{\link{ru_settings}()}, 59 | \code{\link{ru_setup}()}, 60 | \code{\link{semver_gt}()}, 61 | \code{\link{semver_lt}()}, 62 | \code{\link{yell_if_error}()} 63 | } 64 | \concept{ru_settings} 65 | \keyword{internal} 66 | -------------------------------------------------------------------------------- /tests/testthat/test-form_schema_parse.R: -------------------------------------------------------------------------------- 1 | test_that("predict_ruodk_name works", { 2 | testthat::expect_equal( 3 | predict_ruodk_name("bar", "Submissions.foo"), 4 | "foo_bar" 5 | ) 6 | 7 | testthat::expect_equal( 8 | predict_ruodk_name("bar", "Submissions"), 9 | "bar" 10 | ) 11 | 12 | testthat::expect_equal( 13 | predict_ruodk_name("rock", "Submissions.foo_fighters"), 14 | "foo_fighters_rock" 15 | ) 16 | }) 17 | 18 | # nolint start 19 | # This test is retired, as the current test server runs at v1.4+ 20 | # test_that("form_schema works with ODK Central v0.8", { 21 | # skip_if(Sys.getenv("ODKC_TEST_URL") == "", 22 | # message = "Test server not configured" 23 | # ) 24 | # fs <- form_schema( 25 | # flatten = FALSE, 26 | # parse = FALSE, 27 | # odata = FALSE, 28 | # pid = get_test_pid(), 29 | # fid = get_test_fid(), 30 | # url = get_test_url(), 31 | # un = get_test_un(), 32 | # pw = get_test_pw(), 33 | # odkc_version = get_test_odkc_version(), 34 | # verbose = TRUE 35 | # ) 36 | # testthat::expect_true(tibble::is_tibble(fs)) 37 | # testthat::expect_equal( 38 | # names(fs), 39 | # c("path", "name", "type", "binary", "ruodk_name") 40 | # ) 41 | # testthat::expect_true("encounter_start_datetime" %in% fs$name) 42 | # testthat::expect_true("quadrat_photo" %in% fs$name) 43 | # # # Attachments 44 | # # fsp %>% dplyr::filter(type=="binary") 45 | # # 46 | # # # dateYime 47 | # # fsp %>% dplyr::filter(type=="dateTime") 48 | # # 49 | # # # Point location 50 | # # fsp %>% dplyr::filter(type=="geopoint") 51 | # }) 52 | # nolint end 53 | 54 | test_that("form_schema_parse debug messages work", { 55 | data("fs_v7_raw") 56 | data("fs_v7") 57 | 58 | testthat::capture_output( 59 | testthat::expect_message( 60 | fs_v7_parsed <- form_schema_parse(fs_v7_raw, verbose = TRUE) 61 | ) 62 | ) 63 | 64 | testthat::expect_equal(class(fs_v7_parsed), c("tbl_df", "tbl", "data.frame")) 65 | testthat::expect_true("observation_start_time" %in% fs_v7_parsed$name) 66 | testthat::expect_true("disturbance_cause" %in% fs_v7_parsed$name) 67 | 68 | testthat::expect_equal(fs_v7, fs_v7_parsed) 69 | }) 70 | -------------------------------------------------------------------------------- /tests/testthat/test-user_list.R: -------------------------------------------------------------------------------- 1 | test_that("user_list returns list of users", { 2 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 3 | message = "Test server not configured" 4 | ) 5 | ul <- user_list( 6 | url = get_test_url(), 7 | un = get_test_un(), 8 | pw = get_test_pw() 9 | ) 10 | testthat::expect_s3_class(ul, "tbl_df") 11 | 12 | cn <- c( 13 | "id", 14 | "type", 15 | "display_name", 16 | "created_at", 17 | "email", 18 | "updated_at" 19 | ) 20 | 21 | purrr::map( 22 | cn, 23 | ~ testthat::expect_true( 24 | . %in% names(ul), 25 | label = glue::glue("Column {.} missing from user_list") 26 | ) 27 | ) 28 | }) 29 | 30 | test_that("user_list returns filtered list of users", { 31 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 32 | message = "Test server not configured" 33 | ) 34 | 35 | # Use the first user's name to generate search strings 36 | ul <- user_list( 37 | url = get_test_url(), 38 | un = get_test_un(), 39 | pw = get_test_pw() 40 | ) 41 | ss3 <- substr(ul$display_name[[1]], 1, 3) # too short 42 | ss5 <- substr(ul$display_name[[1]], 1, 5) # long enough 43 | 44 | # Concerningly short search strings will emit a warning only if verbose 45 | testthat::expect_message( 46 | # reason: provided query string 47 | testthat::expect_warning( 48 | # reason: query string too short 49 | ul_flt3 <- user_list( 50 | url = get_test_url(), 51 | un = get_test_un(), 52 | pw = get_test_pw(), 53 | qry = ss3, 54 | verbose = TRUE 55 | ) 56 | ) 57 | ) 58 | 59 | # No warning here 60 | ul_flt3 <- user_list( 61 | url = get_test_url(), 62 | un = get_test_un(), 63 | pw = get_test_pw(), 64 | qry = ss3, 65 | verbose = FALSE 66 | ) 67 | ul_flt5 <- user_list( 68 | url = get_test_url(), 69 | un = get_test_un(), 70 | pw = get_test_pw(), 71 | qry = ss5 72 | ) 73 | 74 | testthat::expect_gte( 75 | nrow(ul_flt3), 76 | 0, 77 | label = "Short search strings (3 char) should return no matches" 78 | ) 79 | 80 | testthat::expect_gte( 81 | nrow(ul_flt5), 82 | 1, 83 | label = "Sufficiently long search strings (5 char) should return matches" 84 | ) 85 | }) 86 | 87 | # usethis::use_r("user_list") # nolint 88 | -------------------------------------------------------------------------------- /tests/testthat/test-entity_detail.R: -------------------------------------------------------------------------------- 1 | test_that("entity_detail works", { 2 | ru_setup( 3 | pid = get_test_pid(), 4 | url = get_test_url(), 5 | un = get_test_un(), 6 | pw = get_test_pw(), 7 | odkc_version = get_test_odkc_version() 8 | ) 9 | 10 | el <- entitylist_list() 11 | 12 | # Entity List name (dataset ID) 13 | did <- el$name[1] 14 | 15 | # All Entities of Entity List 16 | en <- entity_list(did = el$name[1]) 17 | 18 | # Entity detail 19 | ed <- entity_detail(did = el$name[1], eid = en$uuid[1]) 20 | 21 | cn <- c( 22 | "uuid", 23 | "creator_id", 24 | "conflict", 25 | "created_at", 26 | "updated_at", 27 | "deleted_at", 28 | "current_version" 29 | # not unfolded: 30 | # "current_version_created_at", 31 | # "current_version_current", 32 | # "current_version_label", 33 | # "current_version_creator_id", 34 | # "current_version_user_agent", 35 | # "current_version_version", 36 | # "current_version_base_version", 37 | # "current_version_conflicting_properties" 38 | ) 39 | testthat::expect_equal(cn, names(ed)) 40 | 41 | # The UUID of the first Entity 42 | eid <- en$uuid[1] 43 | testthat::expect_is(eid, "character") 44 | 45 | # The current version of the first Entity 46 | ev <- en$current_version_version[1] 47 | testthat::expect_is(ev, "integer") 48 | }) 49 | 50 | test_that("entity_detail errors if did is missing", { 51 | testthat::expect_error( 52 | entity_detail() 53 | ) 54 | }) 55 | 56 | test_that("entity_detail warns if odkc_version too low", { 57 | skip_if(Sys.getenv("ODKC_TEST_URL") == "", 58 | message = "Test server not configured" 59 | ) 60 | 61 | ru_setup( 62 | pid = get_test_pid(), 63 | url = get_test_url(), 64 | un = get_test_un(), 65 | pw = get_test_pw(), 66 | odkc_version = get_test_odkc_version() 67 | ) 68 | 69 | el <- entitylist_list() 70 | 71 | # Entity List name (dataset ID) 72 | did <- el$name[1] 73 | 74 | # All Entities of Entity List 75 | en <- entity_list(did = el$name[1]) 76 | 77 | # Entity detail 78 | ed <- entity_detail(did = el$name[1], eid = en$uuid[1]) 79 | 80 | # Expect error with missing eid 81 | testthat::expect_error( 82 | entity_detail(did = el$name[1]) 83 | ) 84 | }) 85 | 86 | 87 | # usethis::use_r("entity_detail") # nolint 88 | -------------------------------------------------------------------------------- /man/fq_raw_taxa.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_raw_taxa} 5 | \alias{fq_raw_taxa} 6 | \title{OData submission data for a subgroup of an ODK Central form.} 7 | \format{ 8 | A list of lists 9 | } 10 | \source{ 11 | See \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 12 | } 13 | \usage{ 14 | fq_raw_taxa 15 | } 16 | \description{ 17 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 18 | } 19 | \details{ 20 | The OData response for a subgroup of an ODK Central form. 21 | 22 | This subgroup represents an individual plant taxon which is encountered by 23 | the enumerators. Typically, one voucher specimen is taken for each distinct 24 | encountered plant taxon. A field name is allocated by the enumerators, which 25 | can be the proper canonical name (if known) or any other moniker. 26 | The voucher specimens are later determined by taxonomic experts, who then 27 | provide the real, terminal taxonomic name for a given voucher specimen. 28 | 29 | This data is kept up to date with the data used in vignettes and package 30 | tests. The data is comprised of test records with nonsensical data. 31 | The forms used to capture this data are development versions of real-world 32 | forms. 33 | } 34 | \seealso{ 35 | Other included: 36 | \code{\link{fq_attachments}}, 37 | \code{\link{fq_data}}, 38 | \code{\link{fq_data_strata}}, 39 | \code{\link{fq_data_taxa}}, 40 | \code{\link{fq_form_detail}}, 41 | \code{\link{fq_form_list}}, 42 | \code{\link{fq_form_schema}}, 43 | \code{\link{fq_form_xml}}, 44 | \code{\link{fq_meta}}, 45 | \code{\link{fq_project_detail}}, 46 | \code{\link{fq_project_list}}, 47 | \code{\link{fq_raw}}, 48 | \code{\link{fq_raw_strata}}, 49 | \code{\link{fq_submission_list}}, 50 | \code{\link{fq_submissions}}, 51 | \code{\link{fq_svc}}, 52 | \code{\link{fq_zip_data}}, 53 | \code{\link{fq_zip_strata}}, 54 | \code{\link{fq_zip_taxa}}, 55 | \code{\link{fs_v7}}, 56 | \code{\link{fs_v7_raw}}, 57 | \code{\link{geo_fs}}, 58 | \code{\link{geo_gj}}, 59 | \code{\link{geo_gj88}}, 60 | \code{\link{geo_gj_raw}}, 61 | \code{\link{geo_wkt}}, 62 | \code{\link{geo_wkt88}}, 63 | \code{\link{geo_wkt_raw}} 64 | } 65 | \concept{included} 66 | \keyword{datasets} 67 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ubuntu-latest 14 | environment: ci 15 | env: 16 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 17 | R_KEEP_PKG_SOURCE: yes 18 | ODKC_TEST_URL: ${{ secrets.ODKC_TEST_URL }} 19 | ODKC_TEST_SVC: ${{ secrets.ODKC_TEST_SVC }} 20 | ODKC_TEST_PID: ${{ secrets.ODKC_TEST_PID }} 21 | ODKC_TEST_PID_ENC: ${{ secrets.ODKC_TEST_PID_ENC }} 22 | ODKC_TEST_PP: ${{ secrets.ODKC_TEST_PP }} 23 | ODKC_TEST_FID: ${{ secrets.ODKC_TEST_FID }} 24 | ODKC_TEST_FID_ZIP: ${{ secrets.ODKC_TEST_FID_ZIP }} 25 | ODKC_TEST_FID_ATT: ${{ secrets.ODKC_TEST_FID_ATT }} 26 | ODKC_TEST_FID_GAP: ${{ secrets.ODKC_TEST_FID_GAP }} 27 | ODKC_TEST_FID_WKT: ${{ secrets.ODKC_TEST_FID_WKT }} 28 | ODKC_TEST_FID_I8N0: ${{ secrets.ODKC_TEST_FID_I8N0 }} 29 | ODKC_TEST_FID_I8N1: ${{ secrets.ODKC_TEST_FID_I8N1 }} 30 | ODKC_TEST_FID_I8N2: ${{ secrets.ODKC_TEST_FID_I8N2 }} 31 | ODKC_TEST_FID_ENC: ${{ secrets.ODKC_TEST_FID_ENC }} 32 | ODKC_TEST_VERSION: ${{ secrets.ODKC_TEST_VERSION }} 33 | RU_VERBOSE: ${{ secrets.RU_VERBOSE }} 34 | RU_TIMEZONE: ${{ secrets.RU_TIMEZONE }} 35 | RU_RETRIES: ${{ secrets.RU_RETRIES }} 36 | ODKC_TEST_UN: ${{ secrets.ODKC_TEST_UN }} 37 | ODKC_TEST_PW: ${{ secrets.ODKC_TEST_PW }} 38 | ODKC_URL: ${{ secrets.ODKC_TEST_URL }} 39 | ODKC_UN: ${{ secrets.ODKC_TEST_UN }} 40 | ODKC_PW: ${{ secrets.ODKC_TEST_PW }} 41 | ODKC_PP: ${{ secrets.ODKC_TEST_PP }} 42 | ODKC_VERSION: ${{ secrets.ODKC_TEST_VERSION }} 43 | 44 | steps: 45 | - uses: actions/checkout@v4 46 | 47 | - uses: r-lib/actions/setup-r@v2 48 | with: 49 | use-public-rspm: true 50 | 51 | - uses: r-lib/actions/setup-r-dependencies@v2 52 | with: 53 | extra-packages: any::rcmdcheck 54 | needs: check 55 | 56 | - uses: r-lib/actions/check-r-package@v2 57 | with: 58 | upload-snapshots: true 59 | build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' 60 | -------------------------------------------------------------------------------- /man/fq_data_strata.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_data_strata} 5 | \alias{fq_data_strata} 6 | \title{Parsed submission data for a subgroup of an ODK Central form.} 7 | \format{ 8 | The output of \code{\link{odata_submission_get}} for a set of example 9 | data. A tidy tibble referencing the attachments included in the vignettes 10 | and documentation at a relative path \verb{attachments/media/.}. 11 | } 12 | \source{ 13 | See \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 14 | and \code{\link{odata_submission_get}}. 15 | } 16 | \usage{ 17 | fq_data_strata 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \details{ 23 | The parsed OData response for the subgroup of an ODK Central form. 24 | 25 | This subgroup represents vegetation strata as per the NVIS classification. 26 | A vegetation stratum is a layer of plants with the same height, and dominated 27 | by one or few plant taxa. Plant communities can be made of up to five strata, 28 | with two to three being most common. 29 | 30 | This data is kept up to date with the data used in vignettes and package 31 | tests. The data is comprised of test records with nonsensical data. 32 | The forms used to capture this data are development versions of real-world 33 | forms. 34 | } 35 | \seealso{ 36 | Other included: 37 | \code{\link{fq_attachments}}, 38 | \code{\link{fq_data}}, 39 | \code{\link{fq_data_taxa}}, 40 | \code{\link{fq_form_detail}}, 41 | \code{\link{fq_form_list}}, 42 | \code{\link{fq_form_schema}}, 43 | \code{\link{fq_form_xml}}, 44 | \code{\link{fq_meta}}, 45 | \code{\link{fq_project_detail}}, 46 | \code{\link{fq_project_list}}, 47 | \code{\link{fq_raw}}, 48 | \code{\link{fq_raw_strata}}, 49 | \code{\link{fq_raw_taxa}}, 50 | \code{\link{fq_submission_list}}, 51 | \code{\link{fq_submissions}}, 52 | \code{\link{fq_svc}}, 53 | \code{\link{fq_zip_data}}, 54 | \code{\link{fq_zip_strata}}, 55 | \code{\link{fq_zip_taxa}}, 56 | \code{\link{fs_v7}}, 57 | \code{\link{fs_v7_raw}}, 58 | \code{\link{geo_fs}}, 59 | \code{\link{geo_gj}}, 60 | \code{\link{geo_gj88}}, 61 | \code{\link{geo_gj_raw}}, 62 | \code{\link{geo_wkt}}, 63 | \code{\link{geo_wkt88}}, 64 | \code{\link{geo_wkt_raw}} 65 | } 66 | \concept{included} 67 | \keyword{datasets} 68 | -------------------------------------------------------------------------------- /man/fq_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_data} 5 | \alias{fq_data} 6 | \title{Parsed submission data for an ODK Central form.} 7 | \format{ 8 | The output of \code{\link{odata_submission_get}} for a set of example 9 | data. A tidy tibble referencing the attachments included in the vignettes 10 | and documentation at a relative path \verb{attachments/media/.}. 11 | } 12 | \source{ 13 | See \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 14 | and \code{\link{odata_submission_get}}. 15 | } 16 | \usage{ 17 | fq_data 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \details{ 23 | The parsed OData response for the submissions of an ODK Central form. 24 | This form represents a Flora Quadrat, which is a ca 50 by 50 m quadrat of 25 | a uniform plant community. 26 | 27 | The XML and .odkbuild versions for this form are available as 28 | \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 29 | and \code{system.file("extdata", "FloraQuadrat04.odkbuild", package = "ruODK")}, 30 | respectively. 31 | 32 | This data is kept up to date with the data used in vignettes and package 33 | tests. The data is comprised of test records with nonsensical data. 34 | The forms used to capture this data are development versions of real-world 35 | forms. 36 | } 37 | \seealso{ 38 | Other included: 39 | \code{\link{fq_attachments}}, 40 | \code{\link{fq_data_strata}}, 41 | \code{\link{fq_data_taxa}}, 42 | \code{\link{fq_form_detail}}, 43 | \code{\link{fq_form_list}}, 44 | \code{\link{fq_form_schema}}, 45 | \code{\link{fq_form_xml}}, 46 | \code{\link{fq_meta}}, 47 | \code{\link{fq_project_detail}}, 48 | \code{\link{fq_project_list}}, 49 | \code{\link{fq_raw}}, 50 | \code{\link{fq_raw_strata}}, 51 | \code{\link{fq_raw_taxa}}, 52 | \code{\link{fq_submission_list}}, 53 | \code{\link{fq_submissions}}, 54 | \code{\link{fq_svc}}, 55 | \code{\link{fq_zip_data}}, 56 | \code{\link{fq_zip_strata}}, 57 | \code{\link{fq_zip_taxa}}, 58 | \code{\link{fs_v7}}, 59 | \code{\link{fs_v7_raw}}, 60 | \code{\link{geo_fs}}, 61 | \code{\link{geo_gj}}, 62 | \code{\link{geo_gj88}}, 63 | \code{\link{geo_gj_raw}}, 64 | \code{\link{geo_wkt}}, 65 | \code{\link{geo_wkt88}}, 66 | \code{\link{geo_wkt_raw}} 67 | } 68 | \concept{included} 69 | \keyword{datasets} 70 | -------------------------------------------------------------------------------- /R/drop_null_coords.R: -------------------------------------------------------------------------------- 1 | #' Drop any NULL coordinates from a GeoJSON geometry. 2 | #' 3 | #' This helper patches a bug/feature in ODK Central (versions 0.7-0.9), where 4 | #' geotrace / geoshape GeoJSON contains a last coordinate pair with NULL 5 | #' lat/lon (no alt/acc), and WKT ends in `, undefined NaN`. 6 | #' 7 | #' While \code{\link{split_geotrace}} and \code{\link{split_geoshape}} modify 8 | #' the WKT inline, it is more maintainable to separate the GeoJSON cleaner 9 | #' into this function. 10 | #' 11 | #' This helper drops the last element of a GeoJSON coordinate list if it is 12 | #' `list(NULL, NULL)`. 13 | #' 14 | #' @param x A GeoJSON geometry parsed as nested list. 15 | #' E.g. `geo_gj$path_location_path_gps`. 16 | #' @return The nested list minus the last element (if NULL). 17 | #' @family utilities 18 | #' @export 19 | #' @examples 20 | #' # A snapshot of geo data with trailing empty coordinates. 21 | #' data("geo_gj88") 22 | #' 23 | #' len_coords <- length(geo_gj88$path_location_path_gps[[1]]$coordinates) 24 | #' 25 | #' length(geo_gj88$path_location_path_gps[[1]]$coordinates[[len_coords]]) %>% 26 | #' testthat::expect_equal(2) 27 | #' 28 | #' geo_gj88$path_location_path_gps[[1]]$coordinates[[len_coords]][[1]] %>% 29 | #' testthat::expect_null() 30 | #' 31 | #' geo_gj88$path_location_path_gps[[1]]$coordinates[[len_coords]][[2]] %>% 32 | #' testthat::expect_null() 33 | #' 34 | #' # The last coordinate pair is a list(NULL, NULL). 35 | #' # Invalid coordinates like these are a choking hazard for geospatial 36 | #' # packages. We should remove them before we can convert ODK data into native 37 | #' # spatial formats, such as sf. 38 | #' str(geo_gj88$path_location_path_gps[[1]]$coordinates[[len_coords]]) 39 | #' 40 | #' geo_gj_repaired <- geo_gj88 %>% 41 | #' dplyr::mutate( 42 | #' path_location_path_gps = path_location_path_gps %>% 43 | #' purrr::map(drop_null_coords) 44 | #' ) 45 | #' 46 | #' len_coords_repaired <- length( 47 | #' geo_gj_repaired$path_location_path_gps[[1]]$coordinates 48 | #' ) 49 | #' testthat::expect_equal(len_coords_repaired + 1, len_coords) 50 | drop_null_coords <- function(x) { 51 | # Extract and simplify last coords. list(NULL, NULL) becomes list(). 52 | xx <- purrr::compact(x$coordinates[[length(x$coordinates)]]) 53 | # Remove empty coords by setting the entire list(NULL, NULL) to NULL. 54 | if (is.list(xx) && length(xx) == 0) { 55 | x$coordinates[[length(x$coordinates)]] <- NULL 56 | } 57 | x 58 | } 59 | 60 | # usethis::use_test("drop_null_coords") # nolint 61 | -------------------------------------------------------------------------------- /man/isodt_to_local.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/isodt_to_local.R 3 | \name{isodt_to_local} 4 | \alias{isodt_to_local} 5 | \title{Parse an ISO8601 datetime string to a timezone aware datetime.} 6 | \usage{ 7 | isodt_to_local( 8 | datetime_string, 9 | orders = c("YmdHMS", "YmdHMSz"), 10 | tz = get_default_tz(), 11 | quiet = TRUE 12 | ) 13 | } 14 | \arguments{ 15 | \item{datetime_string}{(character) An ISO8601 datetime string as produced by 16 | XForms exported from ODK Central.} 17 | 18 | \item{orders}{(vector of character) Orders of datetime elements for 19 | \code{lubridate}. 20 | Default: \code{c("YmdHMS", "YmdHMSz", "Ymd HMS", "Ymd HMSz")}.} 21 | 22 | \item{tz}{A timezone to convert dates and times to. 23 | 24 | Read \code{vignette("setup", package = "ruODK")} to learn how \code{ruODK}'s 25 | timezone can be set globally or per function.} 26 | 27 | \item{quiet}{(lgl) Used in \code{lubridate::parse_date_time(quiet=quiet)} to 28 | suppress warnings from attempting to parse all empty values or columns. 29 | Run with \code{quiet=FALSE} to show any \code{lubridate} warnings.} 30 | } 31 | \value{ 32 | A \code{lubridate} PosixCT datetime in the given timezone. 33 | } 34 | \description{ 35 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 36 | } 37 | \details{ 38 | This function is used internally by \code{ruODK} to parse ISO timestamps 39 | to timezone-aware local times. 40 | 41 | Warnings are suppressed through \code{lubridate::parse_date_time(quiet=TRUE)}. 42 | } 43 | \seealso{ 44 | Other utilities: 45 | \code{\link{attachment_get}()}, 46 | \code{\link{attachment_link}()}, 47 | \code{\link{attachment_url}()}, 48 | \code{\link{drop_null_coords}()}, 49 | \code{\link{form_schema_parse}()}, 50 | \code{\link{get_one_attachment}()}, 51 | \code{\link{get_one_submission}()}, 52 | \code{\link{get_one_submission_att_list}()}, 53 | \code{\link{get_one_submission_audit}()}, 54 | \code{\link{handle_ru_attachments}()}, 55 | \code{\link{handle_ru_datetimes}()}, 56 | \code{\link{handle_ru_geopoints}()}, 57 | \code{\link{handle_ru_geoshapes}()}, 58 | \code{\link{handle_ru_geotraces}()}, 59 | \code{\link{odata_submission_rectangle}()}, 60 | \code{\link{predict_ruodk_name}()}, 61 | \code{\link{prepend_uuid}()}, 62 | \code{\link{split_geopoint}()}, 63 | \code{\link{split_geoshape}()}, 64 | \code{\link{split_geotrace}()}, 65 | \code{\link{strip_uuid}()}, 66 | \code{\link{tidyeval}}, 67 | \code{\link{unnest_all}()} 68 | } 69 | \concept{utilities} 70 | \keyword{internal} 71 | -------------------------------------------------------------------------------- /man/odata_service_get.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/odata_service_get.R 3 | \name{odata_service_get} 4 | \alias{odata_service_get} 5 | \title{Retrieve service metadata from an OData URL ending in .svc as tibble.} 6 | \usage{ 7 | odata_service_get( 8 | pid = get_default_pid(), 9 | fid = get_default_fid(), 10 | url = get_default_url(), 11 | un = get_default_un(), 12 | pw = get_default_pw(), 13 | retries = get_retries() 14 | ) 15 | } 16 | \arguments{ 17 | \item{pid}{The numeric ID of the project, e.g.: 2. 18 | 19 | Default: \code{\link{get_default_pid}}. 20 | 21 | Set default \code{pid} through \code{ru_setup(pid="...")}. 22 | 23 | See \code{vignette("Setup", package = "ruODK")}.} 24 | 25 | \item{fid}{The alphanumeric form ID, e.g. "build_Spotlighting-0-8_1559885147". 26 | 27 | Default: \code{\link{get_default_fid}}. 28 | 29 | Set default \code{fid} through \code{ru_setup(fid="...")}. 30 | 31 | See \code{vignette("Setup", package = "ruODK")}.} 32 | 33 | \item{url}{The ODK Central base URL without trailing slash. 34 | 35 | Default: \code{\link{get_default_url}}. 36 | 37 | Set default \code{url} through \code{ru_setup(url="...")}. 38 | 39 | See \code{vignette("Setup", package = "ruODK")}.} 40 | 41 | \item{un}{The ODK Central username (an email address). 42 | Default: \code{\link{get_default_un}}. 43 | Set default \code{un} through \code{ru_setup(un="...")}. 44 | See \code{vignette("Setup", package = "ruODK")}.} 45 | 46 | \item{pw}{The ODK Central password. 47 | Default: \code{\link{get_default_pw}}. 48 | Set default \code{pw} through \code{ru_setup(pw="...")}. 49 | See \code{vignette("Setup", package = "ruODK")}.} 50 | 51 | \item{retries}{The number of attempts to retrieve a web resource. 52 | 53 | This parameter is given to \code{\link[httr]{RETRY}(times = retries)}. 54 | 55 | Default: 3.} 56 | } 57 | \value{ 58 | A tibble with one row per submission data endpoint. 59 | Columns: name, kind, url. 60 | } 61 | \description{ 62 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 63 | } 64 | \examples{ 65 | \dontrun{ 66 | # See vignette("setup") for setup and authentication options 67 | # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 68 | 69 | svc <- odata_service_get() 70 | svc 71 | } 72 | } 73 | \seealso{ 74 | \url{https://docs.getodk.org/central-api-odata-endpoints/#service-document} 75 | 76 | Other odata-api: 77 | \code{\link{odata_metadata_get}()}, 78 | \code{\link{odata_submission_get}()} 79 | } 80 | \concept{odata-api} 81 | -------------------------------------------------------------------------------- /man/fq_data_taxa.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data.R 3 | \docType{data} 4 | \name{fq_data_taxa} 5 | \alias{fq_data_taxa} 6 | \title{Parsed submission data for a subgroup of an ODK Central form.} 7 | \format{ 8 | The output of \code{\link{odata_submission_get}} for a set of example 9 | data. A tidy tibble referencing the attachments included in the vignettes 10 | and documentation at a relative path \verb{attachments/media/.}. 11 | } 12 | \source{ 13 | See \code{system.file("extdata", "FloraQuadrat04.xml", package = "ruODK")} 14 | and \code{\link{odata_submission_get}}. 15 | } 16 | \usage{ 17 | fq_data_taxa 18 | } 19 | \description{ 20 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 21 | } 22 | \details{ 23 | The parsed OData response for a subgroup of an ODK Central form. 24 | 25 | This subgroup represents an individual plant taxon which is encountered by 26 | the enumerators. Typically, one voucher specimen is taken for each distinct 27 | encountered plant taxon. A field name is allocated by the enumerators, which 28 | can be the proper canonical name (if known) or any other moniker. 29 | The voucher specimens are later determined by taxonomic experts, who then 30 | provide the real, terminal taxonomic name for a given voucher specimen. 31 | 32 | This data is kept up to date with the data used in vignettes and package 33 | tests. The data is comprised of test records with nonsensical data. 34 | The forms used to capture this data are development versions of real-world 35 | forms. 36 | } 37 | \seealso{ 38 | Other included: 39 | \code{\link{fq_attachments}}, 40 | \code{\link{fq_data}}, 41 | \code{\link{fq_data_strata}}, 42 | \code{\link{fq_form_detail}}, 43 | \code{\link{fq_form_list}}, 44 | \code{\link{fq_form_schema}}, 45 | \code{\link{fq_form_xml}}, 46 | \code{\link{fq_meta}}, 47 | \code{\link{fq_project_detail}}, 48 | \code{\link{fq_project_list}}, 49 | \code{\link{fq_raw}}, 50 | \code{\link{fq_raw_strata}}, 51 | \code{\link{fq_raw_taxa}}, 52 | \code{\link{fq_submission_list}}, 53 | \code{\link{fq_submissions}}, 54 | \code{\link{fq_svc}}, 55 | \code{\link{fq_zip_data}}, 56 | \code{\link{fq_zip_strata}}, 57 | \code{\link{fq_zip_taxa}}, 58 | \code{\link{fs_v7}}, 59 | \code{\link{fs_v7_raw}}, 60 | \code{\link{geo_fs}}, 61 | \code{\link{geo_gj}}, 62 | \code{\link{geo_gj88}}, 63 | \code{\link{geo_gj_raw}}, 64 | \code{\link{geo_wkt}}, 65 | \code{\link{geo_wkt88}}, 66 | \code{\link{geo_wkt_raw}} 67 | } 68 | \concept{included} 69 | \keyword{datasets} 70 | -------------------------------------------------------------------------------- /R/entitylist_list.R: -------------------------------------------------------------------------------- 1 | #' List all Entity Lists of one Project. 2 | #' 3 | #' `r lifecycle::badge("maturing")` 4 | #' 5 | #' The returned list is useful to retrieve the valid name of an Entity List for 6 | #' further use by functions of the Entity Management family. 7 | #' 8 | #' @template tpl-def-entitylist 9 | #' @template tpl-entitylist-dataset 10 | #' @template tpl-auth-missing 11 | #' @template tpl-compat-2022-3 12 | #' @template param-pid 13 | #' @template param-url 14 | #' @template param-auth 15 | #' @template param-retries 16 | #' @template param-odkcv 17 | #' @template param-orders 18 | #' @template param-tz 19 | #' @return A tibble with exactly one row for each Entity List of the given 20 | #' Project as per ODK Central API docs. 21 | #' Column names are renamed from ODK Central's `camelCase` to `snake_case`. 22 | # nolint start 23 | #' @seealso \url{ https://docs.getodk.org/central-api-dataset-management/#datasets} 24 | # nolint end 25 | #' @family entity-management 26 | #' @export 27 | #' @examples 28 | #' \dontrun{ 29 | #' # See vignette("setup") for setup and authentication options 30 | #' # ruODK::ru_setup(svc = "... .svc", un = "me@email.com", pw = "...") 31 | #' 32 | #' ds <- entitylist_list(pid = get_default_pid()) 33 | #' 34 | #' ds |> knitr::kable() 35 | #' } 36 | entitylist_list <- function(pid = get_default_pid(), 37 | url = get_default_url(), 38 | un = get_default_un(), 39 | pw = get_default_pw(), 40 | retries = get_retries(), 41 | odkc_version = get_default_odkc_version(), 42 | orders = get_default_orders(), 43 | tz = get_default_tz()) { 44 | yell_if_missing(url, un, pw, pid = pid) 45 | 46 | if (odkc_version |> semver_lt("2022.3")) { 47 | ru_msg_warn("entitylist_list is supported from v2022.3") 48 | } 49 | 50 | httr::RETRY( 51 | "GET", 52 | httr::modify_url(url, path = glue::glue("v1/projects/{pid}/datasets")), 53 | httr::add_headers( 54 | "Accept" = "application/json", 55 | "X-Extended-Metadata" = "true" 56 | ), 57 | httr::authenticate(un, pw), 58 | times = retries 59 | ) |> 60 | yell_if_error(url, un, pw) |> 61 | httr::content(encoding = "utf-8") |> 62 | purrr::list_transpose() |> 63 | tibble::as_tibble() |> 64 | janitor::clean_names() |> 65 | dplyr::mutate_at( 66 | dplyr::vars(c("created_at", "last_entity")), 67 | ~ isodt_to_local(., orders = orders, tz = tz) 68 | ) 69 | } 70 | 71 | # usethis::use_test("entitylist_list") # nolint 72 | -------------------------------------------------------------------------------- /man/odata_metadata_get.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/odata_metadata_get.R 3 | \name{odata_metadata_get} 4 | \alias{odata_metadata_get} 5 | \title{Retrieve metadata from an OData URL ending in .svc as list of lists.} 6 | \usage{ 7 | odata_metadata_get( 8 | pid = get_default_pid(), 9 | fid = get_default_fid(), 10 | url = get_default_url(), 11 | un = get_default_un(), 12 | pw = get_default_pw(), 13 | retries = get_retries() 14 | ) 15 | } 16 | \arguments{ 17 | \item{pid}{The numeric ID of the project, e.g.: 2. 18 | 19 | Default: \code{\link{get_default_pid}}. 20 | 21 | Set default \code{pid} through \code{ru_setup(pid="...")}. 22 | 23 | See \code{vignette("Setup", package = "ruODK")}.} 24 | 25 | \item{fid}{The alphanumeric form ID, e.g. "build_Spotlighting-0-8_1559885147". 26 | 27 | Default: \code{\link{get_default_fid}}. 28 | 29 | Set default \code{fid} through \code{ru_setup(fid="...")}. 30 | 31 | See \code{vignette("Setup", package = "ruODK")}.} 32 | 33 | \item{url}{The ODK Central base URL without trailing slash. 34 | 35 | Default: \code{\link{get_default_url}}. 36 | 37 | Set default \code{url} through \code{ru_setup(url="...")}. 38 | 39 | See \code{vignette("Setup", package = "ruODK")}.} 40 | 41 | \item{un}{The ODK Central username (an email address). 42 | Default: \code{\link{get_default_un}}. 43 | Set default \code{un} through \code{ru_setup(un="...")}. 44 | See \code{vignette("Setup", package = "ruODK")}.} 45 | 46 | \item{pw}{The ODK Central password. 47 | Default: \code{\link{get_default_pw}}. 48 | Set default \code{pw} through \code{ru_setup(pw="...")}. 49 | See \code{vignette("Setup", package = "ruODK")}.} 50 | 51 | \item{retries}{The number of attempts to retrieve a web resource. 52 | 53 | This parameter is given to \code{\link[httr]{RETRY}(times = retries)}. 54 | 55 | Default: 3.} 56 | } 57 | \value{ 58 | A nested list containing Edmx (dataset schema definition) and 59 | .attrs (Version). 60 | } 61 | \description{ 62 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#stable}{\figure{lifecycle-stable.svg}{options: alt='[Stable]'}}}{\strong{[Stable]}} 63 | } 64 | \examples{ 65 | \dontrun{ 66 | # See vignette("setup") for setup and authentication options 67 | # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 68 | 69 | meta <- odata_metadata_get() 70 | listviewer::jsonedit(meta) 71 | } 72 | } 73 | \seealso{ 74 | \url{https://docs.getodk.org/central-api-odata-endpoints/#metadata-document} 75 | 76 | Other odata-api: 77 | \code{\link{odata_service_get}()}, 78 | \code{\link{odata_submission_get}()} 79 | } 80 | \concept{odata-api} 81 | -------------------------------------------------------------------------------- /R/project_detail.R: -------------------------------------------------------------------------------- 1 | #' List all details of one project. 2 | #' 3 | #' While the API endpoint will return all details for one project, 4 | #' \code{\link{project_detail}} will fail with incorrect or missing 5 | #' authentication. 6 | #' 7 | #' `r lifecycle::badge("stable")` 8 | #' 9 | #' @template param-pid 10 | #' @template param-url 11 | #' @template param-auth 12 | #' @template param-retries 13 | #' @return A tibble with exactly one row for the project and all project 14 | #' metadata as columns as per ODK Central API docs. 15 | #' Column names are renamed from ODK's `camelCase` to `snake_case`. 16 | #' Values differ to values returned by ODK Central API: 17 | #' 18 | #' * archived: FALSE (if NULL) else TRUE 19 | #' * dates: NA if NULL 20 | # nolint start 21 | #' @seealso \url{https://docs.getodk.org/central-api-project-management/#getting-project-details} 22 | # nolint end 23 | #' @family project-management 24 | #' @export 25 | #' @examples 26 | #' \dontrun{ 27 | #' # See vignette("setup") for setup and authentication options 28 | #' # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 29 | #' 30 | #' pd <- project_detail() 31 | #' 32 | #' pd %>% 33 | #' dplyr::select(-"verbs") %>% 34 | #' knitr::kable(.) 35 | #' } 36 | project_detail <- function(pid = get_default_pid(), 37 | url = get_default_url(), 38 | un = get_default_un(), 39 | pw = get_default_pw(), 40 | retries = get_retries()) { 41 | yell_if_missing(url, un, pw, pid = pid) 42 | httr::RETRY( 43 | "GET", 44 | httr::modify_url(url, path = glue::glue("v1/projects/{pid}")), 45 | httr::add_headers( 46 | "Accept" = "application/xml", 47 | "X-Extended-Metadata" = "true" 48 | ), 49 | httr::authenticate(un, pw), 50 | times = retries 51 | ) |> 52 | yell_if_error(url, un, pw) |> 53 | httr::content() %>% 54 | { # nolint 55 | tibble::tibble( 56 | id = .$id, 57 | name = .$name, 58 | forms = .$forms, 59 | app_users = .$appUsers, 60 | last_submission = ifelse( 61 | is.null(.$lastSubmission), 62 | NA_character_, 63 | .$lastSubmission 64 | ), 65 | created_at = .$createdAt, 66 | updated_at = ifelse( 67 | is.null(.$updatedAt), 68 | NA_character_, 69 | .$updatedAt 70 | ), 71 | archived = ifelse( 72 | is.null(.$archived), 73 | FALSE, 74 | TRUE 75 | ), 76 | verbs = list(.$verbs) 77 | ) 78 | } 79 | } 80 | 81 | # usethis::use_test("project_detail") # nolint 82 | -------------------------------------------------------------------------------- /R/project_list.R: -------------------------------------------------------------------------------- 1 | #' List all projects. 2 | #' 3 | #' 4 | #' While the API endpoint will return all projects, 5 | #' \code{\link{project_list}} will fail with incorrect or missing 6 | #' authentication. 7 | #' 8 | #' `r lifecycle::badge("stable")` 9 | #' 10 | #' @template param-url 11 | #' @template param-auth 12 | #' @template param-retries 13 | #' @template param-orders 14 | #' @template param-tz 15 | #' @return A tibble with one row per project and all project metadata 16 | #' as columns as per ODK Central API docs. 17 | # nolint start 18 | #' @seealso \url{https://docs.getodk.org/central-api-project-management/#listing-projects} 19 | # nolint end 20 | #' @family project-management 21 | #' @export 22 | #' @examples 23 | #' \dontrun{ 24 | #' # See vignette("setup") for setup and authentication options 25 | #' # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 26 | #' 27 | #' pl <- project_list() 28 | #' knitr::kable(pl) 29 | #' 30 | #' # project_list returns a tibble 31 | #' class(pl) 32 | #' # > "tbl_df" "tbl" "data.frame" 33 | #' 34 | #' # columns are project metadata 35 | #' names(pl) 36 | #' # > "id" "name" "forms" "app_users" "created_at" "updated_at" 37 | #' # > "last_submission" "archived" 38 | #' } 39 | project_list <- function(url = get_default_url(), 40 | un = get_default_un(), 41 | pw = get_default_pw(), 42 | retries = get_retries(), 43 | orders = get_default_orders(), 44 | tz = get_default_tz()) { 45 | yell_if_missing(url, un, pw) 46 | httr::RETRY( 47 | "GET", 48 | httr::modify_url(url, path = glue::glue("v1/projects")), 49 | httr::add_headers( 50 | "Accept" = "application/xml", 51 | "X-Extended-Metadata" = "true" 52 | ), 53 | httr::authenticate(un, pw), 54 | times = retries 55 | ) %>% 56 | yell_if_error(., url, un, pw) %>% 57 | httr::content(.) %>% 58 | tibble::tibble(.) %>% 59 | tidyr::unnest_wider(".", names_repair = "universal") %>% 60 | # tidyr::unnest_wider( 61 | # "verbs", 62 | # names_repair = "universal", names_sep = "_" 63 | # ) %>% 64 | janitor::clean_names(.) %>% 65 | dplyr::mutate( 66 | dplyr::across( 67 | dplyr::contains("last_submission|created_at|updated_at|deleted_at"), 68 | ~ isodt_to_local(., orders = orders, tz = tz) 69 | ) 70 | ) %>% 71 | { 72 | if ("archived" %in% names(.)) { 73 | dplyr::mutate(., archived = tidyr::replace_na(archived, FALSE)) 74 | } else { 75 | . 76 | } 77 | } 78 | } 79 | 80 | # usethis::use_test("project_list") # nolint 81 | -------------------------------------------------------------------------------- /R/attachment_link.R: -------------------------------------------------------------------------------- 1 | #' Prefix attachment columns from CSV export with a local attachment file path. 2 | #' 3 | #' `r lifecycle::badge("stable")` 4 | #' 5 | #' @param data_tbl The downloaded submissions from 6 | #' \code{\link{submission_export}} read into a `tibble` by 7 | #' \code{readr::read_csv}. 8 | #' @param form_schema The `form_schema` for the submissions. 9 | #' E.g. the output of `ruODK::form_schema()`. 10 | #' @param att_path A local path, default: "media" (as per .csv.zip export). 11 | #' Selected columns of the dataframe (containing attchment filenames) are 12 | #' prefixed with `att_path`, thus turning them into relative paths. 13 | #' @return The dataframe with attachment columns modified to contain relative 14 | #' paths to the downloaded attachment files. 15 | #' @export 16 | #' @family utilities 17 | #' @examples 18 | #' \dontrun{ 19 | #' t <- tempdir() 20 | #' # See vignette("setup") for setup and authentication options 21 | #' # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 22 | #' 23 | #' # Predict filenames (with knowledge of form) 24 | #' fid <- get_default_fid() 25 | #' fid_csv <- fs::path(t, glue::glue("{fid}.csv")) 26 | #' fid_csv_tae <- fs::path(t, glue::glue("{fid}-taxon_encounter.csv")) 27 | #' fs <- form_schema() 28 | #' 29 | #' # Download the zip file 30 | #' se <- ruODK::submission_export( 31 | #' local_dir = t, 32 | #' overwrite = FALSE, 33 | #' verbose = TRUE 34 | #' ) 35 | #' 36 | #' # Unpack the zip file 37 | #' f <- unzip(se, exdir = t) 38 | #' fs::dir_ls(t) 39 | #' 40 | #' # Prepend attachments with media/ to turn into relative file paths 41 | #' data_quadrat <- fid_csv %>% 42 | #' readr::read_csv(na = c("", "NA", "na")) %>% 43 | #' janitor::clean_names() %>% 44 | #' handle_ru_datetimes(fs) %>% 45 | #' attachment_link(fs) 46 | #' } 47 | attachment_link <- function(data_tbl, 48 | form_schema, 49 | att_path = "media") { 50 | # Find attachment columns 51 | # Caveat: if an attachment field has no submissions, it is dropped from data 52 | att_cols <- form_schema %>% 53 | dplyr::filter(type == "binary") %>% 54 | magrittr::extract2("ruodk_name") %>% 55 | intersect(names(data_tbl)) 56 | 57 | data_tbl %>% 58 | dplyr::mutate_at( 59 | dplyr::vars(dplyr::all_of(att_cols)), 60 | ~ fs::path(att_path, .) 61 | ) 62 | } 63 | 64 | # nolint start 65 | # usethis::use_test("attachment_link") 66 | # usethis::use_test("submission_export") 67 | # covr::file_coverage("R/attachment_link.R", 68 | # test_files = c("tests/testthat/test-attachment_link.R", 69 | # "tests/testthat/test-submission_export.R")) 70 | # nolint end 71 | -------------------------------------------------------------------------------- /R/handle_ru_geopoints.R: -------------------------------------------------------------------------------- 1 | #' Split all geopoints of a submission tibble into their components. 2 | #' 3 | #' `r lifecycle::badge("stable")` 4 | #' 5 | #' @details For a given tibble of submissions, find all columns which are listed 6 | #' in the form schema as type \code{geopoint}, and extract their components. 7 | #' Extracted components are longitude (X), latitude (Y), altitude (Z, where 8 | #' given), and accuracy (M, where given). 9 | #' 10 | #' The original column is retained to allow parsing into other spatially 11 | #' enabled formats. 12 | #' @param data Submissions rectangled into a tibble. E.g. the output of 13 | #' ``` 14 | #' ruODK::odata_submission_get(parse = FALSE) %>% 15 | #' ruODK::odata_submission_rectangle() 16 | #' ``` 17 | #' @param form_schema The `form_schema` for the submissions. 18 | #' E.g. the output of `ruODK::form_schema()`. 19 | #' @template param-wkt 20 | #' @template param-verbose 21 | #' @return The submissions tibble with all geopoints retained in their original 22 | #' format, plus columns of their coordinate components as provided by 23 | #' \code{\link{split_geopoint}}. 24 | #' @export 25 | #' @family utilities 26 | #' @examples 27 | #' library(magrittr) 28 | #' data("geo_fs") 29 | #' data("geo_gj_raw") 30 | #' data("geo_wkt_raw") 31 | #' 32 | #' # GeoJSON 33 | #' geo_gj_parsed <- geo_gj_raw %>% 34 | #' ruODK::odata_submission_rectangle(form_schema = geo_fs) %>% 35 | #' ruODK::handle_ru_geopoints(form_schema = geo_fs, wkt = FALSE) 36 | #' 37 | #' dplyr::glimpse(geo_gj_parsed) 38 | #' 39 | #' # WKT 40 | #' geo_wkt_parsed <- geo_wkt_raw %>% 41 | #' ruODK::odata_submission_rectangle(form_schema = geo_fs) %>% 42 | #' ruODK::handle_ru_geopoints(form_schema = geo_fs, wkt = TRUE) 43 | #' 44 | #' dplyr::glimpse(geo_wkt_parsed) 45 | handle_ru_geopoints <- function(data, 46 | form_schema, 47 | wkt = FALSE, 48 | verbose = get_ru_verbose()) { 49 | # Find Geopoint columns 50 | geo_cols <- form_schema %>% 51 | dplyr::filter(type == "geopoint") %>% 52 | magrittr::extract2("ruodk_name") %>% 53 | intersect(names(data)) 54 | 55 | x <- paste(geo_cols, collapse = ", ") # nolint 56 | "Found geopoints: {x}." %>% 57 | glue::glue() %>% 58 | ru_msg_info(verbose = verbose) 59 | 60 | for (colname in geo_cols) { 61 | if (colname %in% names(data)) { 62 | "Parsing {colname}..." %>% 63 | glue::glue() %>% 64 | ru_msg_info(verbose = verbose) 65 | data <- 66 | data %>% split_geopoint(as.character(colname), wkt = wkt) 67 | } 68 | } 69 | 70 | data 71 | } 72 | 73 | # usethis::use_test("handle_ru_geopoints") # nolint 74 | -------------------------------------------------------------------------------- /R/submission_detail.R: -------------------------------------------------------------------------------- 1 | #' Show metadata for one submission. 2 | #' 3 | #' `r lifecycle::badge("stable")` 4 | #' 5 | #' @template param-iid 6 | #' @template param-pid 7 | #' @template param-fid 8 | #' @template param-url 9 | #' @template param-auth 10 | #' @template param-retries 11 | #' @return A nested list of submission metadata. 12 | # nolint start 13 | #' @seealso \url{https://docs.getodk.org/central-api-submission-management/#getting-submission-metadata} 14 | # nolint end 15 | #' @family submission-management 16 | #' @export 17 | #' @examples 18 | #' \dontrun{ 19 | #' # See vignette("setup") for setup and authentication options 20 | #' # ruODK::ru_setup(svc = "....svc", un = "me@email.com", pw = "...") 21 | #' 22 | #' sl <- submission_list() 23 | #' 24 | #' sub <- submission_detail(sl$instance_id[[1]]) 25 | #' 26 | #' # The details for one submission return exactly one row 27 | #' nrow(sub) 28 | #' # > 1 29 | #' 30 | #' # The columns are metadata about the submission and the submitter 31 | #' names(sub) 32 | #' # > "instance_id" "submitter_id" "submitter_type" "submitter_display_name" 33 | #' # > "submitter_created_at" "device_id" "created_at" 34 | #' } 35 | submission_detail <- function(iid, 36 | pid = get_default_pid(), 37 | fid = get_default_fid(), 38 | url = get_default_url(), 39 | un = get_default_un(), 40 | pw = get_default_pw(), 41 | retries = get_retries()) { 42 | yell_if_missing(url, un, pw, pid = pid, fid = fid) 43 | httr::RETRY( 44 | "GET", 45 | httr::modify_url( 46 | url, 47 | path = glue::glue( 48 | "v1/projects/{pid}/forms/", 49 | "{URLencode(fid, reserved = TRUE)}/submissions/{iid}" 50 | ) 51 | ), 52 | httr::add_headers( 53 | "Accept" = "application/json; extended", 54 | "X-Extended-Metadata" = "true" 55 | ), 56 | httr::authenticate(un, pw), 57 | times = retries 58 | ) %>% 59 | yell_if_error(., url, un, pw) %>% 60 | httr::content(.) %>% 61 | { # nolint 62 | tibble::tibble( 63 | instance_id = .$instanceId, 64 | submitter_id = .$submitter$id, 65 | submitter = .$submitter$displayName, 66 | created_at = readr::parse_datetime( 67 | .$createdAt, 68 | format = "%Y-%m-%dT%H:%M:%OSZ" 69 | ), 70 | updated_at = ifelse( 71 | is.null(.$updatedAt), 72 | NA, 73 | readr::parse_datetime( 74 | .$updatedAt, 75 | format = "%Y-%m-%dT%H:%M:%OSZ" 76 | ) 77 | ) 78 | ) 79 | } 80 | } 81 | 82 | # usethis::use_test("submission_detail") # nolint 83 | --------------------------------------------------------------------------------