Index: openacs-4/packages/workflow/workflow.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/workflow.info,v diff -u -r1.2 -r1.3 --- openacs-4/packages/workflow/workflow.info 14 Jan 2003 15:08:54 -0000 1.2 +++ openacs-4/packages/workflow/workflow.info 21 Jan 2003 18:05:20 -0000 1.3 @@ -26,6 +26,7 @@ + @@ -35,8 +36,12 @@ + + + + Index: openacs-4/packages/workflow/sql/postgresql/workflow-procedural-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/sql/postgresql/workflow-procedural-create.sql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/workflow/sql/postgresql/workflow-procedural-create.sql 14 Jan 2003 15:09:07 -0000 1.2 +++ openacs-4/packages/workflow/sql/postgresql/workflow-procedural-create.sql 21 Jan 2003 18:05:48 -0000 1.3 @@ -23,42 +23,45 @@ -- Function for creating a workflow -create function workflow__new (varchar, -- short_name - varchar, -- pretty_name - integer, -- object_id - varchar, -- object_type - integer, -- creation_user - varchar, -- creation_ip - integer -- context_id - ) +create function workflow__new ( + varchar, -- short_name + varchar, -- pretty_name + varchar, -- package_key + integer, -- object_id + varchar, -- object_type + integer, -- creation_user + varchar, -- creation_ip + integer -- context_id +) returns integer as ' declare - p_short_name alias for $1; - p_pretty_name alias for $2; - p_object_id alias for $3; - p_object_type alias for $4; - p_creation_user alias for $5; - p_creation_ip alias for $6; - p_context_id alias for $7; - - v_workflow_id integer; + p_short_name alias for $1; + p_pretty_name alias for $2; + p_package_key alias for $3; + p_object_id alias for $4; + p_object_type alias for $5; + p_creation_user alias for $6; + p_creation_ip alias for $7; + p_context_id alias for $8; + + v_workflow_id integer; begin - -- Instantiate the ACS Object super type with auditing info - v_workflow_id := acs_object__new(null, - ''workflow_lite'', - now(), - p_creation_user, - p_creation_ip, - p_context_id, - ''t''); + -- Instantiate the ACS Object super type with auditing info + v_workflow_id := acs_object__new(null, + ''workflow_lite'', + now(), + p_creation_user, + p_creation_ip, + p_context_id, + ''t''); - -- Insert workflow specific info into the workflows table - insert into workflows - (workflow_id, short_name, pretty_name, object_id, object_type) - values - (v_workflow_id, p_short_name, p_pretty_name, p_object_id, p_object_type); - + -- Insert workflow specific info into the workflows table + insert into workflows + (workflow_id, short_name, pretty_name, package_key, object_id, object_type) + values + (v_workflow_id, p_short_name, p_pretty_name, p_package_key, p_object_id, p_object_type); + - return v_workflow_id; + return v_workflow_id; end; ' language 'plpgsql'; Index: openacs-4/packages/workflow/sql/postgresql/workflow-tables-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/sql/postgresql/workflow-tables-create.sql,v diff -u -r1.4 -r1.5 --- openacs-4/packages/workflow/sql/postgresql/workflow-tables-create.sql 20 Jan 2003 15:44:59 -0000 1.4 +++ openacs-4/packages/workflow/sql/postgresql/workflow-tables-create.sql 21 Jan 2003 18:05:48 -0000 1.5 @@ -56,11 +56,12 @@ constraint workflows_pretty_name_nn not null, object_id integer - constraint workflows_object_id_nn - not null constraint workflows_object_id_fk references acs_objects(object_id) on delete cascade, + package_key varchar(100) + constraint workflows_apm_package_types_fk + references apm_package_types(package_key), -- object_id points to either a package type, package instance, or single workflow case -- For Bug Tracker, every package instance will get its own workflow instance that is a copy -- of the workflow instance for the Bug Tracker package type @@ -70,30 +71,28 @@ constraint workflows_object_type_fk references acs_object_types(object_type) on delete cascade, - -- the object type (and its subtypes) this workflow is designed for. Use acs_object - -- if you don't want to restrict the types of objects this workflow can be applied to. constraint workflows_oid_sn_un unique (object_id, short_name) ); --- For callback procedures that execute when any action in the workflow is taken -create table workflow_side_effects ( +-- For callbacks on workflow +create table workflow_callbacks ( workflow_id integer - constraint workflow_side_effects_wid_nn + constraint workflow_callbacks_wid_nn not null - constraint workflow_side_effects_wid_fk + constraint workflow_callbacks_wid_fk references workflows(workflow_id) on delete cascade, acs_sc_impl_id integer - constraint workflow_side_effects_sci_nn + constraint workflow_callbacks_sci_nn not null - constraint workflow_side_effects_sci_fk + constraint workflow_callbacks_sci_fk references acs_sc_impls(impl_id) on delete cascade, sort_order integer - constraint workflow_side_effects_so_nn + constraint workflow_callbacks_so_nn not null, - constraint workflow_side_effects_pk + constraint workflow_callbacks_pk primary key (workflow_id, acs_sc_impl_id) ); @@ -151,28 +150,30 @@ primary key (role_id, party_id) ); --- Application specific callback procedures for dynamically mapping parties to roles -create table workflow_role_assignment_rules ( +-- Callbacks for roles +create table workflow_role_callbacks ( role_id integer - constraint workflow_role_assignment_rules_role_id_nn + constraint workflow_role_callbacks_role_id_nn not null - constraint workflow_role_assignment_rules_role_id_fk + constraint workflow_role_callbacks_role_id_fk references workflow_roles(role_id) on delete cascade, acs_sc_impl_id integer - constraint workflow_role_assignment_rules_contract_id_nn + constraint workflow_role_callbacks_contract_id_nn not null - constraint workflow_role_assignment_rules_contract_id_fk + constraint workflow_role_callbacks_contract_id_fk references acs_sc_impls(impl_id) on delete cascade, - -- this can be an implementation of any of the three assignment + -- this should be an implementation of any of the three assignment -- service contracts: DefaultAssignee, AssigneePickList, or -- AssigneeSubQuery sort_order integer - constraint workflow_role_assignment_rules_sort_order_nn + constraint workflow_role_callbacks_sort_order_nn not null, - constraint workflow_role_assignment_rules_pk - primary key (role_id, acs_sc_impl_id) + constraint workflow_role_callbacks_pk + primary key (role_id, acs_sc_impl_id), + constraint workflow_role_asgn_rol_sort_un + unique (role_id, sort_order) ); create table workflow_actions ( @@ -241,25 +242,24 @@ primary key (action_id, privilege) ); --- For application specific callback procedures that execute when --- certain actions are taken -create table workflow_action_side_effects ( +-- For callbacks on actions +create table workflow_action_callbacks ( action_id integer - constraint workflow_action_side_effects_action_id_nn + constraint workflow_action_callbacks_action_id_nn not null - constraint workflow_action_side_effects_action_id_fk + constraint workflow_action_callbacks_action_id_fk references workflow_actions(action_id) on delete cascade, acs_sc_impl_id integer - constraint workflow_action_side_effects_sci_nn + constraint workflow_action_callbacks_sci_nn not null - constraint workflow_action_side_effects_sci_fk + constraint workflow_action_callbacks_sci_fk references acs_sc_impls(impl_id) on delete cascade, sort_order integer - constraint workflow_action_side_effects_sort_order_nn + constraint workflow_action_callbacks_sort_order_nn not null, - constraint workflow_action_side_effects_pk + constraint workflow_action_callbacks_pk primary key (action_id, acs_sc_impl_id) ); Index: openacs-4/packages/workflow/sql/postgresql/workflow-tables-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/sql/postgresql/workflow-tables-drop.sql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/workflow/sql/postgresql/workflow-tables-drop.sql 14 Jan 2003 15:09:07 -0000 1.2 +++ openacs-4/packages/workflow/sql/postgresql/workflow-tables-drop.sql 21 Jan 2003 18:05:48 -0000 1.3 @@ -48,15 +48,15 @@ drop table workflow_fsm_actions; drop table workflow_initial_action; drop table workflow_fsm_states; -drop table workflow_action_side_effects; +drop table workflow_action_callbacks; drop table workflow_action_privileges; drop table workflow_action_allowed_roles; drop table workflow_actions; -drop table workflow_role_assignment_rules; +drop table workflow_role_callbacks; drop table workflow_role_allowed_parties; drop table workflow_role_default_parties; drop table workflow_roles; -drop table workflow_side_effects; +drop table workflow_callbacks; drop table workflows; -- Drop sequences Index: openacs-4/packages/workflow/tcl/action-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/action-procs.tcl,v diff -u -r1.3 -r1.4 --- openacs-4/packages/workflow/tcl/action-procs.tcl 20 Jan 2003 15:45:00 -0000 1.3 +++ openacs-4/packages/workflow/tcl/action-procs.tcl 21 Jan 2003 18:06:00 -0000 1.4 @@ -10,14 +10,16 @@ namespace eval workflow::action {} namespace eval workflow:::action::fsm {} + + + ##### # # workflow::action namespace # ##### ad_proc -public workflow::action::new { - -initial_action:boolean {-workflow_id:required} {-sort_order {}} {-short_name:required} @@ -26,7 +28,9 @@ {-assigned_role {}} {-allowed_roles {}} {-privileges {}} + {-callbacks {}} {-always_enabled_p f} + {-initial_action:boolean} } { This procedure is normally not invoked from application code. Instead a procedure for a certain workflow implementation, such as for example @@ -47,6 +51,8 @@ treated by the workflow (i.e. a bug in the Bug Tracker) will be allowed to take this action. + @param callbacks List of names of service contract implementations of callbacks for the action in + impl_owner_name.impl_name format. @param initial_action Use this switch to indicate that this is the initial action that will fire whenever a case of the workflow is created. The initial action is used to determine @@ -62,15 +68,22 @@ db_transaction { # Insert basic action info if { [empty_string_p $sort_order] } { - set sort_order [workflow::default_sort_order -workflow_id $workflow_id workflow_actions] + set sort_order [workflow::default_sort_order \ + -workflow_id $workflow_id \ + -table_name "workflow_actions"] } + set action_id [db_nextval "workflow_actions_seq"] + if { [empty_string_p $assigned_role] } { set assigned_role_id [db_null] } else { - set assigned_role_id [workflow::role::get_id -workflow_id $workflow_id \ - -short_name $assigned_role] + set assigned_role_id [workflow::role::get_id \ + -workflow_id $workflow_id \ + -short_name $assigned_role] } + + # Insert the action db_dml insert_action {} # Record which roles are allowed to take action @@ -87,6 +100,14 @@ if { $initial_action_p } { db_dml insert_initial_action {} } + + # Callbacks + foreach callback_name $callbacks { + workflow::action::callback_insert \ + -action_id $action_id \ + -name $callback_name + } + } return $action_id @@ -137,6 +158,7 @@ ad_proc -public workflow::action::get { {-action_id:required} + {-array:required} } { Return information about an action with a given id. @@ -146,36 +168,71 @@ pretty_past_tense, assigned_role, and always_enabled_p column values for an action. } { - db_1row action_info {} -column_array action_info + # Select the info into the upvar'ed Tcl Array + upvar $array row - return [array get action_info] + db_1row action_info {} -column_array row } +ad_proc -public workflow::action::callback_insert { + {-action_id:required} + {-name:required} + {-sort_order {}} +} { + Add a side-effect to an action. + + @param action_id The ID of the action. + @param name Name of service contract implementation, in the form (impl_owner_name).(impl_name), + for example, bug-tracker.CaptureResolutionCode + @param sort_order The sort_order for the rule. Leave blank to add to the end of the list + + @author Lars Pind (lars@collaboraid.biz) +} { + # TODO: + # Insert for real when the service contracts have been defined + + ns_log Error "LARS: workflow::action::callback_insert -- would have inserted the callback $name to action $action_id" + return + db_transaction { + + # Get the impl_id + set acs_sc_impl_id [workflow::service_contract::get_impl_id -name $name] + + # Get the sort order + if { ![exists_and_not_null sort_order] } { + set sort_order [db_string select_sort_order {}] + } + + # Insert the callback + db_dml insert_callback {} + } + return $acs_sc_impl_id +} + + + + + ##### # # workflow::action::fsm # ##### -##### -# -# workflow::fsm::action namespace -# -##### - ad_proc -public workflow::action::fsm::new { - -initial_action:boolean {-workflow_id:required} {-short_name:required} {-pretty_name:required} {-pretty_past_tense {}} {-allowed_roles {}} {-assigned_role {}} {-privileges {}} - {-always_enabled_p f} {-enabled_states {}} {-new_state {}} + {-callbacks {}} + {-always_enabled_p f} + {-initial_action:boolean} } { Add an action to a certain FSM (Finite State Machine) workflow. This procedure invokes the generic workflow::action::new procedures and does additional inserts @@ -194,31 +251,35 @@ db_transaction { # Generic workflow data: - set action_id [workflow::action::new -initial_action=$initial_action_p \ - -workflow_id $workflow_id \ - -short_name $short_name \ - -pretty_name $pretty_name \ - -pretty_past_tense $pretty_past_tense \ - -allowed_roles $allowed_roles \ - -assigned_role $assigned_role \ - -privileges $privileges \ - -always_enabled_p $always_enabled_p] + set action_id [workflow::action::new \ + -initial_action=$initial_action_p \ + -workflow_id $workflow_id \ + -short_name $short_name \ + -pretty_name $pretty_name \ + -pretty_past_tense $pretty_past_tense \ + -allowed_roles $allowed_roles \ + -assigned_role $assigned_role \ + -privileges $privileges \ + -callbacks $callbacks \ + -always_enabled_p $always_enabled_p] # FSM specific data: # Record whether the action changes state if { ![empty_string_p $new_state] } { - set new_state_id [workflow::state::fsm::get_id -workflow_id $workflow_id \ - -short_name $new_state] + set new_state_id [workflow::state::fsm::get_id \ + -workflow_id $workflow_id \ + -short_name $new_state] } else { set new_state_id [db_null] } db_dml insert_fsm_action {} # Record in which states the action is enabled foreach state_short_name $enabled_states { - set enabled_state_id [workflow::state::fsm::get_id -workflow_id $workflow_id \ - -short_name $state_short_name] + set enabled_state_id [workflow::state::fsm::get_id \ + -workflow_id $workflow_id \ + -short_name $state_short_name] db_dml insert_enabled_state {} } } @@ -233,3 +294,73 @@ } { return [db_string select_new_state {} -default {}] } + + +ad_proc -private workflow::action::fsm::parse_spec { + {-workflow_id:required} + {-short_name:required} + {-spec:required} +} { + Parse the spec for an individual action definition. + + @param workflow_id The id of the workflow to delete. + @param short_name The short_name of the action + @param spec The action spec + + @author Lars Pind (lars@collaboraid.biz) +} { + # Initialize array with default values + array set action { + pretty_past_tense {} + allowed_roles {} + assigned_role {} + privileges {} + always_enabled_p f + enabled_states {} + new_state {} + initial_action_p 0 + } + + # Get the info from the spec + array set action $spec + + # Create the action + set action_id [workflow::action::fsm::new \ + -workflow_id $workflow_id \ + -short_name $short_name \ + -pretty_name $action(pretty_name) \ + -pretty_past_tense $action(pretty_past_tense) \ + -allowed_roles $action(allowed_roles) \ + -assigned_role $action(assigned_role) \ + -privileges $action(privileges) \ + -always_enabled_p $action(always_enabled_p) \ + -enabled_states $action(enabled_states) \ + -new_state $action(new_state) \ + -initial_action=$action(initial_action_p) \ + ] +} + +ad_proc -private workflow::action::fsm::parse_actions_spec { + {-workflow_id:required} + {-spec:required} +} { + Parse the spec for the block containing the definition of all + actions for the workflow. + + @param workflow_id The id of the workflow to delete. + @param spec The actions spec + + @author Lars Pind (lars@collaboraid.biz) +} { + # actions(short_name) { ... action-spec ... } + array set actions $spec + + foreach short_name [array names actions] { + workflow::action::fsm::parse_spec \ + -workflow_id $workflow_id \ + -short_name $short_name \ + -spec $actions($short_name) + } +} + + Index: openacs-4/packages/workflow/tcl/action-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/action-procs.xql,v diff -u -r1.3 -r1.4 --- openacs-4/packages/workflow/tcl/action-procs.xql 20 Jan 2003 15:45:00 -0000 1.3 +++ openacs-4/packages/workflow/tcl/action-procs.xql 21 Jan 2003 18:06:00 -0000 1.4 @@ -85,6 +85,23 @@ + + + select coalesce(max(sort_order)) + 1 + from workflow_action_callbacks + where action_id = :action_id + + + + + + insert into workflow_action_callbacks (action_id, acs_sc_impl_id, sort_order) + values (:action_id, :acs_sc_impl_id, :sort_order) + + + + + insert into workflow_fsm_actions Index: openacs-4/packages/workflow/tcl/case-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/case-procs.tcl,v diff -u -r1.2 -r1.3 --- openacs-4/packages/workflow/tcl/case-procs.tcl 20 Jan 2003 15:45:00 -0000 1.2 +++ openacs-4/packages/workflow/tcl/case-procs.tcl 21 Jan 2003 18:06:00 -0000 1.3 @@ -74,7 +74,7 @@ # Execute the initial action workflow::case::action::execute \ -case_id $case_id \ - -action_id [workflow::action::get_initial_action -workflow_id $workflow_id] \ + -action_id [workflow::get_initial_action -workflow_id $workflow_id] \ -comment $comment \ -comment_format $comment_format \ -user_id $user_id \ @@ -101,7 +101,7 @@ if { $found_p } { return $case_id } else { - return {} + error "No matching workflow case found for object_id $object_id and workflow_short_name $workflow_short_name" } } @@ -155,16 +155,14 @@ return $action_list } -ad_proc -public workflow::case::get_user_actions { +ad_proc -public workflow::case::get_available_actions { {-case_id:required} -user_id } { - Get the currently enabled actions, which the user has permission - to execute. + Get the actions which are enabled and which the current user have permission to execute. @param case_id The ID of the case. - @return A list of id:s of the actions - which are currently enabled + @return A list of ID's of the available actions. @author Lars Pind (lars@collaboraid.biz) } { @@ -237,7 +235,7 @@ set object_id [workflow::case::get_object_id -case_id $case_id] - db_foreach select_assignment_rules {} { + db_foreach select_callbacks {} { # Run the service contract set party_id_list [acs_sc_call $contract_name "GetAssignees" [list $case_id $object_id $role_id] $impl_name] Index: openacs-4/packages/workflow/tcl/case-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/case-procs.xql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/workflow/tcl/case-procs.xql 20 Jan 2003 15:45:00 -0000 1.2 +++ openacs-4/packages/workflow/tcl/case-procs.xql 21 Jan 2003 18:06:00 -0000 1.3 @@ -53,24 +53,22 @@ - select distinct action_id - from (select waeis.action_id - from workflow_cases c, - workflow_case_fsm cfsm, - workflow_fsm_action_enabled_in_states waeis - where c.case_id = :case_id - and cfsm.case_id = c.case_id - and waeis.state_id = cfsm.current_state - - union - - select a.action_id - from workflow_cases c, - workflow_actions a - where c.case_id = :case_id - and a.workflow_id = c.workflow_id - and a.always_enabled_p = 't' - ) enabled_actions + select a.action_id + from workflow_cases c, + workflow_actions a + where c.case_id = :case_id + and a.workflow_id = c.workflow_id + and not exists (select 1 + from workflow_initial_action wia + where wia.workflow_id = c.workflow_id + and wia.action_id = a.action_id) + and (a.always_enabled_p = 't' + or exists (select 1 + from workflow_case_fsm cfsm, + workflow_fsm_action_enabled_in_states waeis + where cfsm.case_id = c.case_id + and waeis.state_id = cfsm.current_state + and waeis.action_id = a.action_id)) @@ -83,10 +81,10 @@ - + select impl.impl_name - from workflow_role_assignment_rules r, + from workflow_role_callbacks r, acs_sc_impls impl, acs_sc_bindings bind, acs_sc_contracts ctr Fisheye: Tag 1.4 refers to a dead (removed) revision in file `openacs-4/packages/workflow/tcl/fsm-procs.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.4 refers to a dead (removed) revision in file `openacs-4/packages/workflow/tcl/fsm-procs.xql'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/workflow/tcl/role-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/role-procs.tcl,v diff -u -r1.3 -r1.4 --- openacs-4/packages/workflow/tcl/role-procs.tcl 20 Jan 2003 15:45:00 -0000 1.3 +++ openacs-4/packages/workflow/tcl/role-procs.tcl 21 Jan 2003 18:06:00 -0000 1.4 @@ -9,28 +9,71 @@ namespace eval workflow::role {} + + + ##### # # workflow::role namespace # ##### +ad_proc -private workflow::role::insert { + {-workflow_id:required} + {-short_name:required} + {-pretty_name:required} +} { + Inserts the DB row for a new role. You shouldn't normally be usin + this procedure, use workflow::role::new instead. + + @param workflow_id The ID of the workflow the new role belongs to + @param short_name The short_name of the new role + @param pretty_name The pretty name of the new role + @return The ID of the new role + + @author Lars Pind (lars@collaboraid.biz) + @see workflow::role::new +} { + db_transaction { + set role_id [db_nextval "workflow_roles_seq"] + db_dml do_insert {} + } + return $role_id +} + ad_proc -public workflow::role::new { {-workflow_id:required} {-short_name:required} {-pretty_name:required} + {-callbacks {}} } { - Creates a new role for a certain workflow. + Creates a new role for a workflow. - @param workflow_id - @param short_name - @param pretty_name + @param workflow_id The ID of the workflow the new role belongs to + @param short_name The short_name of the new role + @param pretty_name The pretty name of the new role + @param callbacks A list of names service-contract implementations. + @return The ID of the new role @author Peter Marklund + @author Lars Pind (lars@collaboraid.biz) } { - set role_id [db_nextval "workflow_roles_seq"] + db_transaction { + # Insert the role + set role_id [insert \ + -workflow_id $workflow_id \ + -short_name $short_name \ + -pretty_name $pretty_name\ + ] - db_dml do_insert {} + # Set up the assignment rules + foreach callback_name $callbacks { + workflow::role::callback_insert \ + -role_id $role_id \ + -name $callback_name + } + } + return $role_id } ad_proc -public workflow::role::get_id { @@ -45,3 +88,90 @@ } { return [db_string select_role_id {} -default {}] } + +ad_proc -private workflow::role::parse_spec { + {-workflow_id:required} + {-short_name:required} + {-spec:required} +} { + Parse the spec for an individual role definition. + + @param workflow_id The id of the workflow to delete. + @param short_name The short_name of the role + @param spec The roles spec + + @author Lars Pind (lars@collaboraid.biz) +} { + # Initialize array with default values + array set role { callbacks {} } + + # Get the info from the spec + array set role $spec + + # Create the role + set role_id [workflow::role::new \ + -workflow_id $workflow_id \ + -short_name $short_name \ + -pretty_name $role(pretty_name) \ + -callbacks $role(callbacks) + ] +} + +ad_proc -private workflow::role::parse_roles_spec { + {-workflow_id:required} + {-spec:required} +} { + Parse the spec for the block containing the definition of all + roles for the workflow. + + @param workflow_id The id of the workflow to delete. + @param spec The roles spec + + @author Lars Pind (lars@collaboraid.biz) +} { + # roles(short_name) { ... role-spec ... } + array set roles $spec + + foreach short_name [array names roles] { + workflow::role::parse_spec \ + -workflow_id $workflow_id \ + -short_name $short_name \ + -spec $roles($short_name) + } +} + +ad_proc -private workflow::role::callback_insert { + {-role_id:required} + {-name:required} + {-sort_order} +} { + Add an assignment rule to a role. + + @param role_id The ID of the role + @param name Name of service contract implementation, in the form (impl_owner_name).(impl_name), + for example, bug-tracker.ComponentMaintainer. + @param sort_order The sort_order for the rule. Leave blank to add to the end of the list + + @author Lars Pind (lars@collaboraid.biz) +} { + # TODO: + # Insert for real when the service contracts have been defined + + ns_log Error "LARS: workflow::role::callback_insert -- would have inserted the callback $name to role $role_id" + return + + db_transaction { + + # Get the impl_id + set acs_sc_impl_id [workflow::service_contract::get_impl_id -name $name] + + # Get the sort order + if { ![exists_and_not_null sort_order] } { + set sort_order [db_string select_sort_order {}] + } + + # Insert the rule + db_dml insert_rule {} + } + return $acs_sc_impl_id +} Index: openacs-4/packages/workflow/tcl/role-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/role-procs.xql,v diff -u -r1.3 -r1.4 --- openacs-4/packages/workflow/tcl/role-procs.xql 20 Jan 2003 15:45:00 -0000 1.3 +++ openacs-4/packages/workflow/tcl/role-procs.xql 21 Jan 2003 18:06:00 -0000 1.4 @@ -1,7 +1,7 @@ - + insert into workflow_roles (role_id, workflow_id, short_name, pretty_name) @@ -19,4 +19,21 @@ + + + select coalesce(max(sort_order)) + 1 + from workflow_role_callbacks + where role_id = :role_id + + + + + + insert into workflow_role_callbacks (role_id, acs_sc_impl_id, sort_order) + values (:role_id, :acs_sc_impl_id, :sort_order) + + + + + Index: openacs-4/packages/workflow/tcl/state-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/state-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/workflow/tcl/state-procs.tcl 21 Jan 2003 18:06:00 -0000 1.1 @@ -0,0 +1,125 @@ +ad_library { + Procedures in the workflow::fsm::state namespace and + in its child namespaces. + + @creation-date 8 January 2003 + @author Lars Pind (lars@collaboraid.biz) + @author Peter Marklund (peter@collaboraid.biz) + @cvs-id $Id: state-procs.tcl,v 1.1 2003/01/21 18:06:00 lars Exp $ +} + +namespace eval workflow::state::fsm {} + +##### +# +# workflow::state::fsm namespace +# +##### + +ad_proc -public workflow::state::fsm::new { + {-workflow_id:required} + {-short_name:required} + {-pretty_name:required} + {-sort_order {}} +} { + Creates a new state for a certain FSM (Finite State Machine) workflow. + + @param workflow_id The id of the FSM workflow to add the state to + @param short_name + @param pretty_name + @return ID of new state. + + @author Peter Marklund +} { + db_transaction { + + set state_id [db_nextval "workflow_fsm_states_seq"] + + if { [empty_string_p $sort_order] } { + set sort_order [workflow::default_sort_order -workflow_id $workflow_id -table_name "workflow_fsm_states"] + } + + db_dml do_insert {} + } + return $state_id +} + +ad_proc -public workflow::state::fsm::get { + {-state_id:required} + {-array:required} +} { + Return workflow_id, sort_order, short_name, and pretty_name for a certain + FSM workflow state. + + @author Peter Marklund +} { + # Select the info into the upvar'ed Tcl Array + upvar $array row + + db_1row state_info {} -column_array row +} + +ad_proc -public workflow::state::fsm::get_id { + {-workflow_id:required} + {-short_name:required} +} { + Return the id of the state with given short name + + @param workflow_id The id of the workflow the state belongs to. + @param short_name The name of the state to return the id for. + + @author Peter Marklund +} { + return [db_string select_id {}] +} + + +ad_proc -private workflow::state::fsm::parse_spec { + {-workflow_id:required} + {-short_name:required} + {-spec:required} +} { + Parse the spec for an individual state definition. + + @param workflow_id The id of the workflow to delete. + @param short_name The short_name of the state + @param spec The state spec + + @author Lars Pind (lars@collaboraid.biz) +} { + # Initialize array with default values + array set state {} + + # Get the info from the spec + array set state $spec + + # Create the state + set state_id [workflow::state::fsm::new \ + -workflow_id $workflow_id \ + -short_name $short_name \ + -pretty_name $state(pretty_name) + ] +} + +ad_proc -private workflow::state::fsm::parse_states_spec { + {-workflow_id:required} + {-spec:required} +} { + Parse the spec for the block containing the definition of all + states for the workflow. + + @param workflow_id The id of the workflow to delete. + @param spec The states spec + + @author Lars Pind (lars@collaboraid.biz) +} { + # states(short_name) { ... state-spec ... } + array set states $spec + + foreach short_name [array names states] { + workflow::state::fsm::parse_spec \ + -workflow_id $workflow_id \ + -short_name $short_name \ + -spec $states($short_name) + } +} Index: openacs-4/packages/workflow/tcl/state-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/state-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/workflow/tcl/state-procs.xql 21 Jan 2003 18:06:00 -0000 1.1 @@ -0,0 +1,32 @@ + + + + + + insert into workflow_fsm_states + (state_id, workflow_id, sort_order, short_name, pretty_name) + values (:state_id, :workflow_id, :sort_order, :short_name, :pretty_name) + + + + + + select workflow_id, + sort_order, + short_name, + pretty_name + from workflow_fsm_states + where state_id = :state_id + + + + + + select state_id + from workflow_fsm_states + where short_name = :short_name + and workflow_id = :workflow_id + + + + Index: openacs-4/packages/workflow/tcl/workflow-procs-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/workflow-procs-postgresql.xql,v diff -u -r1.3 -r1.4 --- openacs-4/packages/workflow/tcl/workflow-procs-postgresql.xql 20 Jan 2003 15:45:00 -0000 1.3 +++ openacs-4/packages/workflow/tcl/workflow-procs-postgresql.xql 21 Jan 2003 18:06:00 -0000 1.4 @@ -4,15 +4,16 @@ - select workflow__new (:short_name, - :pretty_name, - :object_id, - :object_type, - :creation_user, - :creation_ip, - :context_id - ); - + select workflow__new ( + :short_name, + :pretty_name, + :package_key, + :object_id, + :object_type, + :creation_user, + :creation_ip, + :context_id + ); Index: openacs-4/packages/workflow/tcl/workflow-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/workflow-procs.tcl,v diff -u -r1.3 -r1.4 --- openacs-4/packages/workflow/tcl/workflow-procs.tcl 20 Jan 2003 15:45:00 -0000 1.3 +++ openacs-4/packages/workflow/tcl/workflow-procs.tcl 21 Jan 2003 18:06:00 -0000 1.4 @@ -8,6 +8,7 @@ } namespace eval workflow {} +namespace eval workflow::fsm {} namespace eval workflow::service_contract {} ##### @@ -23,20 +24,25 @@ ad_proc -public workflow::new { {-short_name:required} {-pretty_name:required} - {-object_id:required} + {-package_key {}} + {-object_id {}} {-object_type "acs_object"} + {-callbacks {}} } { Creates a new workflow. For each workflow you must create an initial action (using the workflow::action::new proc) to be fired when a workflow case is opened. @param short_name For referring to the workflow from Tcl code. Use Tcl variable syntax. @param pretty_name A human readable name for the workflow for use in the UI. + @param package_key The package to which this workflow belongs @param object_id The id of an ACS Object indicating the scope the workflow. Typically this will be the id of a package type or a package instance but it could also be some other type of ACS object within a package, for example the id of a bug in the Bug Tracker application. @param object_type The type of objects that the workflow will be applied to. Valid values are in the acs_object_types table. The parameter is optional and defaults to acs_object. + @param callbacks List of names of service contract implementations of callbacks for the workflow in + impl_owner_name.impl_name format. @author Peter Marklund } { @@ -46,20 +52,64 @@ set creation_ip [ad_conn peeraddr] } else { # No HTTP request so we have don't have IP and user info - set creation_user "" - set creation_ip "" + set creation_user {} + set creation_ip {} } # It makes sense that the workflow inherits permissions from the object # (typically package type or package instance) that sets the scope of the workflow set context_id $object_id - # Insert the workflow - set workflow_id [db_string do_insert {}] + db_transaction { + if { [empty_string_p $package_key] } { + set package_key [db_null] + } + + if { [empty_string_p $object_id] } { + set object_id [db_null] + } + + # Insert the workflow + set workflow_id [db_string do_insert {}] + + # Callbacks + foreach callback_name $callbacks { + workflow::callback_insert \ + -workflow_id $workflow_id \ + -name $callback_name + } + + # May need to parse the simple workflow notation + if { [exists_and_not_null workflow] } { + parse_spec -workflow_id $workflow_id -spec $workflow + } + } + return $workflow_id } +ad_proc -private workflow::fsm::parse_spec { + {-workflow_id:required} + {-spec:required} +} { + Parse the -workflow argument to workflow::new and create roles, + states, actions, etc., as appropriate + + @param workflow_id The id of the workflow to delete. + + @author Lars Pind (lars@collaboraid.biz) + @see workflow::new +} { + array set workflow { roles {} states {} actions {} } + array set workflow $spec + + workflow::roles::parse_spec $workflow(roles) + workflow::roles::parse_spec $workflow(roles) +} + + + ad_proc -public workflow::delete { {-workflow_id:required} } { @@ -73,7 +123,8 @@ } ad_proc -public workflow::get_id { - {-object_id:required} + {-package_key {}} + {-object_id {}} {-short_name:required} } { Get workflow_id by short_name and object_id. @@ -83,10 +134,34 @@ @author Lars Pind (lars@collaboraid.biz) } { - return [db_string select_workflow_id {} -default {}] + if { [empty_string_p $package_key] } { + if { [empty_string_p $object_id] } { + if { [ad_conn isconnected] } { + set package_key [ad_conn package_key] + } else { + error "You must supply either package_key or object_id, or there must be a current connection" + set query_name select_workflow_id_by_package_key + } + } else { + set query_name select_workflow_id_by_object_id + } + } else { + if { [empty_string_p $object_id] } { + set query_name select_workflow_id_by_package_key + } else { + error "You must supply only one of either package_key or object_id" + } + } + + set workflow_id [db_string $query_name {} -default {}] + if { ![empty_string_p $workflow_id] } { + return $workflow_id + } else { + error "No workflow found with object_id $object_id and short_name $short_name" + } } -ad_proc -public workflow::action::get_initial_action { +ad_proc -public workflow::get_initial_action { {-workflow_id:required} } { Get the action_id of the special 'open' action of a workflow. @@ -101,27 +176,143 @@ ad_proc -private workflow::default_sort_order { {-workflow_id:required} - table_name + {-table_name:required} } { By default the sort_order will be the highest current sort order plus 1. This reflects the order in which states and actions are added to the workflow starting with 1 @author Peter Marklund } { - set sort_order_current \ - [db_string max_sort_order "select max(sort_order) \ - from $table_name \ - where workflow_id = $workflow_id" \ - -default 0] + set max_sort_order [db_string max_sort_order {} -default 0] - set sort_order [expr $sort_order_current + 1] + return [expr $max_sort_order + 1] +} - return $sort_order +ad_proc -private workflow::callback_insert { + {-workflow_id:required} + {-name:required} + {-sort_order {}} +} { + Add a side-effect to a workflow. + + @param workflow_id The ID of the workflow. + @param name Name of service contract implementation, in the form (impl_owner_name).(impl_name), + for example, bug-tracker.FormatLogTitle. + @param sort_order The sort_order for the rule. Leave blank to add to the end of the list + + @author Lars Pind (lars@collaboraid.biz) +} { + # TODO: + # Insert for real when the service contracts have been defined + + ns_log Error "LARS: workflow::callback_insert -- would have inserted the callback $name to workflow $workflow_id" + return + + db_transaction { + + # Get the impl_id + set acs_sc_impl_id [workflow::service_contract::get_impl_id -name $name] + + # Get the sort order + if { ![exists_and_not_null sort_order] } { + set sort_order [db_string select_sort_order {}] + } + + # Insert the callback + db_dml insert_callback {} + } + return $acs_sc_impl_id } + + ##### # +# workflow::fsm namespace +# +##### + +ad_proc -public workflow::fsm::new { + {-short_name:required} + {-pretty_name:required} + {-object_id:required} + {-object_type "acs_object"} + {-callbacks {}} + {-spec} +} { + Creates a new FSM workflow, with an optional spec argument. + + @param short_name For referring to the workflow from Tcl code. Use Tcl variable syntax. + @param pretty_name A human readable name for the workflow for use in the UI. + @param object_id The id of an ACS Object indicating the scope the workflow. + Typically this will be the id of a package type or a package instance + but it could also be some other type of ACS object within a package, for example + the id of a bug in the Bug Tracker application. + @param object_type The type of objects that the workflow will be applied to. Valid values are in the + acs_object_types table. The parameter is optional and defaults to acs_object. + @param spec The workflow spec in array-lists-in-array-lists format. + + @author Lars Pind (lars@collaboraid.biz) + @see workflow::new +} { + + db_transaction { + + # Create the workflow + set workflow_id [workflow::new \ + -short_name $short_name \ + -pretty_name $pretty_name \ + -object_id $object_id \ + -object_type $object_type \ + -callbacks $callbacks] + + # May need to parse the simple workflow notation + if { [exists_and_not_null spec] } { + parse_spec -workflow_id $workflow_id -spec $spec + } + } + + return $workflow_id +} + +ad_proc -private workflow::fsm::parse_spec { + {-workflow_id:required} + {-spec:required} +} { + Parse the -workflow argument to workflow::new and create roles, + states, actions, etc., as appropriate + + @param workflow_id The id of the workflow to delete. + @param spec The roles spec + + @author Lars Pind (lars@collaboraid.biz) + @see workflow::new +} { + array set workflow { roles {} states {} actions {} } + array set workflow $spec + + workflow::role::parse_roles_spec \ + -workflow_id $workflow_id \ + -spec $workflow(roles) + + workflow::state::fsm::parse_states_spec \ + -workflow_id $workflow_id \ + -spec $workflow(states) + + workflow::action::fsm::parse_actions_spec \ + -workflow_id $workflow_id \ + -spec $workflow(actions) +} + + + + + + + +##### +# # workflow::service_contract # ##### @@ -146,3 +337,15 @@ return "ActivityLog_FormatTitle" } +ad_proc -public workflow::service_contract::get_impl_id { + {-name:required} +} { + set namev [split $name "."] + + set impl_owner_name [lindex $namev 0] + set impl_name [lindex $namev 1] + + set acs_sc_impl_id [db_string select_impl_id {}] + + return $acs_sc_impl_id +} Index: openacs-4/packages/workflow/tcl/workflow-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/workflow-procs.xql,v diff -u -r1.2 -r1.3 --- openacs-4/packages/workflow/tcl/workflow-procs.xql 20 Jan 2003 15:45:00 -0000 1.2 +++ openacs-4/packages/workflow/tcl/workflow-procs.xql 21 Jan 2003 18:06:00 -0000 1.3 @@ -1,7 +1,7 @@ - + select workflow_id from workflows @@ -10,12 +10,53 @@ - + + select workflow_id + from workflows + where package_key = :package_key + and short_name = :short_name + + + + + select action_id from workflow_initial_action where workflow_id = :workflow_id + + + select max(sort_order) + from $table_name + where workflow_id = :workflow_id + + + + + + select coalesce(max(sort_order)) + 1 + from workflow_callbacks + where workflow_id = :workflow_id + + + + + + insert into workflow_callbacks (workflow_id, acs_sc_impl_id, sort_order) + values (:workflow_id, :acs_sc_impl_id, :sort_order) + + + + + + select impl_id + from acs_sc_impls + where impl_owner_name = :impl_owner_name + and impl_name = :impl_name + + + Index: openacs-4/packages/workflow/tcl/test/workflow-test-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/tcl/test/workflow-test-procs.tcl,v diff -u -r1.2 -r1.3 --- openacs-4/packages/workflow/tcl/test/workflow-test-procs.tcl 20 Jan 2003 15:45:00 -0000 1.2 +++ openacs-4/packages/workflow/tcl/test/workflow-test-procs.tcl 21 Jan 2003 18:06:13 -0000 1.3 @@ -28,8 +28,9 @@ ad_proc workflow::test::workflow_id {} { Get the id of the Bug Tracker bug workflow } { - return [workflow::get_id -object_id [workflow::test::workflow_object_id] \ - -short_name [workflow::test::workflow_name]] + return [workflow::get_id \ + -object_id [workflow::test::workflow_object_id] \ + -short_name [workflow::test::workflow_name]] } ad_proc workflow::test::admin_owner_id {} { @@ -47,7 +48,7 @@ } { set short_name_list [list] foreach action_id $action_id_list { - array set action_info [workflow::action::get -action_id $action_id] + workflow::action::get -action_id $action_id -array action_info lappend short_name_list $action_info(short_name) } @@ -73,10 +74,13 @@ -user_id [workflow::test::admin_owner_id]] set enabled_actions [workflow::test::action_short_names \ [workflow::case::get_enabled_actions -case_id $case_id]] - array set state_info \ - [workflow::state::fsm::get -state_id [workflow::case::fsm::get_current_state -case_id $case_id]] + + workflow::state::fsm::get \ + -state_id [workflow::case::fsm::get_current_state -case_id $case_id] \ + -array state_info + set user_actions [workflow::test::action_short_names \ - [workflow::case::get_user_actions -case_id $case_id \ + [workflow::case::get_available_actions -case_id $case_id \ -user_id [workflow::test::admin_owner_id]]] aa_true "current state should be $expect_current_state" \ @@ -89,6 +93,101 @@ [empty_string_p $user_roles] } +ad_proc workflow::test::workflow_setup_array_style {} { + Create a test workflow for the Bug Tracker + Bug use case. +} { + set spec { + roles { + submitter { + pretty_name "Submitter" + callbacks { + workflow.CreationUser + } + } + assignee { + pretty_name "Assignee" + callbacks { + bug-tracker.ComponentMaintainer + bug-tracker.ProjectMaintainer + } + } + } + states { + open { + pretty_name "Open" + } + resolved { + pretty_name "Resolved" + } + closed { + pretty_name "Closed" + } + } + actions { + open { + pretty_name "Open" + pretty_past_tense "Opened" + new_state "open" + initial_action_p 1 + } + comment { + pretty_name "Comment" + pretty_past_tense "Commented" + allowed_roles { submitter assignee } + privileges { read } + always_enabled_p t + } + edit { + pretty_name "Edit" + pretty_past_tense "Edited" + allowed_roles { submitter assignee } + privileges { write } + always_enabled_p t + } + resolve { + pretty_name "Resolve" + pretty_past_tense "Resolved" + assigned_roles { assignee } + enabled_states { open resolved } + new_state "resolved" + privileges { write } + callbacks { bug-tracker.CaptureResolutionCode } + } + close { + pretty_name "Close" + pretty_past_tense "Closed" + assigned_roles { submitter } + enabled_states { resolved } + new_state "closed" + privileges { write } + } + reopen { + pretty_name "Reopen" + pretty_past_tense "Closed" + allowed_roles { submitter } + enabled_states { resolved closed } + new_state "open" + privileges { write } + } + } + } + + set main_site_package_id [workflow::test::workflow_object_id] + + # Cannot use bt_bug as we cannot assume Bug Tracker to be installed + + set workflow_id [workflow::fsm::new \ + -short_name [workflow::test::workflow_name] \ + -pretty_name "Bug Test" \ + -object_id $main_site_package_id \ + -object_type "acs_object" \ + -callbacks { bug-tracker.FormatLogTitle } \ + -spec $spec] + + return $workflow_id +} + ad_proc workflow::test::workflow_setup {} { Create a test workflow for the Bug Tracker Bug use case. @@ -100,35 +199,34 @@ ##### set main_site_package_id [workflow::test::workflow_object_id] + # Cannot use bt_bug as we cannot assume Bug Tracker to be installed - # TODO: test side_effects? - # -side_effects { bug-tracker.FormatLogTitle } + set workflow_id [workflow::new \ -short_name [workflow::test::workflow_name] \ -pretty_name "Bug Test" \ -object_id $main_site_package_id \ - -object_type "acs_object"] + -object_type "acs_object" \ + -callbacks { bug-tracker.FormatLogTitle }] ##### # # Roles # ##### - # TODO: add assignment rules? - # -assignment_rules { workflow.CreationUser } workflow::role::new -workflow_id $workflow_id \ -short_name "submitter" \ - -pretty_name "Submitter" + -pretty_name "Submitter" \ + -callbacks { workflow.CreationUser } - # TODO: add assignment rules? - # -assignment_rules { - # bug-tracker.ComponentMaintainer - # bug-tracker.ProjectMaintainer - # } workflow::role::new -workflow_id $workflow_id \ -short_name "assignee" \ - -pretty_name "Assignee" + -pretty_name "Assignee" \ + -callbacks { + bug-tracker.ComponentMaintainer + bug-tracker.ProjectMaintainer + } ##### # @@ -154,41 +252,45 @@ # ##### - workflow::action::fsm::new -initial_action \ - -workflow_id $workflow_id \ - -short_name "open" \ - -pretty_name "Open" \ - -pretty_past_tense "Opened" \ - -new_state "open" - - workflow::action::fsm::new -workflow_id $workflow_id \ + workflow::action::fsm::new \ + -initial_action \ + -workflow_id $workflow_id \ + -short_name "open" \ + -pretty_name "Open" \ + -pretty_past_tense "Opened" \ + -new_state "open" + + workflow::action::fsm::new \ + -workflow_id $workflow_id \ -short_name "comment" \ -pretty_name "Comment" \ -pretty_past_tense "Commented" \ -allowed_roles { submitter assignee } \ -privileges { read } \ -always_enabled_p t - workflow::action::fsm::new -workflow_id $workflow_id \ + workflow::action::fsm::new \ + -workflow_id $workflow_id \ -short_name "edit" \ -pretty_name "Edit" \ -pretty_past_tense "Edited" \ -allowed_roles { submitter assignee } \ -privileges { write } \ -always_enabled_p t - # TODO add side effects? - # -side_effects { bug-tracker.CaptureResolutionCode } - workflow::action::fsm::new -workflow_id $workflow_id \ + workflow::action::fsm::new \ + -workflow_id $workflow_id \ -short_name "resolve" \ -pretty_name "Resolve" \ -pretty_past_tense "Resolved" \ -assigned_role { assignee } \ -enabled_states { open resolved } \ -new_state "resolved" \ - -privileges { write } + -privileges { write } \ + -callbacks { bug-tracker.CaptureResolutionCode } - workflow::action::fsm::new -workflow_id $workflow_id \ + workflow::action::fsm::new \ + -workflow_id $workflow_id \ -short_name "close" \ -pretty_name "Close" \ -pretty_past_tense "Closed" \ @@ -197,7 +299,8 @@ -new_state "closed" \ -privileges { write } - workflow::action::fsm::new -workflow_id $workflow_id \ + workflow::action::fsm::new \ + -workflow_id $workflow_id \ -short_name "reopen" \ -pretty_name "Reopen" \ -pretty_past_tense "Closed" \ @@ -212,10 +315,14 @@ ad_proc workflow::test::workflow_teardown {} { Delete the Bug Tracker Bug test workflow. } { - set workflow_id [workflow::get_id -object_id [workflow::test::workflow_object_id] \ - -short_name [workflow::test::workflow_name]] + # We don't care about error here + catch { + set workflow_id [workflow::get_id \ + -object_id [workflow::test::workflow_object_id] \ + -short_name [workflow::test::workflow_name]] - workflow::delete -workflow_id $workflow_id + workflow::delete -workflow_id $workflow_id + } } @@ -235,77 +342,115 @@ return $case_id } -aa_register_case bugtracker_workflow_create { - Test creation and teardown of an FSM workflow case. - - @author Peter Marklund - @creation-date 16 January 2003 +ad_proc workflow::test::run_bug_tracker_test { + {-create_proc "workflow_setup"} } { - # Setup - # Make sure to run the teardown proc even if there is an error - # Cannot get this to work as it seems the catch will return true - # if any catch did so in the executed code. - # set error_p [catch workflow::test::workflow_setup error] - set workflow_id [workflow::test::workflow_setup] + set test_chunk { + # Setup + # Make sure to run the teardown proc even if there is an error + # Cannot get this to work as it seems the catch will return true + # if any catch did so in the executed code. + # set error_p [catch workflow::test::workflow_setup error] + set workflow_id [workflow::test::$create_proc] + + # Create the workflow case in open state + set object_id [workflow::test::workflow_object_id] + set case_id [workflow::test::case_setup] + + set retrieved_case_id \ + [workflow::case::get_id \ + -object_id $object_id \ + -workflow_short_name [workflow::test::workflow_name]] + + set retrieved_object_id \ + [workflow::case::get_object_id -case_id $case_id] + + aa_true "case_id of a created workflow case should be retrievable" \ + [string equal $case_id $retrieved_case_id] + aa_true "object_id of a created workflow case should be retrievable" \ + [string equal $object_id $retrieved_object_id] + + set expect_enabled_actions [list comment edit resolve] + workflow::test::assert_case_state \ + -workflow_id $workflow_id \ + -case_id $case_id \ + -expect_current_state open \ + -expect_enabled_actions $expect_enabled_actions \ + -expect_user_actions $expect_enabled_actions \ + -expect_user_roles {} + + # Resolve the bug + workflow::case::action::execute \ + -case_id $case_id \ + -action_id [workflow::action::get_id -workflow_id $workflow_id \ + -short_name "resolve"] \ + -comment "Resolving Bug" \ + -comment_format plain \ + -user_id [workflow::test::admin_owner_id] + + set expect_enabled_actions [list comment edit resolve reopen close] + workflow::test::assert_case_state \ + -workflow_id $workflow_id \ + -case_id $case_id \ + -expect_current_state resolved \ + -expect_enabled_actions $expect_enabled_actions \ + -expect_user_actions $expect_enabled_actions \ + -expect_user_roles {} + + # Close the bug + workflow::case::action::execute \ + -case_id $case_id \ + -action_id [workflow::action::get_id -workflow_id $workflow_id \ + -short_name "close"] \ + -comment "Closing Bug" \ + -comment_format plain \ + -user_id [workflow::test::admin_owner_id] + + set expect_enabled_actions [list comment edit reopen] + workflow::test::assert_case_state \ + -workflow_id $workflow_id \ + -case_id $case_id \ + -expect_current_state closed \ + -expect_enabled_actions $expect_enabled_actions \ + -expect_user_actions $expect_enabled_actions \ + -expect_user_roles {} + + } - # Create the workflow case in open state - set object_id [workflow::test::workflow_object_id] - set case_id [workflow::test::case_setup] + set error_p [catch $test_chunk errMsg] + + # Teardown + workflow::test::workflow_teardown - set retrieved_case_id \ - [workflow::case::get_id -object_id $object_id \ - -workflow_short_name [workflow::test::workflow_name]] - set retrieved_object_id \ - [workflow::case::get_object_id -case_id $case_id] - aa_true "case_id of a created workflow case should be retrievable" \ - [string equal $case_id $retrieved_case_id] - aa_true "object_id of a created workflow case should be retrievable" \ - [string equal $object_id $retrieved_object_id] + # Report any errors from the setup proc + global errorInfo + aa_false "error during setup: $errMsg - $errorInfo" $error_p +} - set expect_enabled_actions [list comment edit resolve] - workflow::test::assert_case_state -workflow_id $workflow_id \ - -case_id $case_id \ - -expect_current_state open \ - -expect_enabled_actions $expect_enabled_actions \ - -expect_user_actions $expect_enabled_actions \ - -expect_user_roles {} - # Resolve the bug - workflow::case::action::execute -case_id $case_id \ - -action_id [workflow::action::get_id -workflow_id $workflow_id \ - -short_name "resolve"] \ - -comment "Resolving Bug" \ - -comment_format plain \ - -user_id [workflow::test::admin_owner_id] - set expect_enabled_actions [list comment edit resolve reopen close] - workflow::test::assert_case_state -workflow_id $workflow_id \ - -case_id $case_id \ - -expect_current_state resolved \ - -expect_enabled_actions $expect_enabled_actions \ - -expect_user_actions $expect_enabled_actions \ - -expect_user_roles {} - - # Close the bug - workflow::case::action::execute -case_id $case_id \ - -action_id [workflow::action::get_id -workflow_id $workflow_id \ - -short_name "close"] \ - -comment "Closing Bug" \ - -comment_format plain \ - -user_id [workflow::test::admin_owner_id] - set expect_enabled_actions [list comment edit reopen] - workflow::test::assert_case_state -workflow_id $workflow_id \ - -case_id $case_id \ - -expect_current_state closed \ - -expect_enabled_actions $expect_enabled_actions \ - -expect_user_actions $expect_enabled_actions \ - -expect_user_roles {} +##### +# +# Register the test cases +# +##### - # Teardown - workflow::test::workflow_teardown +aa_register_case bugtracker_workflow_create_normal { + Test creation and teardown of an FSM workflow case. - # Report any errors from the setup proc - #global errorInfo - #aa_false "error during setup: $error - $errorInfo" $error_p + @author Peter Marklund + @creation-date 16 January 2003 +} { + workflow::test::run_bug_tracker_test -create_proc "workflow_setup" } + +aa_register_case bugtracker_workflow_create_array_style { + Test creation and teardown of an FSM workflow case, with array style specification. + + @author Peter Marklund + @creation-date 16 January 2003 +} { + workflow::test::run_bug_tracker_test -create_proc "workflow_setup_array_style" +} +