relation-procs.tcl

Helpers for dealing with relations

Location:
packages/acs-subsite/tcl/relation-procs.tcl
Created:
Sun Dec 10 16:46:11 2000
Author:
mbryzek@arsdigita.com
CVS Identification:
$Id: relation-procs.tcl,v 1.20.2.2 2019/05/16 09:27:52 gustafn Exp $

Procedures in this file

Detailed information

relation::get_id (public)

 relation::get_id -object_id_one object_id_one \
    -object_id_two object_id_two [ -rel_type rel_type ]

Find the rel_id of the relation matching the given object_id_one, object_id_two, and rel_type.

Switches:
-object_id_one (required)
-object_id_two (required)
-rel_type (optional, defaults to "membership_rel")
Returns:
rel_id of the found acs_rel, or the empty string if none existed.

Partial Call Graph (max 5 caller/called nodes):
%3 test_acs_subsite_relation_procs acs_subsite_relation_procs (test acs-subsite) relation::get_id relation::get_id test_acs_subsite_relation_procs->relation::get_id db_string db_string (public) relation::get_id->db_string group::admin_p group::admin_p (public) group::admin_p->relation::get_id packages/acs-subsite/www/group-leave.tcl packages/acs-subsite/ www/group-leave.tcl packages/acs-subsite/www/group-leave.tcl->relation::get_id

Testcases:
acs_subsite_relation_procs

relation::get_object_one (public)

 relation::get_object_one -object_id_two object_id_two \
    [ -rel_type rel_type ] [ -multiple ]

Return the object_id of object one if a relation of rel_type exists between the supplied object_id_two and it.

Switches:
-object_id_two (required)
-rel_type (optional, defaults to "membership_rel")
-multiple (optional, boolean)

Partial Call Graph (max 5 caller/called nodes):
%3 test_acs_subsite_relation_procs acs_subsite_relation_procs (test acs-subsite) relation::get_object_one relation::get_object_one test_acs_subsite_relation_procs->relation::get_object_one test_category_tree_procs category_tree_procs (test categories) test_category_tree_procs->relation::get_object_one db_list db_list (public) relation::get_object_one->db_list db_string db_string (public) relation::get_object_one->db_string relation::get_objects relation::get_objects (public) relation::get_objects->relation::get_object_one

Testcases:
acs_subsite_relation_procs, category_tree_procs

relation::get_object_two (public)

 relation::get_object_two -object_id_one object_id_one \
    [ -rel_type rel_type ] [ -multiple ]

Return the object_id of object two if a relation of rel_type exists between the supplied object_id_one and it.

Switches:
-object_id_one (required)
-rel_type (optional, defaults to "membership_rel")
-multiple (optional, boolean)

Partial Call Graph (max 5 caller/called nodes):
%3 test_acs_subsite_relation_procs acs_subsite_relation_procs (test acs-subsite) relation::get_object_two relation::get_object_two test_acs_subsite_relation_procs->relation::get_object_two db_list db_list (public) relation::get_object_two->db_list db_string db_string (public) relation::get_object_two->db_string relation::get_objects relation::get_objects (public) relation::get_objects->relation::get_object_two

Testcases:
acs_subsite_relation_procs

relation::get_objects (public)

 relation::get_objects [ -object_id_one object_id_one ] \
    [ -object_id_two object_id_two ] [ -rel_type rel_type ]

Return the list of object_ids if a relation of rel_type exists between the supplied object_id and it.

Switches:
-object_id_one (optional)
-object_id_two (optional)
-rel_type (optional, defaults to "membership_rel")

Partial Call Graph (max 5 caller/called nodes):
%3 test_acs_subsite_relation_procs acs_subsite_relation_procs (test acs-subsite) relation::get_objects relation::get_objects test_acs_subsite_relation_procs->relation::get_objects _ _ (public) relation::get_objects->_ ad_return_error ad_return_error (public) relation::get_objects->ad_return_error ad_script_abort ad_script_abort (public) relation::get_objects->ad_script_abort relation::get_object_one relation::get_object_one (public) relation::get_objects->relation::get_object_one relation::get_object_two relation::get_object_two (public) relation::get_objects->relation::get_object_two

Testcases:
acs_subsite_relation_procs

relation_add (public)

 relation_add [ -form_id form_id ] [ -extra_vars extra_vars ] \
    [ -variable_prefix variable_prefix ] \
    [ -creation_user creation_user ] [ -creation_ip creation_ip ] \
    [ -member_state member_state ] rel_type object_id_one \
    object_id_two

Creates a new relation of the specified type between the two objects. Throws an error if the new relation violates a relational constraint.

Switches:
-form_id (optional)
The form id from templating form system
-extra_vars (optional)
An ns_set of extra variables
-variable_prefix (optional)
Only form elements that begin with the specified prefix will be processed.
-creation_user (optional)
The user who is creating the relation
-creation_ip (optional)
-member_state (optional)
Only used for membership_relations. See column membership_rels.member_state for more info.
Parameters:
rel_type (required)
object_id_one (required)
object_id_two (required)
Returns:
The rel_id of the new relation
Authors:
Michael Bryzek <mbryzek@arsdigita.com>
Ben Adida <ben@openforce.net>
Created:
1/5/2001

Partial Call Graph (max 5 caller/called nodes):
%3 test_acs_subsite_check_composite_group acs_subsite_check_composite_group (test acs-subsite) relation_add relation_add test_acs_subsite_check_composite_group->relation_add test_acs_subsite_expose_bug_775 acs_subsite_expose_bug_775 (test acs-subsite) test_acs_subsite_expose_bug_775->relation_add test_acs_subsite_rel_segment_new acs_subsite_rel_segment_new (test acs-subsite) test_acs_subsite_rel_segment_new->relation_add test_acs_subsite_relation_procs acs_subsite_relation_procs (test acs-subsite) test_acs_subsite_relation_procs->relation_add db_string db_string (public) relation_add->db_string db_transaction db_transaction (public) relation_add->db_transaction package_instantiate_object package_instantiate_object (public) relation_add->package_instantiate_object group::add_member group::add_member (public) group::add_member->relation_add install::xml::action::relation-add install::xml::action::relation-add (public) install::xml::action::relation-add->relation_add packages/acs-subsite/www/admin/groups/new.tcl packages/acs-subsite/ www/admin/groups/new.tcl packages/acs-subsite/www/admin/groups/new.tcl->relation_add packages/acs-subsite/www/admin/parties/new.tcl packages/acs-subsite/ www/admin/parties/new.tcl packages/acs-subsite/www/admin/parties/new.tcl->relation_add packages/acs-subsite/www/admin/users/new.tcl packages/acs-subsite/ www/admin/users/new.tcl packages/acs-subsite/www/admin/users/new.tcl->relation_add

Testcases:
acs_subsite_expose_bug_775, acs_subsite_check_composite_group, acs_subsite_relation_procs, acs_subsite_rel_segment_new

relation_permission_p (public, deprecated)

 relation_permission_p [ -user_id user_id ] [ -privilege privilege ] \
    rel_id
Deprecated. Invoking this procedure generates a warning.

Wrapper for ad_permission_p that lets us default to read permission Deprecated: just another wrapper for permission::permission_p

Switches:
-user_id (optional)
-privilege (optional, defaults to "read")
Parameters:
rel_id (required)
Author:
Michael Bryzek <mbryzek@arsdigita.com>
Created:
12/2000
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 ad_log_deprecated ad_log_deprecated (public) permission::permission_p permission::permission_p (public) relation_permission_p relation_permission_p relation_permission_p->ad_log_deprecated relation_permission_p->permission::permission_p

Testcases:
No testcase defined.

relation_remove (public)

 relation_remove [ rel_id ]

Removes the specified relation. Throws an error if we violate a relational constraint by removing this relation.

Parameters:
rel_id (optional)
Returns:
1 if we delete anything. 0 otherwise (e.g. when the relation was already deleted)
Author:
Michael Bryzek <mbryzek@arsdigita.com>
Created:
1/5/2001

Partial Call Graph (max 5 caller/called nodes):
%3 test_acs_subsite_relation_procs acs_subsite_relation_procs (test acs-subsite) relation_remove relation_remove test_acs_subsite_relation_procs->relation_remove db_0or1row db_0or1row (public) relation_remove->db_0or1row db_exec_plsql db_exec_plsql (public) relation_remove->db_exec_plsql relation_segment_has_dependent relation_segment_has_dependent (public) relation_remove->relation_segment_has_dependent acs_user::demote_user acs_user::demote_user (public) acs_user::demote_user->relation_remove application_link::delete_links application_link::delete_links (public) application_link::delete_links->relation_remove group::remove_member group::remove_member (public) group::remove_member->relation_remove packages/acs-subsite/www/admin/groups/rel-type-remove-2.tcl packages/acs-subsite/ www/admin/groups/rel-type-remove-2.tcl packages/acs-subsite/www/admin/groups/rel-type-remove-2.tcl->relation_remove packages/acs-subsite/www/admin/rel-types/delete-2.tcl packages/acs-subsite/ www/admin/rel-types/delete-2.tcl packages/acs-subsite/www/admin/rel-types/delete-2.tcl->relation_remove

Testcases:
acs_subsite_relation_procs

relation_required_segments_multirow (public)

 relation_required_segments_multirow \
    [ -datasource_name datasource_name ] [ -group_id group_id ] \
    [ -rel_type rel_type ] [ -rel_side rel_side ]

Sets up a multirow datasource. Also returns a list containing the most essential information.

Switches:
-datasource_name (optional)
-group_id (optional)
-rel_type (optional, defaults to "membership_rel")
-rel_side (optional, defaults to "two")

Partial Call Graph (max 5 caller/called nodes):
%3 packages/acs-subsite/www/admin/parties/new.tcl packages/acs-subsite/ www/admin/parties/new.tcl relation_required_segments_multirow relation_required_segments_multirow packages/acs-subsite/www/admin/parties/new.tcl->relation_required_segments_multirow packages/acs-subsite/www/register/user-join.tcl packages/acs-subsite/ www/register/user-join.tcl packages/acs-subsite/www/register/user-join.tcl->relation_required_segments_multirow ad_urlencode ad_urlencode (public) relation_required_segments_multirow->ad_urlencode application_group::group_id_from_package_id application_group::group_id_from_package_id (public) relation_required_segments_multirow->application_group::group_id_from_package_id db_foreach db_foreach (public) relation_required_segments_multirow->db_foreach template::multirow template::multirow (public) relation_required_segments_multirow->template::multirow

Testcases:
No testcase defined.

relation_segment_has_dependent (public)

 relation_segment_has_dependent [ -rel_id rel_id ] \
    [ -segment_id segment_id ] [ -party_id party_id ]

Returns 1 if the specified segment/party combination has a dependent (meaning a constraint would be violated if we removed this relation). 0 otherwise. Either rel_id or segment_id and party_id must be specified. rel_id takes precedence.

Switches:
-rel_id (optional)
-segment_id (optional)
-party_id (optional)
Author:
Michael Bryzek <mbryzek@arsdigita.com>
Created:
12/2000

Partial Call Graph (max 5 caller/called nodes):
%3 test_demote_promote_a_user demote_promote_a_user (test acs-tcl) relation_segment_has_dependent relation_segment_has_dependent test_demote_promote_a_user->relation_segment_has_dependent db_0or1row db_0or1row (public) relation_segment_has_dependent->db_0or1row db_string db_string (public) relation_segment_has_dependent->db_string packages/acs-subsite/www/admin/relations/remove.tcl packages/acs-subsite/ www/admin/relations/remove.tcl packages/acs-subsite/www/admin/relations/remove.tcl->relation_segment_has_dependent relation_remove relation_remove (public) relation_remove->relation_segment_has_dependent

Testcases:
demote_promote_a_user

relation_type_is_valid_to_group_p (public)

 relation_type_is_valid_to_group_p [ -group_id group_id ] rel_type

Returns 1 if group $group_id allows elements through a relation of type $rel_type, or 0 otherwise. If there are no relational constraints that prevent $group_id from being on side one of a relation of type $rel_type, then 1 is returned.

Switches:
-group_id (optional)
- if unspecified, then we use [application_group::group_id_from_package_id]
Parameters:
rel_type (required)
Author:
Oumi Mehrotra <oumi@arsdigita.com>
Created:
2000-02-07

Partial Call Graph (max 5 caller/called nodes):
%3 packages/acs-subsite/www/admin/relations/add.tcl packages/acs-subsite/ www/admin/relations/add.tcl relation_type_is_valid_to_group_p relation_type_is_valid_to_group_p packages/acs-subsite/www/admin/relations/add.tcl->relation_type_is_valid_to_group_p packages/acs-subsite/www/register/user-join.tcl packages/acs-subsite/ www/register/user-join.tcl packages/acs-subsite/www/register/user-join.tcl->relation_type_is_valid_to_group_p application_group::group_id_from_package_id application_group::group_id_from_package_id (public) relation_type_is_valid_to_group_p->application_group::group_id_from_package_id db_string db_string (public) relation_type_is_valid_to_group_p->db_string

Testcases:
No testcase defined.

relation_types_valid_to_group_multirow (public)

 relation_types_valid_to_group_multirow \
    [ -datasource_name datasource_name ] [ -start_with start_with ] \
    [ -group_id group_id ]

creates multirow datasource containing relationship types starting with the $start_with relationship type. The datasource has columns that are identical to the party::types_allowed_in_group_multirow, which is why the columns are broadly named "object_*" instead of "rel_*". A common template can be used for generating select widgets etc. for both this datasource and the party::types_allowed_in_groups_multirow datasource. All subtypes of $start_with are returned, but the "valid_p" column in the datasource indicates whether the type is a valid one for $group_id. If -group_id is not specified or is specified null, then the current application_group will be used (determined from [application_group::group_id_from_package_id]). Includes fields that are useful for presentation in a hierarchical select widget:

  • object_type
  • object_type_enc - encoded object type
  • indent - an HTML indentation string
  • pretty_name - pretty name of object type

Switches:
-datasource_name (optional, defaults to "object_types")
-start_with (optional, defaults to "acs_rel")
-group_id (optional)
- if unspecified, then [application_group::group_id_from_package_id] is used.
Author:
Oumi Mehrotra <oumi@arsdigita.com>
Created:
2000-02-07

Partial Call Graph (max 5 caller/called nodes):
%3 packages/acs-subsite/www/admin/relations/add.tcl packages/acs-subsite/ www/admin/relations/add.tcl relation_types_valid_to_group_multirow relation_types_valid_to_group_multirow packages/acs-subsite/www/admin/relations/add.tcl->relation_types_valid_to_group_multirow ad_urlencode ad_urlencode (public) relation_types_valid_to_group_multirow->ad_urlencode application_group::group_id_from_package_id application_group::group_id_from_package_id (public) relation_types_valid_to_group_multirow->application_group::group_id_from_package_id db_foreach db_foreach (public) relation_types_valid_to_group_multirow->db_foreach template::multirow template::multirow (public) relation_types_valid_to_group_multirow->template::multirow

Testcases:
No testcase defined.
[ hide source ] | [ make this the default ]

Content File Source

ad_library {

    Helpers for dealing with relations

    @author mbryzek@arsdigita.com
    @creation-date Sun Dec 10 16:46:11 2000
    @cvs-id $Id: relation-procs.tcl,v 1.20.2.2 2019/05/16 09:27:52 gustafn Exp $

}

namespace eval relation {}

d_proc -deprecated -public relation_permission_p {
    { -user_id "" }
    { -privilege "read" }
    rel_id
} {
    Wrapper for ad_permission_p that lets us default to read permission

    Deprecated: just another wrapper for permission::permission_p

    @author Michael Bryzek (mbryzek@arsdigita.com)
    @creation-date 12/2000

    @see permission::permission_p

} {
    return [permission::permission_p -party_id $user_id -object_id $rel_id -privilege $privilege]
}


d_proc -public relation_add {
    { -form_id "" }
    { -extra_vars "" }
    { -variable_prefix "" }
    { -creation_user "" }
    { -creation_ip "" }
    { -member_state "" }
    rel_type
    object_id_one
    object_id_two
} {
    Creates a new relation of the specified type between the two
    objects. Throws an error if the new relation violates a relational
    constraint.

    @author Michael Bryzek (mbryzek@arsdigita.com)
    @author Ben Adida (ben@openforce.net)
    @creation-date 1/5/2001

    @param form_id         The form id from templating form system

    @param extra_vars      An ns_set of extra variables

    @param variable_prefix Only form elements that begin with the
                           specified prefix will be processed.

    @param creation_user   The user who is creating the relation

    @param creation_ip

    @param member_state    Only used for membership_relations.
                           See column membership_rels.member_state
                           for more info.

    @return The <code>rel_id</code> of the new relation

} {
    # First check if the relation already exists, and if so, just return that
    set existing_rel_id [db_string rel_exists {
        select rel_id
        from   acs_rels
        where  rel_type = :rel_type
        and    object_id_one = :object_id_one
        and    object_id_two = :object_id_two
    } -default {}]

    if { $existing_rel_id ne "" } {
        return $existing_rel_id
    }

    set var_list [list \
            [list object_id_one $object_id_one] \
            [list object_id_two $object_id_two]]

    # Note that we don't explicitly check whether rel_type is a type of
    # membership relation before adding the member_state variable.  The
    # package_instantiate_object proc will ignore the member_state variable
    # if the rel_type's plsql package doesn't support it.
    if {$member_state ne ""} {
        lappend var_list [list member_state $member_state]
    }

    # We initialize rel_id, so it's set if there's a problem
    set rel_id {}

    # We use db_transaction inside this proc to roll back the insert
    # in case of a violation

    db_transaction {

        set rel_id [package_instantiate_object \
                -creation_user $creation_user \
                -creation_ip $creation_ip \
                -start_with "relationship" \
                -form_id $form_id \
                -extra_vars $extra_vars \
                -variable_prefix $variable_prefix \
                -var_list $var_list \
                $rel_type]

        # Check to see if constraints are violated because of this new
        # relation

        # JCD: this is enforced by trigger so no longer check explicitly
        # see membership_rels_in_tr
        #
        # set violated_err_msg [db_string select_rel_violation {} -default ""]
        #
        # if { $violated_err_msg ne "" } {
        #     error $violated_err_msg
        # }
    } on_error {
        return -code error $errmsg
    }

    return $rel_id
}


d_proc -public relation_remove {
    {rel_id ""}
} {
    Removes the specified relation. Throws an error if we violate a
    relational constraint by removing this relation.

    @author Michael Bryzek (mbryzek@arsdigita.com)
    @creation-date 1/5/2001

    @return 1 if we delete anything. 0 otherwise (e.g. when the
              relation was already deleted)

} {
    # Pull out the segment_id and the party_id (object_id_two) from
    # acs_rels. Note the outer joins since the segment may not exist.
    if { ![db_0or1row select_rel_info_rm {}] } {
        # Relation doesn't exist
        return 0
    }

    # Check if we would violate some constraint by removing this relation.
    # This query basically says: Does there exist a segment, to which
    # this party is an element (with any relationship type), that
    # depends on this party being in this segment? That's tough to
    # parse. Another way to say the same things is: Is there some constraint
    # that requires this segment? If so, is the user a member of the segment
    # on which that constraint is defined? If so, we cannot remove this
    # relation. Note that this segment is defined by joining against
    # acs_rels to find the group and rel_type for this relation.

    if { $segment_id ne "" } {
        if { [relation_segment_has_dependent -segment_id $segment_id -party_id $party_id] } {
            error "Relational constraints violated by removing this relation"
        }
    }

    db_exec_plsql relation_delete {}

    return 1
}



d_proc -public relation_segment_has_dependent {
    { -rel_id "" }
    { -segment_id "" }
    { -party_id "" }
} {
    Returns 1 if the specified segment/party combination has a
    dependent (meaning a constraint would be violated if we removed this
    relation). 0 otherwise. Either <code>rel_id</code> or
    <code>segment_id</code> and <code>party_id</code> must be
    specified. <code>rel_id</code> takes precedence.

    @author Michael Bryzek (mbryzek@arsdigita.com)
    @creation-date 12/2000

} {

    if { $rel_id ne "" } {
        if { ![db_0or1row select_rel_info {}] } {
            # There is either no relation or no segment... thus no dependents
            return 0
        }
    }

    if { $segment_id eq "" || $party_id eq "" } {
        error "Both of segment_id and party_id must be specified in call to relation_segment_has_dependent"
    }

    return [db_string others_depend_p {}]
}


d_proc -public relation_type_is_valid_to_group_p {
    { -group_id "" }
    rel_type
} {
    Returns 1 if group $group_id allows elements through a relation of
    type $rel_type, or 0 otherwise.

    If there are no relational constraints that prevent $group_id from being
    on side one of a relation of type $rel_type, then 1 is returned.

    @author Oumi Mehrotra (oumi@arsdigita.com)
    @creation-date 2000-02-07

    @param group_id - if unspecified, then we use
                      [application_group::group_id_from_package_id]
    @param rel_type
} {
    if {$group_id eq ""} {
        set group_id [application_group::group_id_from_package_id]
    }

    return [db_string rel_type_valid_p {}]

}


d_proc relation_types_valid_to_group_multirow {
    {-datasource_name object_types}
    {-start_with acs_rel}
    {-group_id ""}
} {
    creates multirow datasource containing relationship types starting with
    the $start_with relationship type.  The datasource has columns that are
    identical to the party::types_allowed_in_group_multirow, which is why
    the columns are broadly named "object_*" instead of "rel_*".  A common
    template can be used for generating select widgets etc. for both
    this datasource and the party::types_allowed_in_groups_multirow datasource.

    All subtypes of $start_with are returned, but the "valid_p" column in the
    datasource indicates whether the type is a valid one for $group_id.

    If -group_id is not specified or is specified null, then the current
    application_group will be used
    (determined from [application_group::group_id_from_package_id]).

    Includes fields that are useful for
    presentation in a hierarchical select widget:
    <ul>
    <li> object_type
    <li> object_type_enc - encoded object type
    <li> indent          - an HTML indentation string
    <li> pretty_name     - pretty name of object type
    </ul>

    @author Oumi Mehrotra (oumi@arsdigita.com)
    @creation-date 2000-02-07

    @param datasource_name
    @param start_with
    @param group_id - if unspecified, then
                      [application_group::group_id_from_package_id] is used.
} {

    if {$group_id eq ""} {
        set group_id [application_group::group_id_from_package_id]
    }

    template::multirow create $datasource_name \
        object_type object_type_enc indent pretty_name valid_p

    db_foreach select_sub_rel_types {} {
        template::multirow append $datasource_name $object_type [ad_urlencode $object_type$indent $pretty_name $valid_p
    }

}


d_proc -public relation_required_segments_multirow {
    { -datasource_name "" }
    { -group_id "" }
    { -rel_type "membership_rel" }
    { -rel_side "two" }
} {
    Sets up a multirow datasource.
    Also returns a list containing the most essential information.
} {
    if {$group_id eq ""} {
        set group_id [application_group::group_id_from_package_id]
    }

    template::multirow create $datasource_name \
            segment_id group_id rel_type rel_type_enc \
            rel_type_pretty_name group_name join_policy


    set group_rel_type_list [list]

    db_foreach select_required_rel_segments {} {
        template::multirow append $datasource_name $segment_id $group_id $rel_type [ad_urlencode $rel_type$rel_type_pretty_name $group_name $join_policy

        lappend group_rel_type_list [list $group_id $rel_type]
    }
    return $group_rel_type_list
}

d_proc -public relation::get_id {
    {-object_id_one:required}
    {-object_id_two:required}
    {-rel_type "membership_rel"}
} {
    Find the rel_id of the relation matching the given object_id_one, object_id_two, and rel_type.

    @return rel_id of the found acs_rel, or the empty string if none existed.
} {
    return [db_string select_rel_id {} -default {}]
}

d_proc -public relation::get_object_one {
    {-object_id_two:required}
    {-rel_type "membership_rel"}
    {-multiple:boolean}
} {
    Return the object_id of object one if a relation of rel_type exists between the supplied object_id_two and it.

    @param multiple_p If set to "t" return a list instead of only one object_id
} {
    if {$multiple_p} {
        return [db_list select_object_one {}]
    } else {
        return [db_string select_object_one {} -default {}]
    }
}

d_proc -public relation::get_object_two {
    {-object_id_one:required}
    {-rel_type "membership_rel"}
    {-multiple:boolean}
} {
    Return the object_id of object two if a relation of rel_type exists between the supplied object_id_one and it.

    @param multiple_p If set to "t" return a list instead of only one object_id
} {
    if {$multiple_p} {
        return [db_list select_object_two {}]
    } else {
        return [db_string select_object_two {} -default {}]
    }
}

d_proc -public relation::get_objects {
    {-object_id_one ""}
    {-object_id_two ""}
    {-rel_type "membership_rel"}
} {
    Return the list of object_ids if a relation of rel_type exists between the supplied object_id and it.
} {
    if {$object_id_one eq ""} {
        if {$object_id_two eq ""} {
            ad_return_error \
                [_ acs-subsite.Missing_argument] \
                [_ acs-subsite.lt_You_have_to_provide_a]
            ad_script_abort
        } else {
            return [relation::get_object_one -object_id_two $object_id_two -rel_type $rel_type -multiple]
        }
    } else {
        return [relation::get_object_two -object_id_one $object_id_one -rel_type $rel_type -multiple]
    }
}

# Local variables:
#    mode: tcl
#    tcl-indent-level: 4
#    indent-tabs-mode: nil
# End: