Index: openacs-4/contrib/packages/simulation/sql/postgresql/simulation-tables-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/simulation/sql/postgresql/Attic/simulation-tables-create.sql,v diff -u -N -r1.21 -r1.22 --- openacs-4/contrib/packages/simulation/sql/postgresql/simulation-tables-create.sql 14 Jan 2004 10:18:10 -0000 1.21 +++ openacs-4/contrib/packages/simulation/sql/postgresql/simulation-tables-create.sql 19 Jan 2004 17:10:31 -0000 1.22 @@ -79,7 +79,7 @@ primary key(role_id, party_id) ); -comment on table sim_role_party_map is 'Each record defines a group of users to be cast into a role in groups of group_size'; +comment on table sim_role_party_map is 'Each record defines a group of users to be cast into a role'; create table sim_tasks ( task_id integer constraint sim_tasks_fk @@ -123,8 +123,6 @@ primary key (simulation_id, party_id, type) ); -comment on table sim_party_sim_map is 'Each record is an invitation to a party to participate in a simulation.'; - create table sim_case_task_object_map ( task_id integer constraint sctom_fk references workflow_actions Index: openacs-4/contrib/packages/simulation/tcl/template-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/simulation/tcl/Attic/template-procs.tcl,v diff -u -N -r1.52 -r1.53 --- openacs-4/contrib/packages/simulation/tcl/template-procs.tcl 16 Jan 2004 17:31:45 -0000 1.52 +++ openacs-4/contrib/packages/simulation/tcl/template-procs.tcl 19 Jan 2004 17:10:31 -0000 1.53 @@ -699,13 +699,49 @@ # TODO (3h): handle casting when casting_type is auto, and some users have enrolled, either through # invitation or because enroll_type is open. + # Get the list of all enrolled users that haven't been cast + set users_to_cast [db_list users_to_cast { + select distinct spsm.party_id, + from sim_party_sim_map spsm, + where spsm.simulation_id = :workflow_id + and spsm.type = 'enrolled' + and not exists (select 1 + from workflow_case_role_party_map wcrpm, + workflow_cases wc + where wcrpm.party_id = spsm.party_id + and wcrpm.case_id = wc.case_id + and wc.workflow_id = :workflow_id + ) + }] + + # Get the list of enrolled and uncast users that are not in any of the + # auto-cast groups + set users_to_cast_not_in_groups [db_list users_to_cast_not_in_groups { + select distinct spsm.party_id, + from sim_party_sim_map spsm, + where spsm.simulation_id = :workflow_id + and spsm.type = 'enrolled' + and not exists (select 1 + from workflow_case_role_party_map wcrpm, + workflow_cases wc + where wcrpm.party_id = spsm.party_id + and wcrpm.case_id = wc.case_id + and wc.workflow_id = :workflow_id + ) + and not exists (select 1 + from sim_party_sim_map spsm2, + party_approved_member_map pamm + where spsm2.party_id = pamm.party + and spsm2.type = 'auto-enroll' + and pamm.member_id = spsm.party_id + ) + }] + + # Build user lists for each of the groups mapped to roles (the auto-cast groups) simulation::template::role_party_mappings \ -workflow_id $workflow_id \ -array roles - # Build user lists for each of the groups mapped to a role and calculate the total number - # of users in the groups - set total_users 0 foreach role_id [array names roles] { array unset one_role array set one_role $roles($role_id) @@ -717,18 +753,16 @@ if { ![info exists group_members($group_id)] } { set group_members($group_id) [party::approved_members -party_id $group_id -object_type user] set group_members($group_id) [util::randomize_list $group_members($group_id)] - incr total_users [llength $group_members($group_id)] } } - } + } set workflow_short_name [workflow::get_element -workflow_id $workflow_id -element short_name] + # Create the cases and for each case assign users to roles set case_counter 0 + while { [llength $users_to_cast] > 0 } { - # Create the cases and for each case assign users to roles - while { $total_users > 0 } { - incr case_counter set sim_case_id [simulation::case::new \ -workflow_id $workflow_id \ @@ -746,32 +780,64 @@ set assignees [list] for { set i 0 } { $i < $one_role(users_per_case) } { incr i } { - # Get user from random group mapped to role - set group_id [lindex [util::randomize_list $one_role(parties)] 0] + # Get user from random non-empty group mapped to role + foreach group_id [util::randomize_list $one_role(parties)] { + # Remove users from the list that have already been cast + set not_cast_list [list] + foreach user_id $group_members($group_id) { + if { [lsearch -exact $users_to_cast $user_id] != -1 } { + lappend not_cast_list $user_id + } + } + set group_members($group_id) $not_cast_list + if { [llength $group_members($group_id)] > 0 } { + break + } + } + if { [llength $group_members($group_id)] > 0 } { - # Add assignee - lappend assignees [lindex $group_members($group_id) 0] + # There is a role group with at least one user that hasn't been cast. + # Cast a random user from that group + set user_id [lindex $group_members($group_id) 0] + lappend assignees $user_id + # Remove the user from the group member list set group_members($group_id) [lreplace $group_members($group_id) 0 0] - # Reduce the total_users count - incr total_users -1 + + # Remove the user from the users_to_cast_list + set cast_list_index [lsearch -exact $users_to_cast_list $user_id] + set users_to_cast [lreplace $user_to_cast $cast_list_index $cast_list_index] + } else { - # Current group exhausted, use current user - lappend assignees [ad_conn user_id] - # Don't add the admin more than once - break + # There is no group mapped to the role with a user that hasn't been cast + + # Are there any uncast users who are not in any groups? + if { [llength $users_to_cast_not_in_groups] > 0 } { + # Fill the role with a user not in any of the role groups + set user_id [lindex $users_to_cast_not_in_groups 0] + lappend assignees $user_id + + # Remove user from the not-in-group list + set users_to_cast_not_in_groups [lreplace $users_to_cast_not_in_gruops 0 0] + + # Remove the user from the users_to_cast_list + set cast_list_index [lsearch -exact $users_to_cast_list $user_id] + set users_to_cast [lreplace $user_to_cast $cast_list_index $cast_list_index] + + } else { + # No more users to cast, use current user (admin) + + lappend assignees [ad_conn user_id] + # Don't add the admin more than once + break + } } } set row($role_short_name($role_id)) $assignees } - #foreach { short_name users } { - # Remove duplicates, otherwise the call below bombs - # set role($short_name) [lsort -unique $role($short_name)] - #} - workflow::case::role::assign \ -case_id $case_id \ -array row \ Index: openacs-4/contrib/packages/simulation/www/siminst/simulation-edit.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/simulation/www/siminst/Attic/simulation-edit.tcl,v diff -u -N -r1.11 -r1.12 --- openacs-4/contrib/packages/simulation/www/siminst/simulation-edit.tcl 14 Jan 2004 15:10:54 -0000 1.11 +++ openacs-4/contrib/packages/simulation/www/siminst/simulation-edit.tcl 19 Jan 2004 17:10:32 -0000 1.12 @@ -128,7 +128,7 @@ set error_p 1 } if { [clock scan $enroll_end] > [clock scan $case_start] } { - template::form::set_error simulation enroll_start "Enrollment start date must be before simulation start date" + template::form::set_error simulation enroll_end "Enrollment end date must be before simulation start date" set error_p 1 } if { [clock scan $enroll_start] > [clock scan $enroll_end] } { Index: openacs-4/contrib/packages/simulation/www/simplay/cast.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/simulation/www/simplay/Attic/cast.adp,v diff -u -N -r1.4 -r1.5 --- openacs-4/contrib/packages/simulation/www/simplay/cast.adp 19 Jan 2004 14:02:33 -0000 1.4 +++ openacs-4/contrib/packages/simulation/www/simplay/cast.adp 19 Jan 2004 17:10:32 -0000 1.5 @@ -34,7 +34,7 @@

- +

TODO: If casting type is group instead of open, do not display or group Index: openacs-4/contrib/packages/simulation/www/simplay/enroll.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/contrib/packages/simulation/www/simplay/Attic/enroll.tcl,v diff -u -N -r1.4 -r1.5 --- openacs-4/contrib/packages/simulation/www/simplay/enroll.tcl 16 Jan 2004 17:31:45 -0000 1.4 +++ openacs-4/contrib/packages/simulation/www/simplay/enroll.tcl 19 Jan 2004 17:10:32 -0000 1.5 @@ -12,9 +12,20 @@ simulation::template::get -workflow_id $workflow_id -array simulation +if { ![string equal $simulation(sim_type) "casting_sim"] } { + ad_return_forbidden "Cannot enroll in simulation" "Simulation \"$simulation(pretty_name)\" is in state $simulation(sim_type) and you cannot enroll in it now. Contact your administrator if you believe this is an error. Thank you!" + ad_script_abort +} + # Check that the user has permission to enroll if { [string equal $simulation(enroll_type) "open"] } { # Open simulation - anybody can enroll so the user is authorized + # Check that we are within the enrollment period + if { [clock scan $simulation(enroll_start)] > [clock seconds] || [clock scan $simulation(enroll_end)] < [clock seconds] } { + # We are not in the enrollment period + ad_return_forbidden "Cannot enroll in simulation" "The enrollment period for simulation \"$simulation(pretty_name)\" is between $simulation(enroll_start) and $simulation(enroll_end) and you cannot enroll at this time. Contact your administrator if you believe this is an error. Thank you!" + ad_script_abort + } } else { # Closed enrollment. The user needs to be invited to enroll set user_invited_p [simulation::template::user_invited_p -workflow_id $workflow_id] Index: openacs-4/packages/simulation/sql/postgresql/simulation-tables-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/simulation/sql/postgresql/simulation-tables-create.sql,v diff -u -N -r1.21 -r1.22 --- openacs-4/packages/simulation/sql/postgresql/simulation-tables-create.sql 14 Jan 2004 10:18:10 -0000 1.21 +++ openacs-4/packages/simulation/sql/postgresql/simulation-tables-create.sql 19 Jan 2004 17:10:31 -0000 1.22 @@ -79,7 +79,7 @@ primary key(role_id, party_id) ); -comment on table sim_role_party_map is 'Each record defines a group of users to be cast into a role in groups of group_size'; +comment on table sim_role_party_map is 'Each record defines a group of users to be cast into a role'; create table sim_tasks ( task_id integer constraint sim_tasks_fk @@ -123,8 +123,6 @@ primary key (simulation_id, party_id, type) ); -comment on table sim_party_sim_map is 'Each record is an invitation to a party to participate in a simulation.'; - create table sim_case_task_object_map ( task_id integer constraint sctom_fk references workflow_actions Index: openacs-4/packages/simulation/tcl/template-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/simulation/tcl/template-procs.tcl,v diff -u -N -r1.52 -r1.53 --- openacs-4/packages/simulation/tcl/template-procs.tcl 16 Jan 2004 17:31:45 -0000 1.52 +++ openacs-4/packages/simulation/tcl/template-procs.tcl 19 Jan 2004 17:10:31 -0000 1.53 @@ -699,13 +699,49 @@ # TODO (3h): handle casting when casting_type is auto, and some users have enrolled, either through # invitation or because enroll_type is open. + # Get the list of all enrolled users that haven't been cast + set users_to_cast [db_list users_to_cast { + select distinct spsm.party_id, + from sim_party_sim_map spsm, + where spsm.simulation_id = :workflow_id + and spsm.type = 'enrolled' + and not exists (select 1 + from workflow_case_role_party_map wcrpm, + workflow_cases wc + where wcrpm.party_id = spsm.party_id + and wcrpm.case_id = wc.case_id + and wc.workflow_id = :workflow_id + ) + }] + + # Get the list of enrolled and uncast users that are not in any of the + # auto-cast groups + set users_to_cast_not_in_groups [db_list users_to_cast_not_in_groups { + select distinct spsm.party_id, + from sim_party_sim_map spsm, + where spsm.simulation_id = :workflow_id + and spsm.type = 'enrolled' + and not exists (select 1 + from workflow_case_role_party_map wcrpm, + workflow_cases wc + where wcrpm.party_id = spsm.party_id + and wcrpm.case_id = wc.case_id + and wc.workflow_id = :workflow_id + ) + and not exists (select 1 + from sim_party_sim_map spsm2, + party_approved_member_map pamm + where spsm2.party_id = pamm.party + and spsm2.type = 'auto-enroll' + and pamm.member_id = spsm.party_id + ) + }] + + # Build user lists for each of the groups mapped to roles (the auto-cast groups) simulation::template::role_party_mappings \ -workflow_id $workflow_id \ -array roles - # Build user lists for each of the groups mapped to a role and calculate the total number - # of users in the groups - set total_users 0 foreach role_id [array names roles] { array unset one_role array set one_role $roles($role_id) @@ -717,18 +753,16 @@ if { ![info exists group_members($group_id)] } { set group_members($group_id) [party::approved_members -party_id $group_id -object_type user] set group_members($group_id) [util::randomize_list $group_members($group_id)] - incr total_users [llength $group_members($group_id)] } } - } + } set workflow_short_name [workflow::get_element -workflow_id $workflow_id -element short_name] + # Create the cases and for each case assign users to roles set case_counter 0 + while { [llength $users_to_cast] > 0 } { - # Create the cases and for each case assign users to roles - while { $total_users > 0 } { - incr case_counter set sim_case_id [simulation::case::new \ -workflow_id $workflow_id \ @@ -746,32 +780,64 @@ set assignees [list] for { set i 0 } { $i < $one_role(users_per_case) } { incr i } { - # Get user from random group mapped to role - set group_id [lindex [util::randomize_list $one_role(parties)] 0] + # Get user from random non-empty group mapped to role + foreach group_id [util::randomize_list $one_role(parties)] { + # Remove users from the list that have already been cast + set not_cast_list [list] + foreach user_id $group_members($group_id) { + if { [lsearch -exact $users_to_cast $user_id] != -1 } { + lappend not_cast_list $user_id + } + } + set group_members($group_id) $not_cast_list + if { [llength $group_members($group_id)] > 0 } { + break + } + } + if { [llength $group_members($group_id)] > 0 } { - # Add assignee - lappend assignees [lindex $group_members($group_id) 0] + # There is a role group with at least one user that hasn't been cast. + # Cast a random user from that group + set user_id [lindex $group_members($group_id) 0] + lappend assignees $user_id + # Remove the user from the group member list set group_members($group_id) [lreplace $group_members($group_id) 0 0] - # Reduce the total_users count - incr total_users -1 + + # Remove the user from the users_to_cast_list + set cast_list_index [lsearch -exact $users_to_cast_list $user_id] + set users_to_cast [lreplace $user_to_cast $cast_list_index $cast_list_index] + } else { - # Current group exhausted, use current user - lappend assignees [ad_conn user_id] - # Don't add the admin more than once - break + # There is no group mapped to the role with a user that hasn't been cast + + # Are there any uncast users who are not in any groups? + if { [llength $users_to_cast_not_in_groups] > 0 } { + # Fill the role with a user not in any of the role groups + set user_id [lindex $users_to_cast_not_in_groups 0] + lappend assignees $user_id + + # Remove user from the not-in-group list + set users_to_cast_not_in_groups [lreplace $users_to_cast_not_in_gruops 0 0] + + # Remove the user from the users_to_cast_list + set cast_list_index [lsearch -exact $users_to_cast_list $user_id] + set users_to_cast [lreplace $user_to_cast $cast_list_index $cast_list_index] + + } else { + # No more users to cast, use current user (admin) + + lappend assignees [ad_conn user_id] + # Don't add the admin more than once + break + } } } set row($role_short_name($role_id)) $assignees } - #foreach { short_name users } { - # Remove duplicates, otherwise the call below bombs - # set role($short_name) [lsort -unique $role($short_name)] - #} - workflow::case::role::assign \ -case_id $case_id \ -array row \ Index: openacs-4/packages/simulation/www/siminst/simulation-edit.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/simulation/www/siminst/simulation-edit.tcl,v diff -u -N -r1.11 -r1.12 --- openacs-4/packages/simulation/www/siminst/simulation-edit.tcl 14 Jan 2004 15:10:54 -0000 1.11 +++ openacs-4/packages/simulation/www/siminst/simulation-edit.tcl 19 Jan 2004 17:10:32 -0000 1.12 @@ -128,7 +128,7 @@ set error_p 1 } if { [clock scan $enroll_end] > [clock scan $case_start] } { - template::form::set_error simulation enroll_start "Enrollment start date must be before simulation start date" + template::form::set_error simulation enroll_end "Enrollment end date must be before simulation start date" set error_p 1 } if { [clock scan $enroll_start] > [clock scan $enroll_end] } { Index: openacs-4/packages/simulation/www/simplay/cast.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/simulation/www/simplay/cast.adp,v diff -u -N -r1.4 -r1.5 --- openacs-4/packages/simulation/www/simplay/cast.adp 19 Jan 2004 14:02:33 -0000 1.4 +++ openacs-4/packages/simulation/www/simplay/cast.adp 19 Jan 2004 17:10:32 -0000 1.5 @@ -34,7 +34,7 @@

- +

TODO: If casting type is group instead of open, do not display or group Index: openacs-4/packages/simulation/www/simplay/enroll.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/simulation/www/simplay/enroll.tcl,v diff -u -N -r1.4 -r1.5 --- openacs-4/packages/simulation/www/simplay/enroll.tcl 16 Jan 2004 17:31:45 -0000 1.4 +++ openacs-4/packages/simulation/www/simplay/enroll.tcl 19 Jan 2004 17:10:32 -0000 1.5 @@ -12,9 +12,20 @@ simulation::template::get -workflow_id $workflow_id -array simulation +if { ![string equal $simulation(sim_type) "casting_sim"] } { + ad_return_forbidden "Cannot enroll in simulation" "Simulation \"$simulation(pretty_name)\" is in state $simulation(sim_type) and you cannot enroll in it now. Contact your administrator if you believe this is an error. Thank you!" + ad_script_abort +} + # Check that the user has permission to enroll if { [string equal $simulation(enroll_type) "open"] } { # Open simulation - anybody can enroll so the user is authorized + # Check that we are within the enrollment period + if { [clock scan $simulation(enroll_start)] > [clock seconds] || [clock scan $simulation(enroll_end)] < [clock seconds] } { + # We are not in the enrollment period + ad_return_forbidden "Cannot enroll in simulation" "The enrollment period for simulation \"$simulation(pretty_name)\" is between $simulation(enroll_start) and $simulation(enroll_end) and you cannot enroll at this time. Contact your administrator if you believe this is an error. Thank you!" + ad_script_abort + } } else { # Closed enrollment. The user needs to be invited to enroll set user_invited_p [simulation::template::user_invited_p -workflow_id $workflow_id]