content-perms.sql
OpenACS Home : ACS API Browser : ACS Content Repository 5.5.1 : content-perms.sql
--------------------------------------------------------------
--
-- Set up the basic permissions used by the CMS, and invent some
-- api in dealing with them
--
--------------------------------------------------------------
create function inline_0 ()
returns integer as '
declare
found_p boolean;
begin
select count(*) > 0 into found_p from dual
where exists (select 1 from acs_privileges
where privilege = ''cm_root'');
if NOT found_p then
-- Dummy root privilege
PERFORM acs_privilege__create_privilege(''cm_root'', ''Root'', ''Root'');
-- He can do everything
PERFORM acs_privilege__create_privilege(''cm_admin'', ''Administrator'', ''Administrators'');
PERFORM acs_privilege__create_privilege(''cm_write'', ''Write'', ''Write'');
PERFORM acs_privilege__create_privilege(''cm_new'', ''Create New Item'', ''Create New Item'');
PERFORM acs_privilege__create_privilege(''cm_examine'', ''Admin-level Read'', ''Admin-level Read'');
PERFORM acs_privilege__create_privilege(''cm_read'', ''User-level Read'', ''User-level Read'');
PERFORM acs_privilege__create_privilege(''cm_item_workflow'', ''Modify Workflow'', ''Modify Workflow'');
PERFORM acs_privilege__create_privilege(''cm_perm_admin'', ''Modify Any Permissions'', ''Modify Any Permissions'');
PERFORM acs_privilege__create_privilege(''cm_perm'', ''Donate Permissions'', ''Donate Permissions'');
PERFORM acs_privilege__add_child(''cm_root'', ''cm_admin''); -- Do anything to an object
PERFORM acs_privilege__add_child(''cm_admin'', ''cm_write''); -- Do anything to an object
PERFORM acs_privilege__add_child(''cm_write'', ''cm_new''); -- Create subitems
PERFORM acs_privilege__add_child(''cm_new'', ''cm_examine''); -- View in admin mode
PERFORM acs_privilege__add_child(''cm_examine'', ''cm_read''); -- View in user mode
PERFORM acs_privilege__add_child(''cm_write'', ''cm_item_workflow''); -- Change item workflow
PERFORM acs_privilege__add_child(''cm_admin'', ''cm_perm_admin''); -- Modify any permissions
PERFORM acs_privilege__add_child(''cm_perm_admin'', ''cm_perm''); -- Modify any permissions on an item
-- Proper inheritance
PERFORM acs_privilege__add_child(''admin'', ''cm_root'');
end if;
return 0;
end;' language 'plpgsql';
select inline_0 ();
drop function inline_0 ();
-- create or replace package body content_permission
-- procedure inherit_permissions
create function content_permission__inherit_permissions (integer,integer,integer)
returns integer as '
declare
inherit_permissions__parent_object_id alias for $1;
inherit_permissions__child_object_id alias for $2;
inherit_permissions__child_creator_id alias for $3; -- default null
v_dummy integer;
begin
-- Determine if the child is a direct descendant of the
-- parent
select 1 into v_dummy from acs_objects
where object_id = inherit_permissions__child_object_id
and context_id = inherit_permissions__parent_object_id;
if NOT FOUND then
raise EXCEPTION ''-20000: Child object is not actually a child of the parent object in inherit_permissions'';
end if;
-- Copy everything one level down
insert into acs_permissions
select
inherit_permissions__child_object_id as object_id,
grantee_id,
privilege
from
acs_permissions
where
object_id = inherit_permissions__parent_object_id;
if inherit_permissions__child_creator_id is not null then
-- Grant cm_write and cm_perm to the child creator
if content_permission__permission_p (
inherit_permissions__child_object_id,
inherit_permissions__child_creator_id,
''cm_perm''
) != ''t'' then
-- Turn off inheritance and grant permission
update acs_objects set security_inherit_p = ''f''
where object_id = inherit_permissions__child_object_id;
PERFORM acs_permission__grant_permission (
inherit_permissions__child_object_id,
inherit_permissions__child_creator_id,
''cm_perm''
);
end if;
if content_permission__permission_p (
inherit_permissions__child_object_id,
inherit_permissions__child_creator_id,
''cm_write''
) != ''t'' then
PERFORM acs_permission__grant_permission (
inherit_permissions__child_object_id,
inherit_permissions__child_creator_id,
''cm_write''
);
end if;
end if;
return 0;
end;' language 'plpgsql';
-- function has_grant_authority
create function content_permission__has_grant_authority (integer,integer,varchar)
returns boolean as '
declare
object_id alias for $1;
holder_id alias for $2;
privilege alias for $3;
begin
-- Can donate permission only if you already have it and you have cm_perm,
-- OR you have cm_perm_admin
if content_permission__permission_p (object_id, holder_id, ''cm_perm_admin'')= ''t''
or (
content_permission__permission_p (object_id, holder_id, ''cm_perm'') = ''t'' and
content_permission__permission_p (object_id, holder_id, privilege) = ''t''
)
then
return ''t'';
else
return ''f'';
end if;
end;' language 'plpgsql';
-- function has_revoke_authority
create function content_permission__has_revoke_authority (integer,integer,varchar,integer)
returns boolean as '
declare
has_revoke_authority__object_id alias for $1;
has_revoke_authority__holder_id alias for $2;
has_revoke_authority__privilege alias for $3;
has_revoke_authority__revokee_id alias for $4;
begin
-- DRB: Note that the privilege selection doesn't use the slick tree_ancestor_keys
-- trick. There are two reasons for this. The first is that we might have a set of
-- tree_sortkeys returned from the acs_privilege_hierarchy_index when child_privilege
-- is ''cm_perm''. The second is that this table is relatively small anyway and the
-- old style's probably just as efficient as the first as an index scan is only preferred
-- by the Postgres optimizer when it will significantly reduce the number of rows scanned.
-- DanW: Removed hierarchy index query in favor of using descendant map.
return exists (select 1 from
(select o2.object_id
from (select tree_ancestor_keys(acs_object__get_tree_sortkey(has_revoke_authority__object_id)) as tree_sortkey) parents,
acs_objects o2
where o2.tree_sortkey = parents.tree_sortkey) t
(select privilege, descendant as child_privilege
from acs_privilege_descendant_map
where descendant = 'cm_perm') h
where
content_permission__permission_p(
t.object_id, has_revoke_authority__holder_id, h.child_privilege
)
and not
content_permission__permission_p(
t.object_id, has_revoke_authority__revokee_id, h.privilege
));
end;' language 'plpgsql';
-- procedure grant_permission_h
create function content_permission__grant_permission_h (integer,integer,varchar)
returns integer as '
declare
grant_permission_h__object_id alias for $1;
grant_permission_h__grantee_id alias for $2;
grant_permission_h__privilege alias for $3;
v_privilege acs_privilege_descendant_map.privilege%TYPE;
v_rec record;
begin
-- If the permission is already granted, do nothing
if content_permission__permission_p (
grant_permission_h__object_id,
grant_permission_h__grantee_id,
grant_permission_h__privilege
) = ''t'' then
return null;
end if;
-- Grant the parent, make sure there is no inheritance
update acs_objects set security_inherit_p = ''f''
where object_id = grant_permission_h__object_id;
PERFORM acs_permission__grant_permission(grant_permission_h__object_id,
grant_permission_h__grantee_id,
grant_permission_h__privilege);
-- Revoke the children - they are no longer relevant
for v_rec in select descendant from acs_privilege_descendant_map
where privilege = grant_permission_h__privilege
and descendant <> grant_permission_h__privilege;
LOOP
PERFORM acs_permission__revoke_permission(
grant_permission_h__object_id,
grant_permission_h__grantee_id,
v_rec.descendant
);
end LOOP;
return 0;
end;' language 'plpgsql';
-- procedure grant_permission
create function content_permission__grant_permission (integer,integer,varchar,integer,boolean,varchar)
returns integer as '
declare
grant_permission__object_id alias for $1;
grant_permission__holder_id alias for $2;
grant_permission__privilege alias for $3;
grant_permission__recepient_id alias for $4;
grant_permission__is_recursive alias for $5; -- default ''f''
grant_permission__object_type alias for $6; -- default ''content_item''
v_object_id acs_objects.object_id%TYPE;
begin
-- select
-- o.object_id
-- from
-- (select object_id, object_type from acs_objects
-- connect by context_id = prior object_id
-- start with object_id = grant_permission__object_id) o
-- where
-- content_permission__has_grant_authority (
-- o.object_id, holder_id, grant_permission__privilege
-- ) = ''t''
-- and
-- content_item__is_subclass (o.object_type, grant_permission__object_type) = ''t''
for v_rec in select
o.object_id
from
(select o1.object_id, o1.object_type
from acs_objects o1, acs_objects o2
where o2.object_id = grant_permission__object_id
and o1.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey)) o
where content_permission__has_grant_authority (o.object_id, holder_id, grant_permission__privilege)
and content_item__is_subclass (o.object_type, grant_permission__object_type)
LOOP
-- Grant the parent and revoke the children, since we do not need them
-- anymore
PERFORM content_permission__grant_permission_h (
v_rec.object_id,
grant_permission__recepient_id,
grant_permission__privilege
);
exit when grant_permission__is_recursive = ''f'';
end loop;
return 0;
end;' language 'plpgsql';
-- procedure revoke_permission_h
create function content_permission__revoke_permission_h (integer,integer,varchar)
returns integer as '
declare
revoke_permission_h__object_id alias for $1;
revoke_permission_h__revokee_id alias for $2;
revoke_permission_h__privilege alias for $3;
v_rec record;
begin
-- Grant all child privileges of the parent privilege
for v_rec in select child_privilege from acs_privilege_hierarchy
where privilege = revoke_permission_h__privilege
LOOP
PERFORM acs_permission__grant_permission (
revoke_permission_h__object_id,
revoke_permission_h__revokee_id,
v_rec.child_privilege
);
end loop;
-- Revoke the parent privilege
PERFORM acs_permission__revoke_permission (
revoke_permission_h__object_id,
revoke_permission_h__revokee_id,
revoke_permission_h__privilege
);
return 0;
end;' language 'plpgsql';
-- procedure revoke_permission
create function content_permission__revoke_permission (integer,integer,varchar,integer,boolean,varchar)
returns integer as '
declare
revoke_permission__object_id alias for $1;
revoke_permission__holder_id alias for $2;
revoke_permission__privilege alias for $3;
revoke_permission__revokee_id alias for $4;
revoke_permission__is_recursive alias for $5; -- default ''f''
revoke_permission__object_type alias for $6; -- default ''content_item''
v_rec record;
begin
-- select object_id, object_type from acs_objects
-- connect by context_id = prior object_id
-- start with object_id = revoke_permission__object_id
for v_rec in select o.object_id
from (select o1.object_id, o1.object_type
from acs_objects o1, acs_objects o2
where o1.tree_sortkey between o2.tree_sortkey and tree_right(o2.tree_sortkey)
and o2.object_id = revoke_permission__object_id) o
where
content_permission__has_revoke_authority (o.object_id, revoke_permission__holder_id, revoke_permission__privilege, revoke_permission__revokee_id) = ''t''
and
content_item__is_subclass(o.object_type, revoke_permission__object_type) = ''t''
LOOP
PERFORM content_permission__revoke_permission_h (
v_rec.object_id,
revoke_permission__revokee_id,
revoke_permission__privilege
);
exit when revoke_permission__is_recursive = ''f'';
end loop;
return 0;
end;' language 'plpgsql';
-- function permission_p
create function content_permission__permission_p (integer,integer,varchar)
returns boolean as '
declare
object_id alias for $1;
holder_id alias for $2;
privilege alias for $3;
begin
return acs_permission__permission_p (object_id, holder_id, privilege);
end;' language 'plpgsql';
-- Determine if the CMS admin exists
create function cm_admin_exists () returns boolean as '
begin
return count(*) > 0 from dual
where exists (
select 1 from acs_permissions
where privilege in (''cm_admin'', ''cm_root'')
);
end;' language 'plpgsql';
-- show errors