jhudsl / OTTR_Template

OTTR for making courses! This is a template repo that helps people write 1 course but publish it in three places
https://www.ottrproject.org/
Creative Commons Attribution 4.0 International
15 stars 12 forks source link

Feedback Widget at the bottom of page #709

Closed howardbaik closed 6 months ago

howardbaik commented 7 months ago

At today's ITN meeting, we discussed having a "feedback widget" at the bottom of each page, asking the reader questions about the course.

Here is a possible solution: https://widgets.formr.org/ . The formr package offers several widgets (embedded in HTML pages) that contain questions/answers which the user can click.

@cansavvy @carriewright11 @kweav

cansavvy commented 7 months ago

This looks promising but I'd like to know more details about how the results are stored and how easy it is to retrieve the results

https://rubenarslan.github.io/formr/reference/index.html

Looks like it's pretty actively under development which is good but it is pretty green it seems. (The docs are a bit sparse) https://github.com/rubenarslan/formr/issues

This definitely could be an option, but do we know of any other options that might have a slightly longer, more proven track record and stability?

howardbaik commented 6 months ago

@cansavvy @carriewright11 @kweav

formr (mentioned in my original post) doesn't seem like the right tool for this problem. It's a tool for setting up a large scale online survey framework, but that's not what we are after here.

I've done a ton of googling to see if R Markdown natively supports this, and the short answer is no. However, I do have an idea on how to hack away at this. I could have every newly created R Markdown create a Google Form using the Google Forms API. Each form would save all the responses to a master Google spreadsheet that hopefully has unique IDs for each Rmd file, the response, and maybe feedback/comments.

This sounds easy in theory, but the difficult part is to code this up and integrate it into the OTTR template. The main HTTP request to call is forms.create: https://developers.google.com/forms/api/reference/rest/v1/forms/create

With the help of ChatGPT, I was able to run the following code and programmatically create a new Google Form:

library(httr2)

# Google's OAuth 2.0 endpoints
auth_url <- "https://accounts.google.com/o/oauth2/auth"
token_url <- "https://oauth2.googleapis.com/token"

# Your OAuth 2.0 credentials
client_id <- "YOUR_CLIENT_ID"
client_secret <- "YOUR_CLIENT_SECRET"

# The scopes you need (modify if necessary)
scopes <- "https://www.googleapis.com/auth/drive"

# Construct the authorization URL
auth_url_full <- paste0(auth_url, "?response_type=code",
                        "&client_id=", URLencode(client_id),
                        "&redirect_uri=", URLencode("urn:ietf:wg:oauth:2.0:oob"),
                        "&scope=", URLencode(scopes),
                        "&access_type=offline") # For refresh token

# Print the URL so you can visit it in your browser
cat("Visit this URL in your web browser to authorize:", auth_url_full, "\n")

auth_code <- "PASTE_AUTHORIZATION_CODE_FROM_PREVIOUS_STEP"

# Prepare the request for an access token
token_response <- request(token_url) |>
  req_body_json(list(code = auth_code,
                     client_id = client_id,
                     client_secret = client_secret,
                     redirect_uri = "urn:ietf:wg:oauth:2.0:oob",
                     grant_type = "authorization_code")) |>
  req_perform()

# Extract the access token from the response
access_token <- resp_body_json(token_response)$access_token

# Define the API endpoint for creating a new form
url <- "https://forms.googleapis.com/v1/forms"

# Adjust the JSON payload according to the provided structure
json_payload <- list(
  info = list(
    title = "Hello from httr2"
  )
)

# Create a request object
response <- request("https://forms.googleapis.com/v1/forms") |>
  req_headers(Authorization = paste("Bearer", access_token),
              `Content-Type` = "application/json") |>
  req_body_json(json_payload) |>
  req_perform()

# Parse the response
response <- resp_body_json(response)

# Print the response to see details of the created form
print(response)

I created a Client ID and Client Secret in the Google Cloud Platform (GCP) and enabled the Google Forms API. (https://babichmorrowc.github.io/post/google-api-creds/)

cansavvy commented 6 months ago

Let me look more detail into this code but certainly seems like we should integrate this into metricminer as a metric one can collect plus Google forms api auth is already set up there.

cansavvy commented 6 months ago

Or I also have code that does this in the rgoogleclassroom r package

cansavvy commented 6 months ago

Also one more thought a Google form for every single Rmd will be a bit of an organizational headache but alternatively we can use one Google form that already enters what page someone responded on.

I can set up a prototype of this to show you what I mean

cansavvy commented 6 months ago

I ended up making a mini shiny app for this because it seemed less intensive than making google forms. But I could use your help making it pretty

?course=github_actions in the code below specifies what course for people so they don't have to add that info. Then when people hit "submit" the course, the rating, and the time is recorded in a googlesheet.

<center>
<div class="container">
  <iframe class="responsive-iframe" src="https://c-savonen.shinyapps.io/widget-survey/?course=github_actions" style="width: 300px; height: 200px; overflow: auto;"></iframe>
</div>
  </div>
</center>

Testing this in a course here: https://github.com/fhdsl/GitHub_Automation_for_Scientists/pull/17

The code is here: https://github.com/fhdsl/widget-survey

cansavvy commented 6 months ago

This is done!