[open-ils-commits] r12534 - trunk/Open-ILS/src/sql/Pg (scottmk)

svn at svn.open-ils.org svn at svn.open-ils.org
Mon Mar 16 09:22:00 EDT 2009


Author: scottmk
Date: 2009-03-16 09:21:59 -0400 (Mon, 16 Mar 2009)
New Revision: 12534

Modified:
   trunk/Open-ILS/src/sql/Pg/006.schema.permissions.sql
Log:
Add several functions for identifying the org units for which
a given user has a given permission.


Modified: trunk/Open-ILS/src/sql/Pg/006.schema.permissions.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/006.schema.permissions.sql	2009-03-16 04:13:10 UTC (rev 12533)
+++ trunk/Open-ILS/src/sql/Pg/006.schema.permissions.sql	2009-03-16 13:21:59 UTC (rev 12534)
@@ -290,5 +290,265 @@
 		END;
 $$ LANGUAGE SQL;
 
+
+CREATE OR REPLACE FUNCTION permission.usr_has_perm_at_nd(
+	user_id    IN INTEGER,
+	perm_code  IN TEXT
+)
+RETURNS SETOF INTEGER AS $$
+--
+-- Return a set of all the org units for which a given user has a given
+-- permission, granted directly (not through inheritance from a parent
+-- org unit).
+--
+-- The permissions apply to a minimum depth of the org unit hierarchy,
+-- for the org unit(s) to which the user is assigned.  (They also apply
+-- to the subordinates of those org units, but we don't report the
+-- subordinates here.)
+--
+-- For purposes of this function, the permission.usr_work_ou_map table
+-- defines which users belong to which org units.  I.e. we ignore the
+-- home_ou column of actor.usr.
+--
+-- The result set may contain duplicates, which should be eliminated
+-- by a DISTINCT clause.
+--
+DECLARE
+	n_perm        INTEGER;
+	n_min_depth   INTEGER; 
+	n_work_ou     INTEGER;
+	n_curr_ou     INTEGER;
+	n_depth       INTEGER;
+	n_curr_depth  INTEGER;
+BEGIN
+	--
+	-- Translate the permission name
+	-- to a numeric permission id
+	--
+	SELECT INTO n_perm
+		id
+	FROM
+		permission.perm_list
+	WHERE
+		code = perm_code;
+	--
+	IF NOT FOUND THEN
+		RETURN;               -- No such permission
+	END IF;
+	--
+	-- Find the highest-level org unit (i.e. the minimum depth)
+	-- to which the permission is applied for this user
+	--
+	-- This query is modified from the one in permission.usr_perms().
+	--
+	SELECT INTO n_min_depth
+		min( depth )
+	FROM	(
+		SELECT depth 
+		  FROM permission.usr_perm_map upm
+		 WHERE upm.usr = user_id 
+		   AND upm.perm = n_perm
+       				UNION
+		SELECT	gpm.depth
+		  FROM	permission.grp_perm_map gpm
+		  WHERE	gpm.perm = n_perm 
+	        AND gpm.grp IN (
+	 		   SELECT	(permission.grp_ancestors(
+					(SELECT profile FROM actor.usr WHERE id = user_id)
+				)).id
+			)
+       				UNION
+		SELECT	p.depth
+		  FROM	permission.grp_perm_map p 
+		  WHERE p.perm = n_perm
+		    AND p.grp IN (
+		  		SELECT (permission.grp_ancestors(m.grp)).id 
+				FROM   permission.usr_grp_map m
+				WHERE  m.usr = user_id
+			)
+	) AS x;
+	--
+	IF NOT FOUND THEN
+		RETURN;                -- No such permission for this user
+	END IF;
+	--
+	-- Identify the org units to which the user is assigned.  Note that
+	-- we pay no attention to the home_ou column in actor.usr.
+	--
+	FOR n_work_ou IN
+		SELECT
+			work_ou
+		FROM
+			permission.usr_work_ou_map
+		WHERE
+			usr = user_id
+	LOOP            -- For each org unit to which the user is assigned
+		--
+		-- Determine the level of the org unit by a lookup in actor.org_unit_type.
+		-- We take it on faith that this depth agrees with the actual hierarchy
+		-- defined in actor.org_unit.
+		--
+		SELECT INTO n_depth
+		    type.depth
+		FROM
+		    actor.org_unit_type type
+		        INNER JOIN actor.org_unit ou
+		            ON ( ou.ou_type = type.id )
+		WHERE
+		    ou.id = n_work_ou;
+		--
+		IF NOT FOUND THEN
+			CONTINUE;        -- Maybe raise exception?
+		END IF;
+		--
+		-- Compare the depth of the work org unit to the
+		-- minimum depth, and branch accordingly
+		--
+		IF n_depth = n_min_depth THEN
+			--
+			-- The org unit is at the right depth, so return it.
+			--
+			RETURN NEXT n_work_ou;
+		ELSIF n_depth > n_min_depth THEN
+			--
+			-- Traverse the org unit tree toward the root,
+			-- until you reach the minimum depth determined above
+			--
+			n_curr_depth := n_depth;
+			n_curr_ou := n_work_ou;
+			WHILE n_curr_depth > n_min_depth LOOP
+				SELECT INTO n_curr_ou
+					parent_ou
+				FROM
+					actor.org_unit
+				WHERE
+					id = n_curr_ou;
+				--
+				IF FOUND THEN
+					n_curr_depth := n_curr_depth - 1;
+				ELSE
+					--
+					-- This can happen only if the hierarchy defined in
+					-- actor.org_unit is corrupted, or out of sync with
+					-- the depths defined in actor.org_unit_type.
+					-- Maybe we should raise an exception here, instead
+					-- of silently ignoring the problem.
+					--
+					n_curr_ou = NULL;
+					EXIT;
+				END IF;
+			END LOOP;
+			--
+			IF n_curr_ou IS NOT NULL THEN
+				RETURN NEXT n_curr_ou;
+			END IF;
+		ELSE
+			--
+			-- The permission applies only at a depth greater than the work org unit.
+			-- Use connectby() to find all dependent org units at the specified depth.
+			--
+			FOR n_curr_ou IN
+				SELECT ou::INTEGER
+				FROM connectby( 
+						'actor.org_unit',         -- table name
+						'id',                     -- key column
+						'parent_ou',              -- recursive foreign key
+						n_work_ou::TEXT,          -- id of starting point
+						(n_min_depth - n_depth)   -- max depth to search, relative
+					)                             --   to starting point
+					AS t(
+						ou text,            -- dependent org unit
+						parent_ou text,     -- (ignore)
+						level int           -- depth relative to starting point
+					)
+				WHERE
+					level = n_min_depth - n_depth
+			LOOP
+				RETURN NEXT n_curr_ou;
+			END LOOP;
+		END IF;
+		--
+	END LOOP;
+	--
+	RETURN;
+	--
+END;
+$$ LANGUAGE 'plpgsql';
+
+
+CREATE OR REPLACE FUNCTION permission.usr_has_perm_at_all_nd(
+	user_id    IN INTEGER,
+	perm_code  IN TEXT
+)
+RETURNS SETOF INTEGER AS $$
+--
+-- Return a set of all the org units for which a given user has a given
+-- permission, granted either directly or through inheritance from a parent
+-- org unit.
+--
+-- The permissions apply to a minimum depth of the org unit hierarchy, and
+-- to the subordinates of those org units, for the org unit(s) to which the
+-- user is assigned.
+--
+-- For purposes of this function, the permission.usr_work_ou_map table
+-- assigns users to org units.  I.e. we ignore the home_ou column of actor.usr.
+--
+-- The result set may contain duplicates, which should be eliminated
+-- by a DISTINCT clause.
+--
+DECLARE
+	n_head_ou     INTEGER;
+	n_child_ou    INTEGER;
+BEGIN
+	FOR n_head_ou IN
+		SELECT DISTINCT * FROM permission.usr_has_perm_at_nd( user_id, perm_code )
+	LOOP
+		--
+		-- The permission applies only at a depth greater than the work org unit.
+		-- Use connectby() to find all dependent org units at the specified depth.
+		--
+		FOR n_child_ou IN
+			SELECT ou::INTEGER
+			FROM connectby( 
+					'actor.org_unit',   -- table name
+					'id',               -- key column
+					'parent_ou',        -- recursive foreign key
+					n_head_ou::TEXT,    -- id of starting point
+					0                   -- no limit on search depth
+				)
+				AS t(
+					ou text,            -- dependent org unit
+					parent_ou text,     -- (ignore)
+					level int           -- (ignore)
+				)
+		LOOP
+			RETURN NEXT n_child_ou;
+		END LOOP;
+	END LOOP;
+	--
+	RETURN;
+	--
+END;
+$$ LANGUAGE 'plpgsql';
+
+
+CREATE OR REPLACE FUNCTION permission.usr_has_perm_at(
+	user_id    IN INTEGER,
+	perm_code  IN TEXT
+)
+RETURNS SETOF INTEGER AS $$
+SELECT DISTINCT * FROM permission.usr_has_perm_at_nd( $1, $2 );
+$$ LANGUAGE 'sql';
+
+
+CREATE OR REPLACE FUNCTION permission.usr_has_perm_at_all(
+	user_id    IN INTEGER,
+	perm_code  IN TEXT
+)
+RETURNS SETOF INTEGER AS $$
+SELECT DISTINCT * FROM permission.usr_has_perm_at_all_nd( $1, $2 );
+$$ LANGUAGE 'sql';
+
+
 COMMIT;
 



More information about the open-ils-commits mailing list