shinymanager icon indicating copy to clipboard operation
shinymanager copied to clipboard

How to use inputs_list

Open dmenne opened this issue 2 years ago • 9 comments

I have successfully added a column group in create_db and can edit the field as admin or retrieve it in server. However, there is a feature input_list in secure_server which might be related and useful; however, I do not understand how it should be use. The documentation below is a bit difficult to read, and it would be helpful if some native speaker could improve the text. Or, even better, could you add something to the example?

 res_auth = secure_server(
    check_credentials = check_credentials(
      sqlite_path,
      passphrase = passphrase
    ),
    inputs_list = 
      list(
        group = list( 
          fun = "selectInput", 
          args = list( choices = c("all", "restricted"), 
                       multiple = TRUE, 
                       selected = c("all", "restricted")
          )
        )
      )
  )

So now what to do with this?

If database credentials, you can configure inputs with inputs_list for editing users information from the admin console. start, expire, admin and password are not configurable. The others columns are rendering by defaut using a textInput. You can modify this using inputs_list. inputs_list must be a named list. Each name must be a column name, and then we must have the function shiny to call fun and the arguments args like this : list(group = list( fun = "selectInput", args = list( choices = c("all", "restricted"), multiple = TRUE, selected = c("all", "restricted") ) ) )

dmenne avatar Jul 16 '21 15:07 dmenne

inputs_list = 
  list(
    name_of_new_variable = list(
      fun = "name of input type for choosing its value",
      args = list( #list containing arguments for this input type )
    )
  )

Moreover, looking through the source code: if you use input type allowing for multiple values to choose, the value will be a character string with chosen values separated by ; character. For example multiple applications access while using applications variable will look like: "app1;app2;app3"

StatisMike avatar Jul 18 '21 19:07 StatisMike

Notice, that's about the same I showed above. The question was how to use it in Shiny. Not for multiple applications, since input_lists is a parameter of secure_server

dmenne avatar Jul 18 '21 19:07 dmenne

By default the extra columns can be edited in Shiny using textInput. The inputs_list argument let you define other input methods for editing/assigning this variable, as shown in example cited by you: the input method for group variable will be a selectInput (as opposed to default textInput) with "all" and "restricted" choices allowing for multiple values to be selected. If you select both of them, the final value will be "all;restricted".

StatisMike avatar Jul 18 '21 21:07 StatisMike

You cited the documentation, but it is very formal and difficult to understand. Let's stick with the R habit of providing and example. How do I make use of this in the example below? It is syntactically correct, but how do I get the selectInput box?

# define some credentials
credentials <- data.frame(
  user = c("shiny", "shinymanager"),
  password = c("azerty", "12345"),
  stringsAsFactors = FALSE,
  input_list = list(
    group = list(
      fun = "selectInput",
      args = list( choices = c("all", "restricted"),
                   multiple = TRUE,
                   selected = c("all", "restricted")
      )
    )
  )
)

library(shiny)
library(shinymanager)

ui <- fluidPage(
  tags$h2("My secure application"),
  textInput("group", "Group"), # ???????
  verbatimTextOutput("auth_output")
)

# Wrap your UI with secure_app
ui <- secure_app(ui, choose_language = TRUE)

server <- function(input, output, session) {

  # call the server part
  # check_credentials returns a function to authenticate users
  res_auth <- secure_server(
    check_credentials = check_credentials(
      credentials)
    )


  output$auth_output <- renderPrint({
    reactiveValuesToList(res_auth)
  })

  observe({
    print(input$shinymanager_where)
    print(input$shinymanager_language)
  })
}

shinyApp(ui, server)

dmenne avatar Jul 19 '21 07:07 dmenne

There are several problems with your implementation.

  1. inputs_list is argument in secure_server. You cannot input list into data.frame!
  2. To get access to admin mode, you need to create a SQLite database
  3. To modify the users database in any way, you need to do it in admin mode, not from the core ShinyApp
  4. You need to create new variable in the credentials data before managing it in database.
# define some credentials (first time only!)

credentials <- data.frame(
    user = c("shiny", "shinymanager"),
    password = c("azerty", "12345"),
    admin = c(TRUE, FALSE),
    group = c("", ""),
    stringsAsFactors = FALSE
)

create_db(credentials,
          sqlite_path = "test.sqlite")

# app Logic

library(shiny)
library(shinymanager)

ui <- fluidPage(
    tags$h2("My secure application"),
    textInput("group", "Group"), # ???????
    verbatimTextOutput("auth_output")
)

# Wrap your UI with secure_app. Admin mode need to be enabled
ui <- secure_app(ui, choose_language = TRUE, enable_admin = TRUE)

server <- function(input, output, session) {
    
    # call the server part
    # check_credentials returns a function to authenticate users
    res_auth <- secure_server(
        check_credentials = check_credentials(db = "test.sqlite"),
        # define the inputs_list argument
        inputs_list = list(
            group = list(
                fun = "selectInput",
                args = list( 
                    choices = c("all", "restricted"),
                    multiple = TRUE,
                    selected = c("all", "restricted")
                )
            )
        )
    )
    
    observe({
        output$auth_output <- renderPrint({
        reactiveValuesToList(res_auth)
    })
        print(input$shinymanager_where)
        print(input$shinymanager_language)
    })
}

shinyApp(ui, server)

StatisMike avatar Jul 19 '21 09:07 StatisMike

Thanks for you example.

inputs_list is argument in secure_app. You cannot input list into data.frame!

Following your documentation, it is a parameter in secure_server, not in secure_app.

To get access to admin mode, you need to create a SQLite database

I am normally using an SQLite database, but I tried to create a simplified example. I could not find documentation that admin-mode is only possible with a database, please correct me when I am wrong.

Your example does not show what the 'group = ...` code is good for.

dmenne avatar Jul 19 '21 09:07 dmenne

Following your documentation, it is a parameter in secure_server, not in secure_app.

You've got me! I'm editing it above, thanks for correction.

Your example does not show what the group = ... code is good for.

It is very vital, when you need to have explicit values of the column, and you don't want to allow admin to pass whatever he wants into it.

Example: custom input group with specified input method:

img

As you can see, it's value can only be in c("", "all", "restricted", "restricted;all" or "all;restricted")

Example2: custom input group without specified input method:

img2

As you can see, the admin can set the value to character string of his choice. Most of the time it isn't good practice.

Of course, the custom column can have any name - it don't neet to be group with values c("all", "restricted"). You can create column of your choice. After logging in, server can access it from auth$name_of_custom_column. (where auth is object to which you've assigned secure_server output). How you use it - it's completely your choice and creativity.

StatisMike avatar Jul 19 '21 10:07 StatisMike

Thanks, now I got it. From the name "selectInput" I had expected that somewhere there should be a dropdown combo box, not a text field. It also means that everything worked as expected already.

Thanks for you patience.

dmenne avatar Jul 19 '21 11:07 dmenne

I wrote:

I could not find documentation that admin-mode is only possible with a database, please correct me when I am wrong.

I have to correct, it says

If database credentials, you can configure inputs for editing users information. See Details.

Proposed: When you are using database credentials, you can configure the inputs for editing of user information; see Details

However, the details example is very difficult to understand, and using selectInput when it is a textInput anyway can be very confusing.

dmenne avatar Jul 19 '21 13:07 dmenne