Skip to content

Commit

Permalink
Merge pull request #1 from nhsbsa-data-analytics/improvements
Browse files Browse the repository at this point in the history
Improvements + deletion of some files
  • Loading branch information
MarkMc1089 authored Oct 11, 2024
2 parents eeb2fe7 + 5e2cc2d commit a2cf8e6
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 130 deletions.
50 changes: 0 additions & 50 deletions .github/workflows/test-coverage.yaml

This file was deleted.

2 changes: 1 addition & 1 deletion .lintr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
linters: with_defaults(line_length_linter(90))
linters: linters_with_defaults (line_length_linter(90))
exclude: "# Exclude Linting"
exclude_start: "# Begin Exclude Linting"
exclude_end: "# End Exclude Linting"
9 changes: 2 additions & 7 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: shinyusertracking
Title: Add user tracking to Shiny apps
Version: 1.0.0.000
Version: 1.0.1.000
Authors@R:
person(
"Mark", "McPherson", ,
Expand All @@ -11,13 +11,8 @@ Description: Log session and user data to a Google sheet.
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.2
Suggests:
covr,
testthat (>= 3.0.0)
RoxygenNote: 7.3.1
Config/testthat/edition: 3
Imports:
shiny,
googlesheets4,
hms,
lubridate
129 changes: 96 additions & 33 deletions R/usertracking.R
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@

#' Add user tracking
#'
#' Log session ID, username (only for Private apps), session start, end and
#' duration to a Google sheet.
#'
#' @param google_email Email used for Google account username.
#' @param sheet_id Google sheet ID.
#' @param columns Which columns to record, from id, username, login, logout and
#' duration. By default all will be recorded.
#' @param session Shiny session object.
#'
#' @return Nothing; used for side effect.
Expand All @@ -18,53 +17,117 @@
#' ui <- fluidPage()
#' server <- function(input, output, session) {
#' shinyusertracking::set_user_tracking(
#' "[email protected]",
#' "1234567890987654321",
#' c("login", "logout", "duration"),
#' session
#' )
#' }
#'
#' shinyApp(ui, server)
#' }
#'
set_user_tracking <- function(google_email, sheet_id, session) {
if (sheet_id == "") {
return(invisible())
set_user_tracking <- function(columns = NULL, session) {
known_cols <- c(
"id",
"username",
"login",
"logout",
"duration"
)

if (is.null(columns)) {
columns <- known_cols
} else {
stopifnot({
columns %in% known_cols
})
}

eval_lines(".google-sheets-credentials")

google_email <- NULL
sheet_id <- NULL

try({
google_email <- get("GOOGLE_SHEET_USER")
})
try({
sheet_id <- get("GOOGLE_SHEET_ID")
})

if (is.null(google_email) || is.null(sheet_id)) {
warning(
"Credentials missing for shinyusertracking::set_user_tracking",
call. = FALSE
)
return()
}

googlesheets4::gs4_auth(
email = google_email,
cache = ".secret/"
)

shiny::isolate({
userdata <<- userdata <- data.frame( # Exclude Linting
id = session$token,
username = ifelse(is.null(session$user), "unknown", session$user),
login = Sys.time(),
logout = lubridate::NA_POSIXct_,
duration = NA_character_
)
})
session$userData$tracking <- data.frame(
id = session$token,
username = ifelse(is.null(session$user), "unknown", session$user),
login = Sys.time(),
logout = lubridate::NA_POSIXct_,
duration = NA_character_
)

session$onSessionEnded(function() {
shiny::isolate({
userdata[userdata$id == session$token, "logout"] <- Sys.time()
userdata[userdata$id == session$token, "duration"] <- as.character(
hms::hms(
round(
lubridate::as.period(
userdata[userdata$id == session$token, "logout"] -
userdata[userdata$id == session$token, "login"],
"seconds"
)
)
)
)
session$userData$tracking$logout <- Sys.time()

googlesheets4::sheet_append(sheet_id, userdata)
})
duration <- difftime(
session$userData$tracking$logout,
session$userData$tracking$login,
units = "secs"
)
duration <- abs(as.numeric(duration))
duration <- sprintf(
"%02d:%02d:%02d", # hh:mm:ss
duration %/% 3600, # whole hours (could be > 24)
duration %% 3600 %/% 60, # whole minutes left
duration %% 60 %/% 1 + round(duration %% 60 %% 1) # rounded seconds left
)

session$userData$tracking$duration <- as.character(duration)

googlesheets4::sheet_append(
sheet_id,
subset(session$userData$tracking, select = columns)
)
})
}


#' Evaluate each line of plain text file
#'
#' Reads a plain text file line by line, evaluating each line. Useful for
#' creating variables dynamically, e.g. reading in parameters.
#'
#' @param filepath Filepath as a String.
#' @param envir Environment to evaluate in. Default is calling environment.
#'
#' @return Nothing
#'
#' @examples
#' \dontrun{
#' filepath <- tempfile()
#' writeLines(
#' text = "LEFT = \"right\"",
#' con = filepath
#' )
#' eval_lines(filepath)
#' print(LEFT)
#' unlink(filepath) # delete temporary file
#' rm(left) # remove example variable
#' }
eval_lines <- function(filepath, envir = parent.frame()) {
con <- file(filepath, open = "r")
on.exit(close(con))

invisible()
while (length(line <- readLines(con, n = 1, warn = FALSE)) > 0) {
eval(parse(text = line), envir = envir)
}
}
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# shinyusertracking

<!-- badges: start -->
[![Codecov test coverage](https://codecov.io/gh/MarkMc1089/shinyusertracking/branch/master/graph/badge.svg)](https://app.codecov.io/gh/MarkMc1089/shinyusertracking?branch=master)
[![R-CMD-check](https://github.com/MarkMc1089/shinyusertracking/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/MarkMc1089/shinyusertracking/actions/workflows/R-CMD-check.yaml)
<!-- badges: end -->

Expand All @@ -19,7 +18,7 @@ devtools::install_github("nhsbsa-data-analytics/shinyusertracking")

## Example

Just add the function at the top of your `server` code. You will need to provide the ID of a Google Sheet and the username (email) of the Google account it is in.
Just add the function at the top of your `server` code. You will need to provide the ID of a Google Sheet and the username (email) of the Google account it is in.

``` r
library(shiny)
Expand All @@ -28,11 +27,26 @@ ui <- fluidPage()

server <- function(input, output, session) {
shinyusertracking::set_user_tracking(
"[email protected]",
"1234567890987654321",
session
)
}

shinyApp(ui, server)
```

Optionally, you can choose to log specific columns only.

Column|Description
:---:|:---:
id|The Shiny session ID
username|The username of user, if available (`null` if app is public)
login|Timestamp of session start
logout|Timestamp of session end
duration|Duration of session in `hh:mm:ss` format

``` r
shinyusertracking::set_user_tracking(
columns = c("login", "logout", "duration"),
session
)
```
14 changes: 0 additions & 14 deletions codecov.yml

This file was deleted.

33 changes: 33 additions & 0 deletions man/eval_lines.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 4 additions & 6 deletions man/set_user_tracking.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 0 additions & 12 deletions tests/testthat.R

This file was deleted.

3 changes: 0 additions & 3 deletions tests/testthat/test-usertracking.R

This file was deleted.

0 comments on commit a2cf8e6

Please sign in to comment.