Index: openacs-4/packages/acs-subsite/www/admin/relations/add.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-subsite/www/admin/relations/add.tcl,v diff -u -r1.17 -r1.18 --- openacs-4/packages/acs-subsite/www/admin/relations/add.tcl 30 Apr 2018 08:51:11 -0000 1.17 +++ openacs-4/packages/acs-subsite/www/admin/relations/add.tcl 3 Sep 2024 15:37:34 -0000 1.18 @@ -1,5 +1,3 @@ -# /packages/acs-subsite/www/admin/relations/add.tcl - ad_page_contract { Add a member to a group. If there are subtypes of the specified rel_type, we ask the user to select a precise rel_type before @@ -12,9 +10,9 @@ group_id:integer,notnull rel_type:notnull { party_id:naturalnum "" } - { exact_p:boolean "f" } + { exact_p:boolean,notnull "f" } { return_url:localurl "" } - { allow_out_of_scope_p:boolean "f" } + { allow_out_of_scope_p:boolean,notnull "f" } } -properties { context:onevalue role_pretty_name:onevalue @@ -25,19 +23,19 @@ add_party_url:onevalue } -validate { party_in_scope_p -requires {party_id:notnull} { - if { $allow_out_of_scope_p == "f" - && ![application_group::contains_party_p -party_id $party_id]} { - ad_complain "The party either does not exist or does not belong to this subsite." - } + if { $allow_out_of_scope_p == "f" + && ![application_group::contains_party_p -party_id $party_id]} { + ad_complain "The party either does not exist or does not belong to this subsite." + } } rel_type_valid_p -requires {group_id:notnull rel_type:notnull exact_p:notnull} { - if {$exact_p == "t" - && ![relation_type_is_valid_to_group_p -group_id $group_id $rel_type]} { - ad_complain "Relations of this type to this group would violate a relational constraint." - } + if {$exact_p == "t" + && ![relation_type_is_valid_to_group_p -group_id $group_id $rel_type]} { + ad_complain "Relations of this type to this group would violate a relational constraint." + } } } -# ISSUES / TO DO: still need to check that party_id is not already in the +# ISSUES / TO DO: still need to check that party_id is not already in the # group through this relation. Actually, we should handle this with # double-click protection (which we're not doing yet). We also need # to check permissions on the party. @@ -51,24 +49,33 @@ group::get -group_id $group_id -array group_info -# We assume the group is on side 1... -db_1row rel_type_info {} +# We assume the group is on side 1... +db_1row rel_type_info { + select t.object_type_two, + t.role_two as role, + (select pretty_name from acs_rel_roles + where role = t.role_two) as role_pretty_name, + (select pretty_name from acs_object_types + where object_type = t.object_type_two) as object_type_two_name + from acs_rel_types t + where rel_type = :rel_type +} # The role pretty names can be message catalog keys that need # to be localized before they are displayed set role_pretty_name [lang::util::localize $role_pretty_name] -if { $exact_p == "f" +if { $exact_p == "f" && [subsite::util::sub_type_exists_p $rel_type] } { # Sub rel-types exist... select one set exact_p "t" set export_url_vars [export_vars -exclude rel_type $export_var_list ] relation_types_valid_to_group_multirow \ - -datasource_name object_types \ - -start_with $rel_type \ - -group_id $group_id + -datasource_name object_types \ + -start_with $rel_type \ + -group_id $group_id set object_type_pretty_name [subsite::util::object_type_pretty_name $rel_type] set this_url [ad_conn url] @@ -82,9 +89,9 @@ foreach var $export_var_list { template::element create add_relation $var \ - -value [set $var] \ - -datatype text \ - -widget hidden + -value [set $var] \ + -datatype text \ + -widget hidden } # Build a URL used to create a new party of type object_type_two @@ -128,8 +135,8 @@ ad_complain $errorMsg } - if { $return_url eq "" } { - set return_url [export_vars -base one rel_id] + if { $return_url eq "" } { + set return_url [export_vars -base one rel_id] } ad_returnredirect $return_url ad_script_abort @@ -140,65 +147,91 @@ # ISSUES / TO DO: add a check to make sure the party is not # already in the group. We only want to do this on is_request, # in which case we know its not a double-click issue. - + set party_name [acs_object_name $party_id] - + # Note: party_id is not null, which means that it got added already # to $export_var_list, which means that there is already a hidden # form element containing the party_id variable. - + # Inform user which party will be on side two of the new relation. template::element create add_relation party_inform \ - -widget "inform" -value "$party_name" -label "$role_pretty_name" - + -widget "inform" -value "$party_name" -label "$role_pretty_name" + } else { - if {$object_type_two eq "party"} { - # We special case 'party' because we don't want to include - # parties whose direct object_type is: - # 'rel_segment' - users will get confused by segments here. - # 'party' - this is an abstract type and should have no objects, - # but the system creates party -1 which users - # shouldn't see. - - set start_with "ot.object_type = 'group' or ot.object_type = 'person'" - } else { - set start_with "ot.object_type = :object_type_two" - } - + + # We special case 'party' because we don't want to include + # parties whose direct object_type is: + # 'rel_segment' - users will get confused by segments here. + # 'party' - this is an abstract type and should have no objects, + # but the system creates party -1 which users + # shouldn't see. + # The $allow_out_of_scope_p flag controls whether or not we limit # the list of parties to those that belong to the current subsite # (allow_out_of_scope_p = 'f'). Even when allow_out_of_scope_p = 't', # permissions checks and relational constraints may limit # the list of parties that can be added to $group_id with a relation # of type $rel_type. - - if {$allow_out_of_scope_p == "f"} { - set scope_query [db_map select_parties_scope_query] - set scope_clause " - and p.party_id = app_elements.element_id" - - } else { - set scope_query "" - set scope_clause "" - } - # SENSITIVE PERFORMANCE - this comment tag is here to make it # easy for us to find all the queries that we know may be unscalable. - # This query has been tuned as well as possible given development + # This query has been tuned as well as possible given development # time constraints, but more tuning may be necessary. - set party_option_list [db_list_of_lists select_parties {}] + set party_option_list [db_list_of_lists select_parties { + with recursive subtypes as ( + select object_type + from acs_object_types + where (object_type = :object_type_two + and :object_type_two <> 'party') or + (object_type in ('person', 'group') + and :object_type_two = 'party') + union all + + select t.object_type + from acs_object_types t, + subtypes s + where t.supertype = s.object_type + ) + select DISTINCT + case when groups.group_id is null then + case when persons.person_id is null then 'INVALID' + else persons.first_names || ' ' || persons.last_name end + else groups.group_name end as party_name, + p.object_id as party_id + from acs_objects p + left join groups on groups.group_id = p.object_id + left join persons on persons.person_id = p.object_id, + subtypes s, + rc_parties_in_required_segs pirs + where p.object_type = s.object_type + -- do not list the group as a possible member + and p.object_id <> :group_id + -- do not list parties that are already members + and not exists (select 1 from group_element_map + where element_id = p.object_id + and group_id = :group_id + and rel_type = :rel_type) + and pirs.rel_type = :rel_type + and pirs.group_id = :group_id + and pirs.party_id = p.object_id + and (:allow_out_of_scope_p <> 'f' or + exists (select 1 from application_group_element_map + where package_id = :package_id + and element_id = p.object_id)) + }] + if { [llength $party_option_list] == 0 } { - ad_return_template add-no-valid-parties - return + ad_return_template add-no-valid-parties + return } - + template::element create add_relation party_id \ - -datatype "text" \ - -widget select \ - -options $party_option_list \ - -label "Select $role_pretty_name" + -datatype "text" \ + -widget select \ + -options $party_option_list \ + -label "Select $role_pretty_name" } ad_return_template