# -*- Tcl -*- ######################################################################## # Inclass-Exam workflow, designed similar to online-exam # ====================================================== # # Defining exams: This workflow lets a lecturer choose from a # predefined set of exam questions, which are typically open text, # short text, single or multiple choice questions. The lecturer # selects test questions via drag and drop. The lecturer can perform a # test run of the created exam, and can get the results via a result # table. # # Publishing and closing exams: When a lecturer is satisfied with the # exam, the exam can be published. In this step, all answers of the # testing phase are deleted. In the process of publishing, the link to # start the exam is offered to the user. When the exam is published, # the lecturer can see the incoming answers in the report by refreshing # the page. When the exam is done, it is unpublished. The workflow # offers the lecturer to see a summary of the results in form of a # table (an to download the results via csv), or the lecturer can # produce a printer friendly version of the answers. # # An admin might with to add the following entries to the folder to ease # creation of exercises and exams # # {clear_menu -menu New} # # {entry -name New.Item.TextInteraction -form en:edit-interaction.wf -query p.item_type=Text} # {entry -name New.Item.ShortTextInteraction -form en:edit-interaction.wf -query p.item_type=ShortText} # {entry -name New.Item.SCInteraction -form en:edit-interaction.wf -query p.item_type=SC} # {entry -name New.Item.MCInteraction -form en:edit-interaction.wf -query p.item_type=MC} # {entry -name New.Item.ReorderInteraction -form en:edit-interaction.wf -query p.item_type=Reorder} # {entry -name New.Item.UploadInteraction -form en:edit-interaction.wf -query p.item_type=Upload} # # {entry -name New.App.Exam -label "Inclass Exam" -form en:inclass-exam.wf} # # Alternatively, one can use the programmatic setup for the menubar # via config=test-items in case a site wants to change all setups in # all instances for menubars by updating a single file. # # {config -use test-items} # # The policy has to allow the following methods on FormPages: # # - "answer" (for students), # - "proctor" (for students), # - "view-my-exam" (for students), # - "edit" (for students), # - "poll" (for lecturers), # - "print-answers" (for lecturers), # - "print-answer-table" (for lecturers), # - "print-participants" (for lecturers), # - "delete" (for lecturers), # - "qrcode" (for lecturers) # # Gustaf Neumann, Feb 2012-2020 ######################################################################## set :autoname 1 ;# to avoid editable name field set :policy ::xowf::test_item::test-item-policy-publish set :debug 0 set :live_updates 1 Action select -next_state created -label #xowf.online-exam-select# \ -title #xowf.online-exam-title-select# Action publish -next_state published -label #xowf.online-exam-publish# \ -title #xowf.online-exam-title-publish# Action unpublish -next_state done -label #xowf.online-exam-unpublish# Action republish -next_state published -label #xowf.online-exam-republish# \ -title #xowf.online-exam-title-republish# Action restart -next_state initial -label #xowf.restart# \ -title #xowf.online-exam-title-restart# Action open_submission_review -next_state submission_review -label #xowf.open_submission_review# \ -title #xowf.open_submission_review_title# Action close_submission_review -next_state done -label #xowf.close_submission_review# \ -title #xowf.close_submission_review_title# State parameter { {extra_css {/resources/xowf/test-item.css}} } State initial -actions {select} -form en:select_question.form -view_method edit State created -actions {publish restart} -form_loader load_form -view_method edit \ -form "#xowf.inclass-exam-draft_exam#" State published -actions {unpublish} -form_loader load_form -view_method edit \ -form "#xowf.inclass-exam-open#" State done -actions {republish open_submission_review restart} -form_loader load_form -view_method edit \ -form "#xowf.inclass-exam-closed#" State submission_review -actions {close_submission_review} -form_loader load_form -view_method edit \ -form "#xowf.inclass-exam-review#" ######################################################################## # Activate action select: After the lecturer has selected the # exercises, the answer workflow is created. # select proc activate {obj} { xowf::test_item::answer_manager create_workflow \ -answer_workflow /packages/xowf/lib/inclass-exam-answer.wf \ $obj } ######################################################################## # Activate action publish: delete all responses for the workflow and # publish user participation link. # publish proc activate {obj} { xowf::test_item::answer_manager delete_all_answer_data $obj :publish_link $obj } ######################################################################## # Activate action republish: publish user participation link. # republish proc activate {obj} { :publish_link $obj } ######################################################################## # When the user un-publishes an exam, just the user participation # link should be removed for the users # unpublish proc activate {obj} { :unpublish_link $obj } ######################################################################## # When the user restarts an exam, make sure that already scheduled # atjobs are removed. # restart proc activate {obj} { xowf::test_item::answer_manager delete_scheduled_atjobs $obj } ######################################################################## # When the user opens the submission review, offer a link. # open_submission_review proc activate {obj} { set aLink [$obj pretty_link -query m=view-my-exam] $obj util_user_message -html -message \ "[$obj name] exam review is available as [ns_quotehtml $aLink]" } ######################################################################## # publish_link: make the user participation link available for the # target group # Action instproc publish_link {obj} { set aLink [$obj pretty_link -query m=answer] $obj util_user_message -html \ -message "[$obj name] is available as [ns_quotehtml $aLink]" # TODO: make it happen in the LMS } ######################################################################## # unpublish_link: remove the user participation link for the target # group # Action instproc unpublish_link {obj} { $obj util_user_message -html -message "[$obj name] is closed" # TODO: make it happen in the LMS } ######################################################################## # form loader: create dynamically a form containing the disabled # questions as a preview and the survey results (the results can be # refreshed). # :proc load_form {ctx title} { set obj [$ctx object] set state [$obj property _state] set combined_form_info [::xowf::test_item::question_manager combined_question_form -with_numbers $obj] set fullQuestionForm [dict get $combined_form_info form] set full_fc [dict get $combined_form_info disabled_form_constraints] #:log fullQuestionForm=$fullQuestionForm set text "
[expr {$synchronized ? "" : "Non-"}]Synchronized Exam [expr {$proctoring ? " with Proctoring" : ""}]
}] set question_objs [dict get $combined_form_info question_objs] set nrQuestions [llength $question_objs] set randomizationOk [dict get $combined_form_info randomization_for_exam] set autograde [dict get $combined_form_info autograde] set revision_sets [$obj get_revision_sets] set published_periods [xowf::test_item::answer_manager state_periods $revision_sets -state published] set review_periods [xowf::test_item::answer_manager state_periods $revision_sets -state submission_review] set total_minutes [xowf::test_item::question_manager total_minutes -max_items $max_items $combined_form_info] set total_points [xowf::test_item::question_manager total_points -max_items $max_items $combined_form_info] set max_items_msg "" if {$max_items ne ""} { set all_minutes [lmap t [dict get $combined_form_info title_infos] { dict get $t minutes }] if {[llength [lsort -unique $all_minutes]] != 1} { set max_items_msg [_ xowf.Max_items_not_ok_duration [list n $max_items]] } elseif {$max_items > [llength $all_minutes]} { set max_items_msg [_ xowf.Max_items_not_ok_number [list n $max_items]] } else { set max_items_msg [_ xowf.Max_items_ok [list n $max_items]] } } set time_window_msg "" if {$time_window ne ""} { set dtstart [dict get $time_window time_window.dtstart] if {$dtstart ne ""} { regsub -all T $dtstart " " dtstart set dtend [dict get $time_window time_window.dtend] set time_window_msg
[expr {$max_items_msg ne "" ? "$max_items_msg" : ""}]
$nrQuestions [expr {$nrQuestions == 1 ? "#xowf.question#" : "#xowf.questions#"}],
$total_minutes #xowf.Minutes#, $total_points #xowf.Points#
[expr {$autograde ? "#xowf.exam_review_possible#" : "#xowf.exam_review_not_possible#"}]
[expr {$randomizationOk ? "#xowf.randomization_for_exam_ok#" : "#xowf.randomization_for_exam_not_ok#"}]
[expr {$allow_paste ? "#xowf.Cut_and_paste_allowed#" : "#xowf.Cut_and_paste_not_allowed#"}]
$time_window_msg
[expr {[llength $published_periods] > 0 ? "
#xowf.inclass-exam-open#: [join $published_periods {, }]
" : ""}]
[expr {[llength $review_periods] > 0 ? "#xowf.inclass-exam-review#: [join $review_periods {, }]
" : ""}]
[xowf::test_item::answer_manager grading_table -csv $grade_csv $grade_dict]
} set return_url [:query_parameter local_return_url:localurl [:pretty_link]] append HTML "