-- 
-- A general permissions facility 
--
-- created by richardl@arsdigita.com on 7/14/99
-- rewritten by michael@arsdigita.com, yon@arsdigita.com & markc@arsdigita.com, 2000-02-25

create sequence gp_id_sequence start 1;

create table general_permissions (
	permission_id		integer not null primary key,
	on_what_id		integer not null,
	on_which_table		varchar(30) not null,
        scope           	varchar(20),
	user_id			integer references users,
	group_id		integer references user_groups,
	role			varchar(200),
	permission_type		varchar(20) not null,
-- This check statment makes the tuple too big for PG 7 ( >8K )
--	check ((scope = 'user' and user_id is not null
--                and group_id is null and role is null) or
--	       (scope = 'group_role' and user_id is null
--                and group_id is not null and role is not null) or
--	       (scope = 'group' and user_id is null
--                and group_id is not null and role is null) or
--	       (scope in ('registered_users', 'all_users')
--                and user_id is null
--                and group_id is null and role is null)),
	unique (on_what_id, on_which_table,
                scope, user_id, group_id, role, permission_type)
);

-- This trigger normalizes values in the on_which_table column to
-- be all lowercase. This makes it easier to implement a case-
-- insensitive API (since function-based indexes do not seem to
-- work as advertised in Oracle 8.1.5). Just make sure to call
-- LOWER whenever constructing a criterion involving
-- on_which_table.
--

create function trig_gp_on_which_table_tr() returns opaque
as '
DECLARE
BEGIN
	NEW.on_which_table:= lower(NEW.on_which_table);
	NEW.permission_type:= lower(NEW.permission_type);
	return NEW;
END;
' language 'plpgsql';

create trigger gp_on_which_table_tr
before insert or update on general_permissions
for each row
execute procedure trig_gp_on_which_table_tr();

-- This trigger normalizes values in the permission_type column to
-- be all lowercase. This makes it easier to implement a case-
-- insensitive API (since function-based indexes do not seem to
-- work as advertised in Oracle 8.1.5). Just make sure to call
-- LOWER whenever constructing a criterion involving
-- permission_type.

-- packaged this in last trigger

-- This view makes it simple to fetch a standard set of
-- permission flags (true or false) for arbitrary rows
-- in the database.
--
create view general_permissions_grid
as
select
 p.on_what_id, p.on_which_table,
 p.scope, p.user_id, p.group_id, p.role,
 case when sum(case when p.permission_type = 'read' then 1 else 0 end)= 0 then 'f'::char else 't'::char end
  as read_permission_p,
 case when sum(case when p.permission_type='comment' then 1 else 0 end)= 0 then 'f'::char else 't'::char end
  as comment_permission_p,
 case when sum(case when p.permission_type= 'write' then 1 else 0 end)= 0 then 'f'::char else 't'::char end
  as write_permission_p,
 case when sum(case when p.permission_type= 'administer' then 1 else 0 end)= 0 then 'f'::char else 't'::char end
 as administer_permission_p
from general_permissions p
group by
 p.on_what_id, p.on_which_table,
 p.scope, p.user_id, p.group_id, p.role;

-- no packages in PG (BMA)
--create or replace package ad_general_permissions
--as
 -- Returns 't' if the specified user has the specified permission on
 -- the specified database row.
 --
-- drop function gp_has_group_role(integer,varchar,integer);
create function gp_has_group_role(integer,varchar,integer) 
returns char as '
declare
        gid     alias for $1;
        role    alias for $2;
        uid     alias for $3;
        exist   char;
begin
        select into exist (case when count(1) is null then ''f'' else
                           case when count(1) = 0 then ''f'' else 
                           ''t'' end end)
          from user_group_map ugm
         where ugm.user_id = uid
           and ugm.group_id = gid
           and ugm.role = role;
           return exist;
end;
' language 'plpgsql';

-- drop function gp_group_member(integer,integer);
create function gp_group_member(integer,integer) returns char as '
declare
        gid     alias for $1;
        uid     alias for $2;
        exist   char;
begin
        select into exist (case when count(1) is null then ''f'' else
                           case when count(1) = 0 then ''f'' else
                           ''t'' end end)
          from user_group_map ugm
         where ugm.user_id = uid
           and ugm.group_id = gid;

        return exist;
end;
' language 'plpgsql';


-- drop function user_has_row_permission_p (integer, varchar, integer, varchar);
create function user_has_row_permission_p (integer, varchar, integer, varchar)
returns char as '
DECLARE
 v_user_id                     alias for $1;
 v_permission_type             alias for $2;
 v_on_what_id                  alias for $3;
 v_on_which_table              alias for $4;
 v_user_has_row_permission_p   integer;
BEGIN
 -- Return true if the permission has been granted to at least one of:
 --
 -- * all users
 -- * registered users if the user is logged in
 -- * the user directly
 -- * a role in a user group that the user plays
 -- * an entire user group of which the user is a member
 --
 select into v_user_has_row_permission_p count(*)
  from general_permissions gp
 where gp.on_what_id = v_on_what_id
   and gp.on_which_table = lower(v_on_which_table)
   and gp.permission_type = lower(v_permission_type)
   and ((gp.scope = ''all_users'')
        or (gp.scope = ''user'' and gp.user_id = v_user_id)
        or (gp.scope = ''registered_users'' and v_user_id > 0)
        or ad_group_member_p(v_user_id,system_administrator_group_id()) = ''t''
        or (gp.scope = ''group''
            and gp_group_member(gp.group_id,v_user_id) = ''t'')
        or (gp.scope = ''group_role''
            and gp_has_group_role(gp.group_id,gp.role,v_user_id) = ''t''));

 return (case when v_user_has_row_permission_p is null then ''f'' else 
         case when v_user_has_row_permission_p = 0 then ''f'' else ''t'' 
         end end);
END;
' language 'plpgsql';


 create function grant_permission_to_user ( integer, varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_user_id		alias for $1;
  v_permission_type	alias for $2;
  v_on_what_id		alias for $3;
  v_on_which_table	alias for $4;
  v_permission_id	general_permissions.permission_id%TYPE;
 BEGIN
  select nextval(''gp_id_sequence'') into v_permission_id;

  insert into general_permissions
   (permission_id, on_what_id, on_which_table,
    scope, user_id, permission_type)
  values
   (v_permission_id, v_on_what_id, v_on_which_table,
    ''user'', v_user_id, v_permission_type);

  return v_permission_id;
 END;
 ' language 'plpgsql';

-- drop function grant_permission_to_role ( integer, varchar, varchar, integer, varchar );
 create function grant_permission_to_role ( integer, varchar, varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_group_id		alias for $1;
  v_role		alias for $2;
  v_permission_type	alias for $3;
  v_on_what_id		alias for $4;
  v_on_which_table	alias for $5;
  v_permission_id	integer;
 BEGIN
  select  into v_permission_id nextval(''gp_id_sequence'');

  insert into general_permissions
   (permission_id, on_what_id, on_which_table,
    scope, group_id, role, permission_type)
  values
   (v_permission_id, v_on_what_id, v_on_which_table,
    ''group_role'', v_group_id, v_role, v_permission_type);

  return v_permission_id;
 END;
 ' language 'plpgsql';

 create function grant_permission_to_group ( integer, varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_group_id		alias for $1;
  v_permission_type	alias for $2;
  v_on_what_id		alias for $3;
  v_on_which_table	alias for $4;
  v_permission_id	general_permissions.permission_id%TYPE;
 BEGIN
  select nextval(''gp_id_sequence'') into v_permission_id;

  insert into general_permissions
   (permission_id, on_what_id, on_which_table,
    scope, group_id, permission_type)
  values
   (v_permission_id, v_on_what_id, v_on_which_table,
    ''group'', v_group_id, v_permission_type);

  return v_permission_id;
 END;
 ' language 'plpgsql';

 create function grant_permission_to_reg_users ( varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_permission_type	alias for $1;
  v_on_what_id		alias for $2;
  v_on_which_table	alias for $3;
  v_permission_id	general_permissions.permission_id%TYPE;
 BEGIN
  select nextval(''gp_id_sequence'') into v_permission_id;

  insert into general_permissions
   (permission_id, on_what_id, on_which_table,
    scope, permission_type)
  values
   (v_permission_id, v_on_what_id, v_on_which_table,
    ''registered_users'', v_permission_type);

  return v_permission_id;
 END;
 ' language 'plpgsql';

-- drop function grant_permission_to_all_users ( varchar, integer, varchar );
 create function grant_permission_to_all_users ( varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_permission_type	alias for $1;
  v_on_what_id		alias for $2;
  v_on_which_table	alias for $3;
  v_permission_id	general_permissions.permission_id%TYPE;
 BEGIN
  select nextval(''gp_id_sequence'') into v_permission_id;

  insert into general_permissions
   (permission_id, on_what_id, on_which_table,
    scope, permission_type)
  values
   (v_permission_id, v_on_what_id, v_on_which_table,
    ''all_users'', v_permission_type);

  return v_permission_id;
 END;
 ' language 'plpgsql';

-- drop function revoke_permission ( integer );
 create function revoke_permission ( integer )
 returns integer as '
 DECLARE
  v_permission_id	alias for $1;
 BEGIN
  delete from general_permissions
  where permission_id = v_permission_id;
  return 0::integer;
 END;
 ' language 'plpgsql';

 create function user_permission_id ( integer, varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_user_id		alias for $1;
  v_permission_type	alias for $2;
  v_on_what_id		alias for $3;
  v_on_which_table	alias for $4;
  v_permission_id	general_permissions.permission_id%TYPE;
 BEGIN
  select permission_id
  into v_permission_id
  from general_permissions
  where on_what_id = v_on_what_id
  and on_which_table = lower(v_on_which_table)
  and scope = ''user''
  and user_id = v_user_id
  and permission_type = lower(v_permission_type);

  if not found then
   return 0;
  else
   return v_permission_id;
  end if;
 END;
 ' language 'plpgsql';

 create function group_role_permission_id ( integer, varchar, varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_group_id		alias for $1;
  v_role		alias for $2;
  v_permission_type	alias for $3;
  v_on_what_id		alias for $4;
  v_on_which_table	alias for $5;
  v_permission_id	general_permissions.permission_id%TYPE;
 BEGIN
  select permission_id
  into v_permission_id
  from general_permissions
  where on_what_id = v_on_what_id
  and on_which_table = lower(v_on_which_table)
  and scope = ''group_role''
  and group_id = v_group_id
  and role = v_role
  and permission_type = lower(v_permission_type);

  if not found then
   return 0;
  else
   return v_permission_id;
  end if;
 END;
 ' language 'plpgsql';

 create function group_permission_id ( integer, varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_group_id		alias for $1;
  v_permission_type	alias for $2;
  v_on_what_id		alias for $3;
  v_on_which_table	alias for $4;
  v_permission_id	general_permissions.permission_id%TYPE;
 BEGIN
  select permission_id
  into v_permission_id
  from general_permissions
  where on_what_id = v_on_what_id
  and on_which_table = lower(v_on_which_table)
  and scope = ''group''
  and group_id = v_group_id
  and permission_type = lower(v_permission_type);

  if not found then
   return 0;
  else
   return v_permission_id;
  end if;
 END;
 ' language 'plpgsql';

 create function reg_users_permission_id ( varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_permission_type	alias for $1;
  v_on_what_id		alias for $2;
  v_on_which_table	alias for $3;
  v_permission_id	general_permissions.permission_id%TYPE;
 BEGIN
  select permission_id
  into v_permission_id
  from general_permissions
  where on_what_id = v_on_what_id
  and on_which_table = lower(v_on_which_table)
  and scope = ''registered_users''
  and permission_type = lower(v_permission_type);

  if not found then
   return 0;
  else
   return v_permission_id;
  end if;
 END;
 ' language 'plpgsql';

 create function all_users_permission_id ( varchar, integer, varchar )
 returns integer as '
 DECLARE
  v_permission_type	alias for $1;
  v_on_what_id		alias for $2;
  v_on_which_table	alias for $3;
  v_permission_id	general_permissions.permission_id%TYPE;
 BEGIN
  select permission_id
  into v_permission_id
  from general_permissions
  where on_what_id = v_on_what_id
  and on_which_table = lower(v_on_which_table)
  and scope = ''all_users''
  and permission_type = lower(v_permission_type);

  if not found then
   return 0;
  else
   return v_permission_id;
  end if;
 END;
 ' language 'plpgsql';

-- This table defines the valid types of permission for each
-- table. Right now, it's only used by the admin pages. We
-- need to figure out if we should use it more broadly.
--
create table general_permission_types (
	table_name	varchar(30) not null,
	permission_type	varchar(20) not null,
	primary key (table_name, permission_type)
);


create view users_view as 
select 
user_id       
,first_names  
,last_name  
,screen_name  
,priv_name       
,email  
,priv_email       
,email_bouncing_p       
,converted_p       
,password   
,url  
,to_char(on_vacation_until,'YYYY-MM-DD') as on_vacation_until     
,to_char(last_visit,'YYYY-MM-DD') as last_visit     
,to_char(second_to_last_visit,'YYYY-MM-DD') as second_to_last_visit     
,n_sessions       
,to_char(registration_date,'YYYY-MM-DD') as registration_date      
,registration_ip    
,user_state   
,to_char(approved_date,'YYYY-MM-DD') as approved_date      
,approving_user        
,approving_note  
,to_char(email_verified_date,'YYYY-MM-DD') as email_verified_date      
,to_char(rejected_date,'YYYY-MM-DD') as rejected_date      
,rejecting_user        
,rejecting_note  
,to_char(deleted_date,'YYYY-MM-DD') as deleted_date      
,deleting_user        
,deleting_note  
,to_char(banned_date,'YYYY-MM-DD') as banned_date      
,banning_user        
,banning_note  
,crm_state    
,to_char(crm_state_entered_date,'YYYY-MM-DD') as crm_state_entered_date      
,lob        
,to_char(portrait_upload_date,'YYYY-MM-DD') as portrait_upload_date      
,portrait_comment  
,portrait_client_file_name   
,portrait_file_type   
,portrait_file_extension    
,portrait_original_width        
,portrait_original_height        
,portrait_thumbnail_width        
,portrait_thumbnail_height        
,bio from users;  


create view users_null as 
select 
''::integer as user_id       
,''::varchar as first_names  
,''::varchar as last_name  
,''::varchar as screen_name  
,''::integer as priv_name       
,''::varchar as email  
,''::integer as priv_email       
,''::char as email_bouncing_p       
,''::char as converted_p       
,''::varchar as password   
,''::varchar as url  
,''::varchar as on_vacation_until     
,''::varchar as last_visit     
,''::varchar as second_to_last_visit     
,''::integer as n_sessions       
,''::varchar as registration_date      
,''::varchar as registration_ip    
,''::varchar as user_state   
,''::varchar as approved_date      
,''::integer as approving_user        
,''::varchar as approving_note  
,''::varchar as email_verified_date      
,''::varchar as rejected_date      
,''::integer as rejecting_user        
,''::varchar as rejecting_note  
,''::varchar as deleted_date      
,''::integer as deleting_user        
,''::varchar as deleting_note  
,''::varchar as banned_date      
,''::integer as banning_user        
,''::varchar as banning_note  
,''::varchar as crm_state    
,''::varchar as crm_state_entered_date      
,''::integer as lob        
,''::varchar as portrait_upload_date      
,''::varchar as portrait_comment  
,''::varchar as portrait_client_file_name   
,''::varchar as portrait_file_type   
,''::varchar as portrait_file_extension    
,''::integer as portrait_original_width        
,''::integer as portrait_original_height        
,''::integer as portrait_thumbnail_width        
,''::integer as portrait_thumbnail_height        
,''::varchar as bio;  

create view user_groups_view as 
select 
group_id      
,group_type  
,group_name 
,short_name 
,admin_email 
,to_char(registration_date,'YYYY-MM-DD') as registration_date    
,creation_user      
,creation_ip_address  
,approved_p      
,active_p      
,existence_public_p      
,new_member_policy  
,spam_policy  
,email_alert_p      
,multi_role_p      
,group_admin_permissions_p      
,index_page_enabled_p      
,body         
,html_p      
,to_char(modification_date,'YYYY-MM-DD') as modification_date     
,modifying_user       
,parent_group_id from user_groups;       


create view user_groups_null as 
select 
''::integer as group_id      
,''::varchar as group_type  
,''::varchar as group_name 
,''::varchar as short_name 
,''::varchar as admin_email 
,''::varchar as registration_date    
,''::integer as creation_user      
,''::varchar as creation_ip_address  
,''::char as approved_p      
,''::char as active_p      
,''::char as existence_public_p      
,''::varchar as new_member_policy  
,''::varchar as spam_policy  
,''::char as email_alert_p      
,''::char as multi_role_p      
,''::char as group_admin_permissions_p      
,''::char as index_page_enabled_p      
,''::text as body         
,''::char as html_p      
,''::varchar as modification_date     
,''::integer as modifying_user       
,''::integer as parent_group_id;       
