acs-permissions-procs.tcl

Tcl procs for the acs permissioning system.

Location:
packages/acs-tcl/tcl/acs-permissions-procs.tcl
Created:
2000-08-17
Author:
rhs@mit.edu
CVS Identification:
$Id: acs-permissions-procs.tcl,v 1.49 2024/09/11 06:15:48 gustafn Exp $

Procedures in this file

Detailed information

permission::cache_eval (private)

 permission::cache_eval [ -party_id party_id ] [ -object_id object_id ] \
    [ -privilege privilege ]

Run permission call and cache the result.

Switches:
-party_id (optional)
-object_id (optional)
-privilege (optional)
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 permission::permission_p permission::permission_p (public) permission::cache_eval permission::cache_eval permission::permission_p->permission::cache_eval parameter::get parameter::get (public) permission::cache_eval->parameter::get permission::permission_p_not_cached permission::permission_p_not_cached (private) permission::cache_eval->permission::permission_p_not_cached

Testcases:
No testcase defined.

permission::cache_flush (public)

 permission::cache_flush [ -party_id party_id ] \
    [ -object_id object_id ] [ -privilege privilege ]

Flush permissions from the cache. Either specify all three parameters or only party_id

Switches:
-party_id (optional)
-object_id (optional)
-privilege (optional)
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 test_test_inheritance_and_custom_permissions test_inheritance_and_custom_permissions (test acs-tcl) permission::cache_flush permission::cache_flush test_test_inheritance_and_custom_permissions->permission::cache_flush permission::permission_thread_cache_flush permission::permission_thread_cache_flush (private) permission::cache_flush->permission::permission_thread_cache_flush acs_user::demote_user acs_user::demote_user (public) acs_user::demote_user->permission::cache_flush group::add_member group::add_member (public) group::add_member->permission::cache_flush packages/acs-admin/www/users/modify-admin-privileges.tcl packages/acs-admin/ www/users/modify-admin-privileges.tcl packages/acs-admin/www/users/modify-admin-privileges.tcl->permission::cache_flush permission::grant permission::grant (public) permission::grant->permission::cache_flush permission::permission_p permission::permission_p (public) permission::permission_p->permission::cache_flush

Testcases:
test_inheritance_and_custom_permissions

permission::cache_p (private)

 permission::cache_p

Check, if permission_p caching is enabled or disabled. By default caching is disabled.

Returns:
Boolean value expressing whether permission caching is enabled

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

Testcases:
No testcase defined.

permission::get_parties_with_permission (public)

 permission::get_parties_with_permission -object_id object_id \
    [ -privilege privilege ]

Return a list of lists of party_id and acs_object.title, having a given privilege on the given object

Switches:
-object_id (required)
-privilege (optional, defaults to "admin")
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 test_test_inheritance_and_custom_permissions test_inheritance_and_custom_permissions (test acs-tcl) permission::get_parties_with_permission permission::get_parties_with_permission test_test_inheritance_and_custom_permissions->permission::get_parties_with_permission db_list_of_lists db_list_of_lists (public) permission::get_parties_with_permission->db_list_of_lists acs_admin::posture_status acs_admin::posture_status (private) acs_admin::posture_status->permission::get_parties_with_permission

Testcases:
test_inheritance_and_custom_permissions

permission::grant (public)

 permission::grant -party_id party_id -object_id object_id \
    -privilege privilege

grant privilege Y to party X on object Z

Switches:
-party_id (required)
-object_id (required)
-privilege (required)

Partial Call Graph (max 5 caller/called nodes):
%3 test_acs_admin_merge_MergeUserInfo acs_admin_merge_MergeUserInfo (test acs-admin) permission::grant permission::grant test_acs_admin_merge_MergeUserInfo->permission::grant test_acs_subsite_expose_bug_775 acs_subsite_expose_bug_775 (test acs-subsite) test_acs_subsite_expose_bug_775->permission::grant test_ad_proc_permission_grant_and_revoke ad_proc_permission_grant_and_revoke (test acs-tcl) test_ad_proc_permission_grant_and_revoke->permission::grant test_ad_proc_permission_permission_p ad_proc_permission_permission_p (test acs-tcl) test_ad_proc_permission_permission_p->permission::grant test_test_inheritance_and_custom_permissions test_inheritance_and_custom_permissions (test acs-tcl) test_test_inheritance_and_custom_permissions->permission::grant db_exec_plsql db_exec_plsql (public) permission::grant->db_exec_plsql permission::cache_flush permission::cache_flush (public) permission::grant->permission::cache_flush Class ::xo::Authorize Class ::xo::Authorize (public) Class ::xo::Authorize->permission::grant acs::test::user::create acs::test::user::create (public) acs::test::user::create->permission::grant acs_privacy::set_user_read_private_data acs_privacy::set_user_read_private_data (public, deprecated) acs_privacy::set_user_read_private_data->permission::grant acs_user::promote_person_to_user acs_user::promote_person_to_user (public) acs_user::promote_person_to_user->permission::grant apm_mount_core_packages apm_mount_core_packages (private) apm_mount_core_packages->permission::grant

Testcases:
acs_admin_merge_MergeUserInfo, acs_subsite_expose_bug_775, ad_proc_permission_grant_and_revoke, ad_proc_permission_permission_p, test_inheritance_and_custom_permissions

permission::inherit_p (public)

 permission::inherit_p -object_id object_id

Does this object inherit permissions?

Switches:
-object_id (required)
Returns:
Boolean value expression whether permussions are inherited.

Partial Call Graph (max 5 caller/called nodes):
%3 test_test_inheritance_and_custom_permissions test_inheritance_and_custom_permissions (test acs-tcl) permission::inherit_p permission::inherit_p test_test_inheritance_and_custom_permissions->permission::inherit_p db_string db_string (public) permission::inherit_p->db_string bug_tracker::access_policy bug_tracker::access_policy (public) bug_tracker::access_policy->permission::inherit_p packages/acs-subsite/www/admin/configure.tcl packages/acs-subsite/ www/admin/configure.tcl packages/acs-subsite/www/admin/configure.tcl->permission::inherit_p

Testcases:
test_inheritance_and_custom_permissions

permission::permission_p (public)

 permission::permission_p [ -no_login ] [ -no_cache ] \
    [ -party_id party_id ] -object_id object_id -privilege privilege

Does the provided party have the requested privilege on the given object?

Switches:
-no_login (optional, boolean)
Don't bump to registration to refresh authentication, if the user's authentication is expired. This is specifically required in the case where you're calling this from the proc that gets the login page.
-no_cache (optional, boolean)
force loading from db even if cached (flushes cache as well)
-party_id (optional)
if null then it is the current user_id
-object_id (required)
The object you want to check permissions on.
-privilege (required)
The privilege you want to check for.
Returns:
Boolean value expressing if the user has the required privilege on the given object

Partial Call Graph (max 5 caller/called nodes):
%3 test_acs_admin_merge_MergeUserInfo acs_admin_merge_MergeUserInfo (test acs-admin) permission::permission_p permission::permission_p test_acs_admin_merge_MergeUserInfo->permission::permission_p test_ad_proc_permission_grant_and_revoke ad_proc_permission_grant_and_revoke (test acs-tcl) test_ad_proc_permission_grant_and_revoke->permission::permission_p test_ad_proc_permission_permission_p ad_proc_permission_permission_p (test acs-tcl) test_ad_proc_permission_permission_p->permission::permission_p test_test_inheritance_and_custom_permissions test_inheritance_and_custom_permissions (test acs-tcl) test_test_inheritance_and_custom_permissions->permission::permission_p acs_object_name acs_object_name (public) permission::permission_p->acs_object_name ad_conn ad_conn (public) permission::permission_p->ad_conn ad_get_tcl_call_stack ad_get_tcl_call_stack (public) permission::permission_p->ad_get_tcl_call_stack ad_login_page ad_login_page (private) permission::permission_p->ad_login_page auth::require_login auth::require_login (public) permission::permission_p->auth::require_login Class ::xo::lti::LTI Class ::xo::lti::LTI (public) Class ::xo::lti::LTI->permission::permission_p Class ::xowiki::includelet::kibana Class ::xowiki::includelet::kibana (public) Class ::xowiki::includelet::kibana->permission::permission_p acs_privacy::user_can_read_private_data_p acs_privacy::user_can_read_private_data_p (public, deprecated) acs_privacy::user_can_read_private_data_p->permission::permission_p acs_user::site_wide_admin_p acs_user::site_wide_admin_p (public) acs_user::site_wide_admin_p->permission::permission_p bug_tracker::get_related_files_links bug_tracker::get_related_files_links (public) bug_tracker::get_related_files_links->permission::permission_p

Testcases:
acs_admin_merge_MergeUserInfo, ad_proc_permission_grant_and_revoke, ad_proc_permission_permission_p, test_inheritance_and_custom_permissions

permission::permission_p_not_cached (private)

 permission::permission_p_not_cached [ -no_cache ] \
    [ -party_id party_id ] -object_id object_id -privilege privilege

does party X have privilege Y on object Z This function accepts "-no_cache" just to match the permission_p signature since we alias it to permission::permission_p when caching is disabled.

Switches:
-no_cache (optional, boolean)
-party_id (optional)
-object_id (required)
-privilege (required)
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 permission::cache_eval permission::cache_eval (private) permission::permission_p_not_cached permission::permission_p_not_cached permission::cache_eval->permission::permission_p_not_cached permission::permission_p permission::permission_p (public) permission::permission_p->permission::permission_p_not_cached ad_conn ad_conn (public) permission::permission_p_not_cached->ad_conn db_string db_string (public) permission::permission_p_not_cached->db_string

Testcases:
No testcase defined.

permission::permission_thread_cache_flush (private)

 permission::permission_thread_cache_flush

Flush thread cache

Partial Call Graph (max 5 caller/called nodes):
%3 permission::cache_flush permission::cache_flush (public) permission::permission_thread_cache_flush permission::permission_thread_cache_flush permission::cache_flush->permission::permission_thread_cache_flush permission::permission_p permission::permission_p (public) permission::permission_p->permission::permission_thread_cache_flush permission::set_inherit permission::set_inherit (public) permission::set_inherit->permission::permission_thread_cache_flush permission::set_not_inherit permission::set_not_inherit (public) permission::set_not_inherit->permission::permission_thread_cache_flush permission::toggle_inherit permission::toggle_inherit (public) permission::toggle_inherit->permission::permission_thread_cache_flush

Testcases:
No testcase defined.

permission::require_permission (public)

 permission::require_permission [ -party_id party_id ] \
    -object_id object_id -privilege privilege

require that party X have privilege Y on object Z

Switches:
-party_id (optional)
-object_id (required)
-privilege (required)

Partial Call Graph (max 5 caller/called nodes):
%3 Class ::Generic::Form Class ::Generic::Form (public) permission::require_permission permission::require_permission Class ::Generic::Form->permission::require_permission attachments::richtext::file_attach attachments::richtext::file_attach (public) attachments::richtext::file_attach->permission::require_permission download_file_downloader download_file_downloader (public) download_file_downloader->permission::require_permission packages/acs-core-docs/www/files/tutorial/note-edit.tcl packages/acs-core-docs/ www/files/tutorial/note-edit.tcl packages/acs-core-docs/www/files/tutorial/note-edit.tcl->permission::require_permission packages/acs-developer-support/www/set-user.tcl packages/acs-developer-support/ www/set-user.tcl packages/acs-developer-support/www/set-user.tcl->permission::require_permission ad_conn ad_conn (public) permission::require_permission->ad_conn ad_log ad_log (public) permission::require_permission->ad_log ad_return_forbidden ad_return_forbidden (public) permission::require_permission->ad_return_forbidden ad_script_abort ad_script_abort (public) permission::require_permission->ad_script_abort auth::require_login auth::require_login (public) permission::require_permission->auth::require_login

Testcases:
No testcase defined.

permission::require_write_permission (public)

 permission::require_write_permission -object_id object_id \
    [ -creation_user creation_user ] [ -party_id party_id ] \
    [ -action action ]

If the user is not allowed to edit this object, returns a permission denied page.

Switches:
-object_id (required)
-creation_user (optional)
Optionally specify creation_user directly as an optimization. Otherwise a query will be executed.
-party_id (optional)
The party to have or not have write permission.
-action (optional, defaults to "edit")
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 packages/acs-core-docs/www/files/tutorial/note-delete.tcl packages/acs-core-docs/ www/files/tutorial/note-delete.tcl permission::require_write_permission permission::require_write_permission packages/acs-core-docs/www/files/tutorial/note-delete.tcl->permission::require_write_permission packages/acs-core-docs/www/files/tutorial/note-edit.tcl packages/acs-core-docs/ www/files/tutorial/note-edit.tcl packages/acs-core-docs/www/files/tutorial/note-edit.tcl->permission::require_write_permission packages/oct-election/www/election-edit.tcl packages/oct-election/ www/election-edit.tcl packages/oct-election/www/election-edit.tcl->permission::require_write_permission packages/xowiki/www/admin/delete-type.tcl packages/xowiki/ www/admin/delete-type.tcl packages/xowiki/www/admin/delete-type.tcl->permission::require_write_permission ad_return_forbidden ad_return_forbidden (public) permission::require_write_permission->ad_return_forbidden ad_script_abort ad_script_abort (public) permission::require_write_permission->ad_script_abort permission::write_permission_p permission::write_permission_p (public) permission::require_write_permission->permission::write_permission_p

Testcases:
No testcase defined.

permission::revoke (public)

 permission::revoke -party_id party_id -object_id object_id \
    -privilege privilege

revoke privilege Y from party X on object Z

Switches:
-party_id (required)
-object_id (required)
-privilege (required)

Partial Call Graph (max 5 caller/called nodes):
%3 test_ad_proc_permission_grant_and_revoke ad_proc_permission_grant_and_revoke (test acs-tcl) permission::revoke permission::revoke test_ad_proc_permission_grant_and_revoke->permission::revoke test_ad_proc_permission_permission_p ad_proc_permission_permission_p (test acs-tcl) test_ad_proc_permission_permission_p->permission::revoke db_exec_plsql db_exec_plsql (public) permission::revoke->db_exec_plsql permission::cache_flush permission::cache_flush (public) permission::revoke->permission::cache_flush acs_privacy::set_user_read_private_data acs_privacy::set_user_read_private_data (public, deprecated) acs_privacy::set_user_read_private_data->permission::revoke bug_tracker::inherit bug_tracker::inherit (private) bug_tracker::inherit->permission::revoke calendar::assign_permissions calendar::assign_permissions (public, deprecated) calendar::assign_permissions->permission::revoke calendar::item::assign_permission calendar::item::assign_permission (public, deprecated) calendar::item::assign_permission->permission::revoke install::xml::action::unset-permission install::xml::action::unset-permission (public) install::xml::action::unset-permission->permission::revoke

Testcases:
ad_proc_permission_grant_and_revoke, ad_proc_permission_permission_p

permission::set_inherit (public)

 permission::set_inherit -object_id object_id

set inherit to true

Switches:
-object_id (required)

Partial Call Graph (max 5 caller/called nodes):
%3 test_test_inheritance_and_custom_permissions test_inheritance_and_custom_permissions (test acs-tcl) permission::set_inherit permission::set_inherit test_test_inheritance_and_custom_permissions->permission::set_inherit db_dml db_dml (public) permission::set_inherit->db_dml permission::permission_thread_cache_flush permission::permission_thread_cache_flush (private) permission::set_inherit->permission::permission_thread_cache_flush bug_tracker::inherit bug_tracker::inherit (private) bug_tracker::inherit->permission::set_inherit packages/acs-subsite/www/admin/configure.tcl packages/acs-subsite/ www/admin/configure.tcl packages/acs-subsite/www/admin/configure.tcl->permission::set_inherit

Testcases:
test_inheritance_and_custom_permissions

permission::set_not_inherit (public)

 permission::set_not_inherit -object_id object_id

set inherit to false

Switches:
-object_id (required)

Partial Call Graph (max 5 caller/called nodes):
%3 test_fs_publish_file fs_publish_file (test file-storage) permission::set_not_inherit permission::set_not_inherit test_fs_publish_file->permission::set_not_inherit test_test_inheritance_and_custom_permissions test_inheritance_and_custom_permissions (test acs-tcl) test_test_inheritance_and_custom_permissions->permission::set_not_inherit db_dml db_dml (public) permission::set_not_inherit->db_dml permission::permission_thread_cache_flush permission::permission_thread_cache_flush (private) permission::set_not_inherit->permission::permission_thread_cache_flush apm_mount_core_packages apm_mount_core_packages (private) apm_mount_core_packages->permission::set_not_inherit bug_tracker::grant_direct_read_permission bug_tracker::grant_direct_read_permission (private) bug_tracker::grant_direct_read_permission->permission::set_not_inherit calendar::create calendar::create (public) calendar::create->permission::set_not_inherit calendar::item::new calendar::item::new (public) calendar::item::new->permission::set_not_inherit install::xml::action::create-package install::xml::action::create-package (public) install::xml::action::create-package->permission::set_not_inherit

Testcases:
test_inheritance_and_custom_permissions, fs_publish_file

permission::toggle_inherit (public)

 permission::toggle_inherit -object_id object_id

toggle whether or not this object inherits permissions from its parent

Switches:
-object_id (required)

Partial Call Graph (max 5 caller/called nodes):
%3 test_test_inheritance_and_custom_permissions test_inheritance_and_custom_permissions (test acs-tcl) permission::toggle_inherit permission::toggle_inherit test_test_inheritance_and_custom_permissions->permission::toggle_inherit db_dml db_dml (public) permission::toggle_inherit->db_dml permission::permission_thread_cache_flush permission::permission_thread_cache_flush (private) permission::toggle_inherit->permission::permission_thread_cache_flush packages/acs-subsite/www/permissions/toggle-inherit.tcl packages/acs-subsite/ www/permissions/toggle-inherit.tcl packages/acs-subsite/www/permissions/toggle-inherit.tcl->permission::toggle_inherit

Testcases:
test_inheritance_and_custom_permissions

permission::write_permission_p (public)

 permission::write_permission_p -object_id object_id \
    [ -party_id party_id ] [ -creation_user creation_user ]

Returns whether a party is allowed to edit an object. The logic is that this party must have either write permission, or it must be the one who created the object.

Switches:
-object_id (required)
The object you want to check write permissions for.
-party_id (optional)
The party to have or not have write permission.
-creation_user (optional)
Optionally specify creation_user directly as an optimization. Otherwise a query will be executed.
Returns:
Boolean value expressing if the user has permission to edit the object
See Also:

Partial Call Graph (max 5 caller/called nodes):
%3 permission::require_write_permission permission::require_write_permission (public) permission::write_permission_p permission::write_permission_p permission::require_write_permission->permission::write_permission_p acs_object::get_element acs_object::get_element (public) permission::write_permission_p->acs_object::get_element ad_conn ad_conn (public) permission::write_permission_p->ad_conn permission::permission_p permission::permission_p (public) permission::write_permission_p->permission::permission_p

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

Content File Source

ad_library {

    Tcl procs for the acs permissioning system.

    @author rhs@mit.edu
    @creation-date 2000-08-17
    @cvs-id $Id: acs-permissions-procs.tcl,v 1.49 2024/09/11 06:15:48 gustafn Exp $

}

namespace eval permission {}
#
# Define cache_p to return boolean value depending on the PermissionCacheP
# kernel parameter on the first call.  The namespace eval is needed to
# make the redefinition work for ttrace.
#
ad_proc -private permission::cache_p {} {
    Check, if permission_p caching is enabled or disabled.
    By default caching is disabled.

    @return Boolean value expressing whether permission caching is enabled
} {
    set cache_p [parameter::get \
                     -package_id $::acs::kernel_id \
                     -parameter PermissionCacheP \
                     -default 0]
    namespace eval ::permission [list proc cache_p {} "return $cache_p"]
    return $cache_p
}

d_proc -public permission::grant {
    {-party_id:required}
    {-object_id:required}
    {-privilege:required}
} {
    grant privilege Y to party X on object Z
} {
    db_exec_plsql grant_permission {}
    permission::cache_flush -party_id $party_id -object_id $object_id -privilege $privilege
}

d_proc -public permission::revoke {
    {-party_id:required}
    {-object_id:required}
    {-privilege:required}
} {
    revoke privilege Y from party X on object Z
} {
    db_exec_plsql revoke_permission {}
    permission::cache_flush -party_id $party_id -object_id $object_id -privilege $privilege
}

# args to permission_p and permission_p_no_cache must match
d_proc -public permission::permission_p {
    {-no_login:boolean}
    {-no_cache:boolean}
    {-party_id ""}
    {-object_id:required}
    {-privilege:required}
} {
    Does the provided party have the requested privilege on the given object?

    @param no_cache force loading from db even if cached (flushes cache as well)

    @param no_login Don't bump to registration to refresh authentication, if the user's authentication is expired.
                    This is specifically required in the case where you're calling this from the proc that gets
                    the login page.

    @param party_id if null then it is the current user_id

    @param object_id The object you want to check permissions on.

    @param privilege The privilege you want to check for.

    @return Boolean value expressing if the user has the required privilege on the given object
} {
    if { $party_id eq "" } {
        set party_id [ad_conn user_id]
    }

    set caching_activated [permission::cache_p]

    if { $no_cache_p || !$caching_activated } {
        #
        # No caching wanted (either per-call or configured)
        #
        if { $no_cache_p } {
            #
            # Avoid all caches.
            #
            permission::permission_thread_cache_flush
        }

        if {$caching_activated} {
            #
            # Only flush the cache, when caching is activated.
            # Frequent cache flushing can cause a flood of
            # intra-server talk in a cluster configuration (see bug
            # #2398);
            #
            permission::cache_flush \
                -party_id $party_id \
                -object_id $object_id \
                -privilege $privilege
        }

        set permission_p [permission::permission_p_not_cached \
                              -party_id $party_id \
                              -object_id $object_id \
                              -privilege $privilege]
    } else {
        #
        # Permission caching is activated
        #
        set permission_p [permission::cache_eval \
                              -party_id $party_id \
                              -object_id $object_id \
                              -privilege $privilege]
    }

    if {
        !$no_login_p
        && $party_id == 0
        && [ad_conn user_id] == 0
        && [ad_conn untrusted_user_id] != 0
        && ![string is true -strict $permission_p]
    } {
        #
        # In case, permission was granted above, the party and ad_conn
        # user_id are 0, and the permission is NOT granted based on
        # the untrusted_user_id, require login unless this is
        # deactivated for this call.
        #
        set untrusted_permission_p [permission_p_not_cached \
                                        -party_id [ad_conn untrusted_user_id] \
                                        -object_id $object_id \
                                        -privilege $privilege]
        if { $permission_p != $untrusted_permission_p } {
            # Bump to registration page
            ns_log Debug "permission_p: party_id=$party_id ([acs_object_name $party_id])," \
                "object_id=$object_id ([acs_object_name $object_id])," \
                "privilege=$privilege. Result=>$permission_p." \
                "Untrusted-Result=>$untrusted_permission_p\n[ad_get_tcl_call_stack]"
            if { ![ad_login_page] } {
                auth::require_login
            }
        }
    }

    return $permission_p
}


d_proc -private permission::permission_p_not_cached {
    {-no_cache:boolean}
    {-party_id ""}
    {-object_id:required}
    {-privilege:required}
} {
    does party X have privilege Y on object Z

    This function accepts "-no_cache" just to match the permission_p
    signature since we alias it to permission::permission_p when
    caching is disabled.

    @see permission::permission_p
} {
    if { $party_id eq "" } {
        set party_id [ad_conn user_id]
    }

    # We have a per-request cache here
    return [acs::per_request_cache eval -key acs-tcl.permission_p__cache-$party_id,$object_id,$privilege {
        db_string select_permission_p {
            select acs_permission.permission_p(:object_id, :party_id, :privilege) from dual
        }
    }]
}


ad_proc -private permission::permission_thread_cache_flush {} {
    Flush thread cache
} {
    acs::per_request_cache flush -pattern acs-tcl.permission_p__cache*
}

d_proc -public permission::require_permission {
    {-party_id ""}
    {-object_id:required}
    {-privilege:required}
} {
    require that party X have privilege Y on object Z
} {
    if {$party_id eq ""} {
        set party_id [ad_conn user_id]
    }

    if {![permission_p -party_id $party_id -object_id $object_id -privilege $privilege]} {

        if {!$party_id && ![ad_conn ajax_p]} {
            auth::require_login
        } else {
            set message [string cat "permission::require_permission: " \
                             "$party_id doesn't have privilege $privilege " \
                             "on object '$object_id'"]
            if {$object_id eq ""} {
                ad_log error $message
            } else {
                ns_log notice $message
            }
            ad_return_forbidden \
                "Permission Denied" \
                "You don't have permission to $privilege on object $object_id."
        }

        ad_script_abort
    }
}

d_proc -public permission::inherit_p {
    {-object_id:required}
} {
    Does this object inherit permissions?
    @return Boolean value expression whether permussions are inherited.
} {
    return [db_string select_inherit_p {} -default 0]
}

d_proc -public permission::toggle_inherit {
    {-object_id:required}
} {
    toggle whether or not this object inherits permissions from its parent
} {
    db_dml toggle_inherit {}
    permission::permission_thread_cache_flush
}

d_proc -public permission::set_inherit {
    {-object_id:required}
} {
    set inherit to true
} {
    db_dml set_inherit {}
    permission::permission_thread_cache_flush
}

d_proc -public permission::set_not_inherit {
    {-object_id:required}
} {
    set inherit to false
} {
    db_dml set_not_inherit {}
    permission::permission_thread_cache_flush
}

d_proc -public permission::write_permission_p {
    {-object_id:required}
    {-party_id ""}
    {-creation_user ""}
} {
    Returns whether a party is allowed to edit an object.
    The logic is that this party must have either write permission,
    or it must be the one who created the object.

    @param object_id     The object you want to check write permissions for.

    @param party_id      The party to have or not have write permission.

    @param creation_user Optionally specify creation_user directly as an optimization.
                         Otherwise a query will be executed.

    @return Boolean value expressing if the user has permission to edit the object

    @see permission::require_write_permission
} {
    if { $party_id eq "" } {
        set party_id [ad_conn user_id]
    }
    if { $creation_user eq "" } {
        set creation_user [acs_object::get_element -object_id $object_id -element creation_user]
    }
    if { $party_id == $creation_user } {
        return 1
    }
    if { [permission::permission_p -privilege write -object_id $object_id -party_id $party_id] } {
        return 1
    }
    return 0
}

d_proc -public permission::require_write_permission {
    {-object_id:required}
    {-creation_user ""}
    {-party_id ""}
    {-action "edit"}
} {
    If the user is not allowed to edit this object, returns a permission denied page.

    @param creation_user Optionally specify creation_user directly as an optimization.
                         Otherwise a query will be executed.
    @param party_id      The party to have or not have write permission.

    @see permission::write_permission_p
} {
    if { ![permission::write_permission_p -object_id $object_id -party_id $party_id] } {
        ad_return_forbidden  "Permission Denied"  "You don't have permission to $action this object."
        ad_script_abort
    }
}

d_proc -public permission::get_parties_with_permission {
    {-object_id:required}
    {-privilege "admin"}
} {
    Return a list of lists of party_id and acs_object.title,
    having a given privilege on the given object

    @param object_id
    @param privilege

    @see permission::permission_p
} {
    return [db_list_of_lists get_parties {}]
}


d_proc -private permission::cache_eval {
    {-party_id}
    {-object_id}
    {-privilege}
} {
    Run permission call and cache the result.

    @param party_id
    @param object_id
    @param privilege

    @see permission::permission_p
} {
    return [acs::permission_cache eval \
                -partition_key $party_id \
                -expires [parameter::get -package_id $::acs::kernel_id \
                              -parameter PermissionCacheTimeout \
                              -default 300] \
                $party_id/$object_id/$privilege {
                    permission::permission_p_not_cached \
                        -party_id $party_id \
                        -object_id $object_id \
                        -privilege $privilege
                }]
}

#
# flush permission cache
#

d_proc -public permission::cache_flush {
    {-party_id}
    {-object_id}
    {-privilege}
} {

    Flush permissions from the cache. Either specify all three
    parameters or only party_id

    @param party_id
    @param object_id
    @param privilege

    @see permission::permission_p
} {
    permission::permission_thread_cache_flush

    if {[namespace which ::acs::permission_cache] eq ""} {
        return

    } elseif {[info exists party_id] && [info exists object_id] && [info exists privilege]} {
        #
        # All three attributes are provided
        #
        ::acs::permission_cache flush -partition_key $party_id $party_id/$object_id/$privilege

    } elseif {[info exists party_id] } {
        #
        # At least the party_id is provided
        #
        ::acs::permission_cache flush_all -partition_key $party_id
    } else {
        #
        # tell user, what's implemented
        #
        error "either specify party_id, object_id and privilege, or only party_id"
    }
}



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