diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml deleted file mode 100644 index bfc9f4d..0000000 --- a/.github/workflows/pkgdown.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples -# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help -on: - push: - branches: [main, master] - pull_request: - release: - types: [published] - workflow_dispatch: - -name: pkgdown.yaml - -permissions: read-all - -jobs: - pkgdown: - runs-on: ubuntu-latest - # Only restrict concurrency for non-PR jobs - concurrency: - group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} - env: - GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} - permissions: - contents: write - steps: - - uses: actions/checkout@v4 - - - uses: r-lib/actions/setup-pandoc@v2 - - - uses: r-lib/actions/setup-r@v2 - with: - use-public-rspm: true - - - uses: r-lib/actions/setup-r-dependencies@v2 - with: - extra-packages: any::pkgdown, local::. - needs: website - - - name: Build site - run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) - shell: Rscript {0} - - - name: Deploy to GitHub pages 🚀 - if: github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@v4.5.0 - with: - clean: false - branch: gh-pages - folder: docs diff --git a/DESCRIPTION b/DESCRIPTION index d02e846..720647d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -27,6 +27,7 @@ Imports: readr, utils, EML, + gdata, magrittr, stringr, lubridate, @@ -49,7 +50,6 @@ Suggests: rmarkdown, testthat (>= 3.0.0), QCkit, - gdata, sf, withr Config/testthat/edition: 3 diff --git a/NAMESPACE b/NAMESPACE index 77d8e86..dd01400 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,6 @@ # Generated by roxygen2: do not edit by hand +export(.finalize_eml) export(.get_user_input3) export(get_abstract) export(get_additional_info) diff --git a/NEWS.md b/NEWS.md index da8df39..0b3388a 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,12 @@ # EMLeditor v1.2.1 (Development version) +## 2026-07-01 + * Add documentation to template script about cross references; clarify that content units are optional. + * Add documentation to github.io pages about cross references; clarify that content units are optional. +## 2026-06-30 + * Add `.finalize_eml()` function to utils.R. Refactor and fix `set_cross_reference()` such that it no longer appends numbers to each cross reference. ## 2026-05-05 * Updated EML script .rmd to include package names when suggesting running `issues()` function. + * Remove pkgdown.yml for DGEC github actions compliance ## 2026-04-22 * Add code.json file and update links, urls, etc in preparation for DGEC migration diff --git a/R/editEMLfunctions.R b/R/editEMLfunctions.R index 2b6d0da..e1219ae 100644 --- a/R/editEMLfunctions.R +++ b/R/editEMLfunctions.R @@ -1723,15 +1723,11 @@ set_cross_reference <- function(eml_object, NPS = TRUE) { # First check that all cross-references are valid: ---- bad_crossref_ids <- NULL - for (i in 1:length(seq_along(cross_ref_id))) { - if (dev == TRUE) { - get_url <- paste0(.ds_dev_api(), - "Profile?q=", - cross_ref_id[[i]]) + for (i in seq_along(cross_ref_id)) { + get_url <- if (dev) { + paste0(.ds_dev_api(), "Profile?q=", cross_ref_id[[i]]) } else { - get_url <- paste0(.ds_secure_api(), - "Profile?q=", - cross_ref_id[[i]]) + paste0(.ds_secure_api(), "Profile?q=", cross_ref_id[[i]]) } req <- httr::GET(get_url, httr::authenticate(":", "", "ntlm"), @@ -1741,15 +1737,14 @@ set_cross_reference <- function(eml_object, cli::cli_abort(c("x" = "ERROR: DataStore connection failed.")) return(invisible(NULL)) } - json <- httr::content(req, "text") - rjson <- jsonlite::fromJSON(json) + rjson <- jsonlite::fromJSON(httr::content(req, "text")) # if the reference doesn't exist: if (length(seq_along(rjson)) == 0) { bad_crossref_ids <- append(bad_crossref_ids, cross_ref_id[[i]]) } } - # Notify user of cross-reference id check: + # Notify user of cross-reference id check: ---- if (!is.null(bad_crossref_ids)) { if (force == FALSE) { msg <- paste0("The following cross reference IDs are invalid, inactive,", @@ -1761,27 +1756,22 @@ set_cross_reference <- function(eml_object, #if cross ref ID check fails and force == TRUE, just abort, no error msg return(invisible(NULL)) } - } else { - if (force == FALSE) { - msg <- paste0("All cross reference ids are valid and activated.") - cli::cli_inform(c("v" = msg)) - } + } else if (force == FALSE) { + cli::cli_inform(c("v" = "All cross reference ids are valid and activated.")) } + # get URLs, titles, and reference types for cross references ---- - cross_ref_url <- NULL - cross_ref_type <- NULL - cross_ref_title <- NULL - for (i in 1:length(seq_along(cross_ref_id))) { - if (dev == TRUE) { - get_url <- paste0(.ds_dev_api(), - "ReferenceCodeSearch?q=", - cross_ref_id[i]) - } else { - get_url <- paste0(.ds_api(), - "ReferenceCodeSearch?q=", - cross_ref_id[i]) - } + cross_ref_url <- character(length(cross_ref_id)) + cross_ref_type <- character(length(cross_ref_id)) + cross_ref_title <- character(length(cross_ref_id)) + + for (i in seq_along(cross_ref_id)) { + get_url <- if (dev) { + paste0(.ds_dev_api(), "ReferenceCodeSearch?q=", cross_ref_id[i]) + } else { + paste0(.ds_api(), "ReferenceCodeSearch?q=", cross_ref_id[i]) + } req2 <- httr::GET(get_url, httr::authenticate(":", "", "ntlm"), @@ -1795,168 +1785,134 @@ set_cross_reference <- function(eml_object, return(invisible()) } #get project information: - json2 <- httr::content(req2, "text") - rjson2 <- jsonlite::fromJSON(json2) + rjson2 <- jsonlite::fromJSON(httr::content(req2, "text")) if (rjson2$isDOI == "True") { cross_url <- paste0("https://doi.org/10.57830/", cross_ref_id[i]) } else { cross_url <- rjson2$referenceUrl } - cross_type <- rjson2$referenceType - cross_title <- rjson2$title - - cross_ref_url <- append(cross_ref_url, cross_url) - cross_ref_type <- append(cross_ref_type, cross_type) - cross_ref_title <- append(cross_ref_title, cross_title) - } - - # generate cross reference additionalMetadata item ---- - cross_refs <- list() - if (length(seq_along(cross_ref_id)) == 1) { - cross_refs <- - list(#describes = cross_ref_description, - metadata = list(crossReferences = - list(crossReference_1 = - list(onlineURL = cross_ref_url, - title = cross_ref_title, - type = cross_ref_type) - ) - ), - id = "DataStore_crossReference") - } else { - #if multiple cross references: - for (j in 1:length(seq_along(cross_ref_id))) { - build_cross_refs <- list(onlineURL = cross_ref_url[j], - title = cross_ref_title[j], - type = cross_ref_type[j]) - build_cross_refs <- list(build_cross_refs) - #names(build_cross_refs)[[1]] <- "crossReference" - names(build_cross_refs)[[1]] <- paste0("crossReference_",j) + cross_ref_type[i] <- rjson2$referenceType + cross_ref_title[i] <- rjson2$title - cross_refs <- append(cross_refs, build_cross_refs) + #cross_ref_url <- append(cross_ref_url, cross_url) + #cross_ref_type <- append(cross_ref_type, cross_type) + #cross_ref_title <- append(cross_ref_title, cross_title) + } + build_cross_ref_items <- function(urls, titles, types) { + items <- vector("list", length(urls)) + for (k in seq_along(urls)) { + items[[k]] <- list(onlineURL = urls[k], + title = titles[k], + type = types[k]) } - #new code line - cross_refs_list <- list(crossReferences = cross_refs) - add_meta_cross_refs <- list(metadata = cross_refs_list, - id = "DataStore_crossReference") -# cross_refs[["id"]] <- "DataStoreCrossReference" + items # unnamed list — each element becomes one node } + new_items <- build_cross_ref_items(cross_ref_url, cross_ref_title, cross_ref_type) + + add_meta_cross_refs <- list( + metadata = list( + crossReferences = list( + crossReference = new_items # named key + unnamed list = repeated siblings + ) + ), + id = "DataStore_crossReference" + ) + # get existing additionalMetadata elements --- doc <- eml_object$additionalMetadata #if no additional metadata at all.... if(is.null(doc)){ eml_object$additionalMetadata <- list( add_meta_cross_refs) + return(.finalize_eml(eml_object, NPS)) } - if(!is.null(doc)){ - #helps track lists of different lengths/hierarchies - x <- length(doc) - # Is cross ref already specified? - exist_cross_ref <- NULL - for (i in seq_along(doc)) { - y <- suppressWarnings(stringr::str_replace_all(doc[i], " ", "")) - if (suppressWarnings( - stringr::str_detect(y, - "DataStore_crossReference")) == TRUE) { - seq <- i - exist_cross_ref <- doc[[i]]$metadata - titles <- unlist(exist_cross_ref)[grepl('title', - names(unlist(exist_cross_ref)), - fixed=T)] - } - } - # scripting route: - if (force == TRUE) { - eml_object$additionalMetadata[[seq]] <- add_meta_cross_refs + # Locate any pre-existing cross reference block + exist_cross_ref <- NULL + seq_idx <- NULL + for (i in seq_along(doc)) { + y <- suppressWarnings(stringr::str_replace_all(doc[i], " ", "")) + if (isTRUE(suppressWarnings( + stringr::str_detect(y, "DataStore_crossReference")))) { + seq_idx <- i + exist_cross_ref <- doc[[i]]$metadata + titles <- unlist(exist_cross_ref)[ + grepl("title", names(unlist(exist_cross_ref)), fixed = TRUE) + ] } - # interactive route: - if (force == FALSE) { - # If no existing cross ref, add it in: - if (is.null(exist_cross_ref)) { - if (x == 1) { - eml_object$additionalMetadata <- list(add_meta_cross_refs, - eml_object$additionalMetadata) - } - if (x > 1) { - eml_object$additionalMetadata[[x + 1]] <- add_meta_cross_refs - } - msg <- paste0("No previous cross references detected. The following ", - "cross references have been added to ", - "additionalMetadata: {.var {cross_ref_id}} \n and will ", - "automatically be added to your DataStore reference.") - cli::cli_inform(c("v" = msg)) - } - - # If existing cross ref, stop. - if (!is.null(exist_cross_ref)) { - - msg <- paste0("Cross references have previously been specified as ", - "{.var {titles}}") - cli::cli_inform(c("*" = msg)) - - cat("Do you you want:\n - 1) Add to the existing cross references - 2) Replace the existing cross references - 3) Make no changes to the existing cross references - ") - repeat { - var1 <- .get_user_input3() #1 = add 2 = replace, 3 = nothing - if (var1 != 1 & var1 != 2 & var1 != 3) { - msg <- "Invalid input: Pleae enter 1, 2, or 3" - cli::cli_inform(c("!" = msg)) - } else { - break - } - } - if (var1 == 2) { - eml_object$additionalMetadata[[seq]] <- add_meta_cross_refs - msg <- paste0("The previously existing cross reference(s) have ", - "been replaced with {.var {cross_ref_id}}.") - cli::cli_inform(c("*" = msg)) - } else if (var1 == 3) { - msg <- "Your originally specified cross reference(s) were retained" - cli::cli_inform(c("*" = msg)) - } else if (var1 == 1) { - # add to existing cross refs... this should work if 1 existing - # and one new. Need to make robust to 1 and 1+ for each. - new_cross_refs <- add_meta_cross_refs[["metadata"]][["crossReferences"]] - - exist_length <- length(exist_cross_ref[["crossReferences"]]) - - all_refs <- append(exist_cross_ref[[1]], new_cross_refs) - - new_names <- NULL - - for (i in 1:length(all_refs)) { - new_names <- append(new_names, paste0("crossReference_", i)) - } - - names(all_refs) <- new_names - - exist_cross_ref[["crossReferences"]] <- all_refs - - eml_object$additionalMetadata[[seq]] <- exist_cross_ref + } - msg <- paste0("The following cross reference(s) have been ", - "added to the existing cross reference(s): ", - "{.var {cross_ref_id}}.") - cli::cli_inform(c("*" = msg)) - } - } + # Scripting route (force == TRUE): silently replace existing block ---- + if (force == TRUE) { + if (is.null(seq_idx)) { + eml_object$additionalMetadata[[length(doc) + 1]] <- add_meta_cross_refs + } else { + eml_object$additionalMetadata[[seq_idx]] <- add_meta_cross_refs } - } - # Set NPS publisher, if it doesn't already exist - if (NPS == TRUE) { - eml_object <- .set_npspublisher(eml_object) + return(.finalize_eml(eml_object, NPS)) } - # add/updated EMLeditor and version to metadata: - eml_object <- .set_version(eml_object) + # Interactive route (force == FALSE): ---- + if (is.null(exist_cross_ref)) { + # No existing block — append new one + eml_object$additionalMetadata[[length(doc) + 1]] <- add_meta_cross_refs + cli::cli_inform(c("v" = paste0( + "No previous cross references detected. The following cross references ", + "have been added to additionalMetadata: {.var {cross_ref_id}} and will ", + "automatically be added to your DataStore reference." + ))) + } else { + # Existing block found — prompt user + cli::cli_inform(c("*" = paste0( + "Cross references have previously been specified as {.var {titles}}" + ))) + cat("Do you want:\n + 1) Add to the existing cross references + 2) Replace the existing cross references + 3) Make no changes to the existing cross references + ") + repeat { + var1 <- .get_user_input3() # 1 = add, 2 = replace, 3 = nothing + if (!var1 %in% c(1, 2, 3)) { + cli::cli_inform(c("!" = "Invalid input: Please enter 1, 2, or 3")) + } else { + break + } + } + + if (var1 == 2) { + eml_object$additionalMetadata[[seq_idx]] <- add_meta_cross_refs + cli::cli_inform(c("*" = paste0( + "The previously existing cross reference(s) have been replaced ", + "with {.var {cross_ref_id}}." + ))) + } else if (var1 == 3) { + cli::cli_inform(c("*" = + "Your originally specified cross reference(s) were retained.")) + } else if (var1 == 1) { + # Merge: pull existing unnamed items and append new ones. + # Both old and new are stored under $crossReferences$crossReference + # as unnamed lists, so append() preserves the flat unnamed structure. + exist_items <- exist_cross_ref[["crossReferences"]][["crossReference"]] + merged_items <- append(exist_items, new_items) + + eml_object$additionalMetadata[[seq_idx]] <- list( + metadata = list( + crossReferences = list(crossReference = merged_items) + ), + id = "DataStore_crossReference" + ) + cli::cli_inform(c("*" = paste0( + "The following cross reference(s) have been added to the existing ", + "cross reference(s): {.var {cross_ref_id}}." + ))) + } + } - return(eml_object) + .finalize_eml(eml_object, NPS) + return(eml_object) } diff --git a/R/utils.R b/R/utils.R index 55694aa..b290798 100644 --- a/R/utils.R +++ b/R/utils.R @@ -310,3 +310,20 @@ globalVariables(c("UnitCode", var1 <- readline(prompt = ("")) return(var1) } + +# Internal helper: apply NPS publisher + version stamp and return object +#' +#' @param eml_object An eml object +#' @param NPS Logical. Whether the product is by or for NPS +#' +#' @returns eml_object +#' @noRd +#' +#' @examples +#' \dontrun{ +#' .finalize_eml(eml_object, NPS = TRUE) +#' } +.finalize_eml <- function(eml_object, NPS) { + if (NPS) eml_object <- .set_npspublisher(eml_object) + .set_version(eml_object) +} diff --git a/README.md b/README.md index 9913860..b936c5d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,6 @@ [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) -[![CodeFactor](https://www.codefactor.io/repository/github/doi-nps/emleditor/badge)](https://www.codefactor.io/repository/github/doi-nps/emleditor) [![R-CMD-check](https://github.com/doi-nps/EMLeditor/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/doi-nps/EMLeditor/actions/workflows/R-CMD-check.yaml) diff --git a/docs/articles/a02_EML_creation_script.html b/docs/articles/a02_EML_creation_script.html index 5dbd7f2..14a85be 100644 --- a/docs/articles/a02_EML_creation_script.html +++ b/docs/articles/a02_EML_creation_script.html @@ -585,7 +585,7 @@

Set the language "English")
-

These are the park units where data were collected from, for instance ROMO, not ROMN. If the data package includes data from more than one @@ -596,6 +596,9 @@

+

Add cross references (optional) +

+

You can also add one or more cross-references to your data package. +These will be linked to the published data package on DataStore. For +instance, if there is a .pdf, map, or diagram of a sampling scheme that +is particularly relevant to your data package but cannot be included +within the data package (because its not in .csv format) you can list it +as a cross-reference.

+
+my_metadata <- EMLeditor::set_cross_reference(my_metadata, 1234567)
+
+

Validate your EML

Almost done! This is another great time to validate your EML and make sure Everything is schema valid. Run:

-
+
 EML::eml_validate(my_metadata)

if your EML is valid you should see the following (admittedly crypitic):

@@ -658,7 +673,7 @@

Write your EML to an xml file
+
 EML::write_eml(my_metadata, "mymetadatafilename_metadata.xml")

@@ -667,7 +682,7 @@

Check your .xml file
+
 # This assumes that you have written your metadata to an .xml file and that the .xml file is in the current working directory.
 DPchecker::run_congruence_checks(check_metadata_only = TRUE)
 
@@ -683,7 +698,7 @@ 

Check your data package -
+
 # this assumes that the data package is the working directory
 DPchecker::run_congruence_checks()
 
@@ -700,7 +715,7 @@ 

Upload your data package -
+
 # this assumes your data package is in the current working directory
 EMLeditor::upload_data_package()
 
diff --git a/docs/index.html b/docs/index.html
index 652131e..71694c0 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -149,7 +149,6 @@ 

Developers

Dev status

  • Lifecycle: experimental
  • -
  • CodeFactor
  • R-CMD-check
diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml index 88bcdc2..92cb306 100644 --- a/docs/pkgdown.yml +++ b/docs/pkgdown.yml @@ -7,7 +7,7 @@ articles: a03_Template_edits: a03_Template_edits.html a04_Editing_fixing_eml: a04_Editing_fixing_eml.html a05_advanced_functionality: a05_advanced_functionality.html -last_built: 2026-05-05T15:15Z +last_built: 2026-07-01T22:16Z urls: reference: https://doi-nps.github.io/EMLeditor/reference article: https://doi-nps.github.io/EMLeditor/articles diff --git a/inst/rmarkdown/templates/editable_eml_creation_workflow/skeleton/skeleton.Rmd b/inst/rmarkdown/templates/editable_eml_creation_workflow/skeleton/skeleton.Rmd index 12a655c..839948a 100644 --- a/inst/rmarkdown/templates/editable_eml_creation_workflow/skeleton/skeleton.Rmd +++ b/inst/rmarkdown/templates/editable_eml_creation_workflow/skeleton/skeleton.Rmd @@ -271,9 +271,7 @@ where the 1234567 number corresponds to the 7-digit DataStore reference ID. #### Add information about a DRR (optional) If you are producing (or plan to produce) a DRR, add links to the DRR describing the data package. -You will need the DOI for the DRR you are drafting as well as the DRR's title. Go to DataStore and initiate a draft DRR, including a title. For the purposes of the data package, there is no need to populate any other fields. At this point, you do not need to activate the DRR reference and, while a DOI has been reserved for your DRR, -it will not be activated until after publication so that you have plenty of -time to construct the DRR. +You will need the DOI for the DRR you are drafting as well as the DRR's title. Go to DataStore and initiate a draft DRR, including a title. For the purposes of the data package, there is no need to populate any other fields. At this point, you do not need to activate the DRR reference and, while a DOI has been reserved for your DRR,it will not be activated until after publication so that you have plenty of time to construct the DRR. ```{r DRR_links} my_metadata <- EMLeditor::set_drr(my_metadata, 7654321, "DRR Title") ``` @@ -284,8 +282,10 @@ This is the human language (as opposed to computer language) that the data packa my_metadata <- EMLeditor::set_language(my_metadata, "English") ``` -#### Add content unit links +#### Add content unit links (optional) These are the park units where data were collected from, for instance ROMO, not ROMN. If the data package includes data from more than one park, they can all be listed. For instance, if data were collected from all park units within a network, each unit should be listed separately rather than the network. This is because the geographic coordinates corresponding to bounding boxes for each park unit listed will automatically be generated and inserted into the metadata. Individual park units will be more informative than the bounding box for the entire network. + +If your data do not come from a specific location (e.g. just a list of endangered species, data from lab samples) you can skip lines 291-294. ```{r content_units} park_units <- c("ROMO", "GRSA", "YELL") my_metadata <- EMLeditor::set_content_units(my_metadata, park_units) @@ -312,6 +312,12 @@ You can add a project to your metadata. Once the metadata are extracted on DataS my_metadata <- EMLeditor::set_project(my_metadata, 1234567) ``` +#### Add cross references to your data package (optional) +You can also add one or more cross-references to your data package. These will be linked to the published data package on DataStore. For instance, if there is a .pdf, map, or diagram of a sampling scheme that is particularly relevant to your data package but cannot be included within the data package (because its not in .csv format) you can list it as a cross-reference. +```{r add_cross_ref} +my_metadata <- EMLediter::set_cross_reference(my_metadata, 1234567) +``` + ## Validate your EML Almost done! This is another great time to validate your EML and make sure everything is schema valid. Run: diff --git a/vignettes/a02_EML_creation_script.Rmd b/vignettes/a02_EML_creation_script.Rmd index 8d417b5..64eac34 100644 --- a/vignettes/a02_EML_creation_script.Rmd +++ b/vignettes/a02_EML_creation_script.Rmd @@ -584,7 +584,7 @@ my_metadata <- EMLeditor::set_language(my_metadata, "English") ``` -## Add content unit links +## Add content unit links (optional) These are the park units where data were collected from, for instance ROMO, not ROMN. If the data package includes data from more than one @@ -596,6 +596,8 @@ automatically be generated and inserted into the metadata. Individual park units will be more informative than the bounding box for the entire network. +If your data do not come from a specific location (e.g. just a list of endangered species, data from lab samples) you can skip the following code. + ```{r content_units, eval=FALSE} park_units <- c("ROMO", "GRSA", "YELL") my_metadata <- EMLeditor::set_content_units(my_metadata, @@ -631,12 +633,20 @@ add it to metadata. 4) Whoever uploads and extracts the metadata on DataStore must have ownership level permissions on both the data package and the project. + ```{r add_project, eval = FALSE} # where "1234567" is the DataStore Reference id for the Project # that the data package should be linked to. my_metadata <- EMLeditor::set_project(my_metadata, 1234567) ``` +## Add cross references (optional) +You can also add one or more cross-references to your data package. These will be linked to the published data package on DataStore. For instance, if there is a .pdf, map, or diagram of a sampling scheme that is particularly relevant to your data package but cannot be included within the data package (because it's not in .csv format) you can list it as a cross-reference. + +```{r add_cross_ref, eval = FALSE} +my_metadata <- EMLeditor::set_cross_reference(my_metadata, 1234567) +``` + ## Validate your EML Almost done! This is another great time to validate your EML and make