Access to an exam is determined on two factors: who is accessing the exam and when is the exam accessed. The first factor, who is accessing the exam, is resolved through the authentication provider. Once the user is authenticated, either a new attempt is started or an unfinished attempt is resumed. Whether the user is allowed to start a new attempt or resume an old attempt is determined by the global or user-specific attempt configuration.
Currently, examinr ships with only three authentication providers:
rsconnect_auth(), which uses the RStudio Connect user information, as well as
ui_token_auth() which show a login screen when the learner loads the exam.
which have to be somehow distributed to the learners beforehand.
RStudio Connect exposes the current user in
session$user and the group membership of the user in
rsconnect_auth() authentication provider uses this information and allows you to give grading permission to certain groups. For example
#! context="server-start" exam_config(auth_provider = rsconnect_auth(grading_groups = c('instructor', 'ta')))
would use the RStudio Connect user name as
user_id and set
grading=TRUE to any user with membership in either the instructor or ta group.
You can also write your own authentication provider which takes information from the session object (e.g., from the query string) to authenticate users. The authentication provider can add more information to the user object than specified above. Any function receiving the user object as input will receive all the information returned by the authentication provider.
Loosely speaking, the authentication provider determines who the user is and relays this information in a standardized form to examinr. The authentication provider is set via
exam_config(auth_provider=), which requires a function taking the Shiny session as argument and returning a user object. The user object is an R list with the following entries
||a character string uniquely identifying the user|
||(optional) a logical value indicating if the user has permission to grade attempts|
||(optional) a character string with a human-readable name to be displayed while grading|
user$user_id must be present and uniquely identifies a user for the exam. If
user$grading is present and is
TRUE, the user has the ability to access the grading interface. Also, if
user$display_name is present it will be shown in lieu of the user id when grading, but be aware of privacy issues when storing the exam data in an unencrypted database. See also the information for storage providers.
The attempt configuration consists of the following options
||date-time when the exam “opens”, i.e., becomes available to users||
||date-time when the exam “closes”, i.e., becomes unavailable to users||
||number of attempts a user is afforded||
||time a user can take for a single attempt||
||seconds a user has to submit an unfinished attempt after the time limit has passed or the exam closed||
The default attempt configuration (i.e., the configuration applying to all users unless overridden) is set in the YAML front matter of the exam document via options passed on to the output format
The opens/closes date-time must be given in the format YYYY-MM-DD HH:MM Timezone. The above example configuration would make the exam available between 12:30 on Nov 28 and 23:59 on Nov 29, 2020 (the time is taken as the local time in Vancouver, Canada). Each user can take at most 2 attempts.
An attempt must be finished either within 1 hour and 15 minutes of starting the attempt, or at the closing time (whichever comes first). If the time runs out, the user is given 60 seconds to submit their exam. After this grace period the exam is disabled and all input up to this point is recorded automatically.
The attempt configuration can be overridden for specific users (e.g., to give them more time or more attempts). This is done by calling
configure_attempts() in an R code chunk with
context="server-start". For instance, to give users s443 and s872 2 hours for the exam, and give user s221 more attempts, you would use
#! context="server-start" configure_attempts(c("s443", "s872"), timelimit = "2:00") configure_attempts("s221", max_attempts = 3)
This allows fully customization for user’s specific needs and requests. The last call to
configure_attempts() for a certain user and specific option will be the one taking effect. The following example would give users s443, s872, and s221 2 hours to complete the exam, but users s443 and s872 would get 3 attempts, while user s221 gets 4.
#! context="server-start" configure_attempts(c("s443", "s872", "s221"), timelimit = "2:00", max_attempts = 3) configure_attempts("s221", max_attempts = 4)
To disable opening or closing date-times (i.e., making the exam accessible as soon as it is uploaded or for the rest of time), set the option to
NA. Similarly, disabling time limits and attempt counters, set the options to
Correct attempt configurations are critical for ensuring integrity of an exam. For debugging, you can verify the attempt configuration in your exam by printing the final configuration in the exam document with
show_attempts_configuration(). Simply add an R code chunk to your exam which calls this function, e.g.,
For the example here this would give
A blank cell indicates that the global configuration (first line with user id
--) is in effect for the respective option and user.