# -*- Tcl -*- ######################################################################## # Online-Exam workflow, designed similar to mobile-clicker # ======================================================== # # This workflow lets a teacher choose from a predefined set of exam # questions, which are typically open text questions. The teacher # selects one or several exam question via drag and drop. The teacher # can test the exam by entering test answers. The results are provided # in form of a table. # # When the teacher 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 teacher can # see the incoming answers in the report by refreshing the page. When # the exam is done, it is unpublished. The workflow offers the teacher # to see a summary of the results in form of a table (an to download # the results via csv), or the teacher can produce a printer friendly # version of the answers. # # You might with to add the following entries to the folder to ease # creation of exercises and exams # # {entry -name New.App.TextInteraction -label "Text Interaction" -form en:TestItemText.form} # {entry -name New.App.TextEntryInteraction -label "Text Entry Interaction" -form en:TestItemTextEntry.form} # {entry -name New.App.MCInteraction -label "MC Interaction" -form en:TestItemMC.form} # {entry -name New.App.Exam -label Exam -form en:online-exam.wf} # # Gustaf Neumann, Feb 2012 ######################################################################## set :autoname 1 set :debug 1 #set :masterWorkflow //xowf/de:workflow.wf set :masterWorkflow en:Workflow.form Action select -next_state created -label #xowf.online-exam-select# Action publish -next_state published -label #xowf.online-exam-publish# Action unpublish -next_state done -label #xowf.online-exam-unpublish# Action republish -next_state published -label #xowf.online-exam-republish# Action restart -next_state initial -label #xowf.restart# 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.online-exam-draft_exam#" State published -actions {unpublish} -form_loader load_form -view_method edit \ -form "#xowf.online-exam-open#" State done -actions {republish restart} -form_loader load_form -view_method edit \ -form "#xowf.online-exam-closed#" ######################################################################## # Activate action select: After the teacher has selected the # exercises, the answer workflow is created. # select proc activate {obj} { [[$obj wf_context] wf_container] create_answer_workflow $obj } ######################################################################## # Activate action publish: delete all responses for the workflow and # publish user participation link. # publish proc activate {obj} { [[$obj wf_context] wf_container] 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 } ######################################################################## # create_answer_workflow: create a workflow based on the template # provided in this method for answering the question for the # students. The name of the workflow is derived from the workflow # instance and recorded in the formfield "wfName". # :proc create_answer_workflow {obj} { #:log "create_answer_workflow $obj" # first delete workflow and data, when it exists if {[$obj property wfName] ne ""} { set wf [:delete_all_answer_data $obj] if {$wf ne ""} {$wf delete} } # create a fresh workflow set wfName [$obj name].wf $obj set_property -new 1 wfName $wfName set wfMaster ${:masterWorkflow} set wfTitle [$obj property _title] set questionObjs [[[$obj wf_context] wf_container] get_questions $obj] set wfQuestionNames {} set wfQuestionTitles {} set attributeNames {} foreach form_obj $questionObjs { lappend attributeNames [xowf::test_item::renaming_form_loader \ form_name_based_attribute_stem [$form_obj name]] lappend wfQuestionNames ../[$form_obj name] lappend wfQuestionTitles [$form_obj title] } set wfID [$obj item_id] set wfDef [subst -nocommands { set wfID $wfID set wfTitle "$wfTitle" set wfQuestionNames [list $wfQuestionNames] set wfQuestionTitles [list $wfQuestionTitles] xowf::include /packages/xowf/lib/online-exam-answer.wf [list wfID wfTitle wfQuestionNames wfQuestionTitles] }] set attributeNames [join $attributeNames ,] #:log "create workflow by filling out form '$wfMaster'" set WF [::xowiki::Weblog instantiate_forms \ -parent_id [$obj parent_id] -package_id [$obj package_id] \ -default_lang [$obj lang] \ -forms $wfMaster] set f [$WF create_form_page_instance \ -name $wfName \ -nls_language [$obj nls_language] \ -publish_status ready \ -parent_id [$obj item_id] \ -package_id [$obj package_id] \ -default_variables [list title $wfTitle] \ -instance_attributes [list workflow_definition $wfDef \ form_constraints "@table:_name,_state,$attributeNames,_last_modified @cr_fields:hidden"]] $f save_new #:log "create_answer_workflow $obj DONE [$f pretty_link]" } ######################################################################## # get_answer_wf: return the workflow denoted by the property wfName in obj # :proc get_answer_wf {obj} { return [::xowiki::Weblog instantiate_forms \ -parent_id [$obj item_id] -package_id [$obj package_id] \ -default_lang [$obj lang] \ -forms [$obj property wfName]] } ######################################################################## # get_wf_instances: return the workflow instances # :proc get_wf_instances {{-initialize false} wf} { return [::xowiki::FormPage get_form_entries \ -base_item_ids [$wf item_id] -form_fields "" \ -always_queried_attributes "*" -initialize $initialize \ -publish_status all -package_id [$wf package_id]] } ######################################################################## # delete_all_answer_data: delete all instances of the answer workflow # :proc delete_all_answer_data {obj} { set wf [:get_answer_wf $obj] if {$wf ne ""} { set items [:get_wf_instances -initialize false $wf] foreach i [$items children] { $i delete } } return $wf } ######################################################################## # 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] util_user_message -html -message "[$obj name] is available as [ns_quotehtml $aLink]" # TODO: make it happen } ######################################################################## # unpublish_link: remove the user participation link for the target # group # Action instproc unpublish_link {obj} { util_user_message -html -message "[$obj name] is closed" # TODO: make it happen } ######################################################################## # get_questions: load and initialize the interaction forms # :proc get_questions {obj} { set questions [lmap ref [$obj property question] { if {![string match "*/*" $ref]} { set ref [[$obj parent_id] name]/$ref } set ref }] set questionNames [join $questions |] set questionForms [::xowiki::Weblog instantiate_forms \ -package_id [$obj package_id] \ -default_lang [$obj lang] \ -forms $questionNames] if {[llength $questionForms] < 1} { error "unknown form $questionNames" } #:msg "questionNames '$questionNames', questionForms 'questionForms'" return $questionForms } ######################################################################## # form loader: create dynamically a form containing the disabled # questions as a preview and the survey results (the results can be # refreshed). This is a simplified version of get_question_form_object # of online-exam-answer.wf. # :proc load_form {ctx title} { set obj [$ctx object] set state [$obj property _state] set questions [:get_questions $obj] set counter 0 set fullQuestionForm "" set full_fc {} foreach q $questions { set raw_form [$q property form] set raw_fc [$q property form_constraints] set newName answer$counter regsub {@answer@} $raw_form "@$newName@" formContent set fc [lmap f $raw_fc { if {[string match "answer:*" $f]} { regsub answer $f $newName f append f ,disabled=true } set f}] append fullQuestionForm \ "