Forum OpenACS Development: Group definitions and use

Collapse
Posted by Nikolay Blyumberg on
I am developing a package for OpenACS 4.0. The requirements are asking for multiple user types

  • Administrator (this can be satisfied with ACS Admin
  • Manager - can create other managers, supervisors and users
  • Supervisor - can create regular users
  • User - regular user

  • All of the users can run a query on a specific device or look at the history of the queries on the specific device.
    The way I have designed my pages is the following: Going to the main page will check to see if you're authorized Depending on group you're in you can see links. Then when a supervisor, manager or admin go to add users the drop down will be populated with more options if the user has the authority to add those types of users. The problem I have is the following:

    In my package-create.sql I define new groups and their permissions but apparently I am not doing this correctly because when I go to group/group type administration my groups are not listed there. However, they are in the Oracle database. I have a good grasp of how the permissions work, it's the coding part that's getting the best of me...If anyone has any suggestions, links or examples I will gladly follow up on them..

    Thanks, Nick

    Collapse
    Posted by Graeme Walters on
    Hi, I've been through a similar process. If you want to send me your package-create.sql script I might be able to suggest something.

    Graeme

    Collapse
    Posted by Nikolay Blyumberg on
    Ok, I'll do that once I have access to the file...
    We had a brownout and the server the files are on isn't configured to launch SSHd on boot...

    I did manage to figure out a couple of things, but I think there should be a few extra additions to my create.sql to make the relationships since my groups are being created

    Collapse
    Posted by Andrew Piskorski on
    Nick, there are several obvious ways of creating ACS users and groups which work, but which don't do everything the ACS expects. For example, you need to use acs.add_user(), not acs_user.new(). Naturally, the differences between these various functions are not documented. Your problem is probably that you did the obvious thing, which left out some fiddly step that the ACS assumes was done.

    Your best bet is to look carefully at the existing ACS login and admin pages that create users and groups, and do it the same way.

    But for comparison, here's some Oracle PL/SQL code that I used in testing an ACS 4.2 site. If I remember correctly, this code creates users and groups exactly the same way as the ACS 4.2 UI pages do, and it also expunges them from the system cleanly and completely. (I don't know if any of this low level user/group stuff has been changed for OpenACS 4, but I suspect not.)

    Creates a test user and group:

    declare
      v_group_id    integer;
      v_person_id   integer;
      v_rel_id      integer;
    begin
      -- Create company A:
      v_group_id := p_account.new(
         v_account_code => 'A'
        ,v_context_id => p_const.package_id_is
      );
    
      v_person_id := acs.add_user (
        email       => 'x@a.com',
        first_names => 'X',
        last_name   => 'X',
        password    => 'X',
        salt        => 'X'
      );
    
      -- add X into A
      v_rel_id := membership_rel.new(
         object_id_one => v_group_id
        ,object_id_two => v_person_id
      );
    end; 
    /
    show errors
    

    Deletes the test user and group:

    (Now, why this calls acs_group.delete instead of p_account.delete, I don't know. Probably that's a bug.)

    declare
      test_users    pl_list.integer_list;
      test_groups   pl_list.integer_list;
      test_parties  pl_list.integer_list;
    begin
      select party_id  bulk collect into test_users
      from parties
      where email in ('x@a.com', 'y@b.com') ;
    
      select party_id  bulk collect into test_groups
      from parties
      where party_id in (
        select account_id  from p_accounts
        where account_code in ('A', 'B')
      );
    
      select party_id  bulk collect into test_parties
      from parties
      where email in ('x@a.com', 'y@b.com')
      or party_id in (
        select account_id  from p_accounts
        where account_code in ('A', 'B')
      );
    
      for i in test_groups.first .. test_groups.last loop
        acs_group.delete(test_groups(i));
    
        -- Note that deleting the group also deletes the membership_rels for
        -- the group, so we don't have to do it explicitly - imagine that!
      end loop;
     
      for i in test_users.first .. test_users.last loop
        for j in (
          select rel_id  from acs_rels
          where rel_type = 'membership_rel'
            and object_id_two = test_users(i)
        ) loop
          membership_rel.delete(j.rel_id);
        end loop;
    
        delete from acs_permissions p
        where p.object_id  = test_users(i)
           or p.grantee_id = test_users(i) ;
        
        acs_user.delete(test_users(i));
        -- Note that acs.remove_user simply delets the row from the users table,
        -- which is not what we want!
      end loop;
    end;
    /
    show errors
    

    Some other stuff:

    Of course, I'd extended the ACS groups table with a "p_accounts" table, so here's the part that actually calls the ACS group create function:

    create or replace package body p_account
    is
    
    
    function new (
       v_account_code         in p_accounts.account_code%TYPE
      -- AKA group_name:      
      ,v_account_pretty_name  in groups.group_name%TYPE  default null
      ,v_allow_auto_join_p    in p_accounts.allow_auto_join_p%TYPE  default 't'
      ,v_account_id           in p_accounts.account_id%TYPE default null
      ,v_creation_date        in acs_objects.creation_date%TYPE  default sysdate
      ,v_creation_user        in acs_objects.creation_user%TYPE  default null
      ,v_creation_ip          in acs_objects.creation_ip%TYPE    default null
      ,v_context_id           in acs_objects.context_id%TYPE     default null 
    ) return p_accounts.account_id%TYPE
    is
      v_id  integer;
      w_account_pretty_name  groups.group_name%TYPE;
    begin
      if v_account_pretty_name is null then
        w_account_pretty_name := v_account_code;
      else
        w_account_pretty_name := v_account_pretty_name;
      end if;
    
      v_id := acs_group.new(
         group_id       => v_id
        ,object_type    => 'p_account'
        ,creation_date  => v_creation_date
        ,creation_user  => v_creation_user
        ,creation_ip    => v_creation_ip
        ,context_id     => v_context_id
        ,group_name     => w_account_pretty_name
      );
    
      insert into p_accounts (
        account_id, account_code, address_id
        ,allow_auto_join_p
      ) values (
        v_id, v_account_code, null
        ,v_allow_auto_join_p
      );
    
      return v_id;
    end new;
    
    
    procedure delete (
      v_account_id  in p_accounts.account_id%TYPE
    )
    is
    begin
      -- Our application logic says that any address mapped directly to the
      -- account belongs ONLY to that account, so if we're deleting the account
      -- delete the address too:
      delete from p_addresses  where address_id = (
        select address_id  from p_accounts
        where account_id = v_account_id
      );
    
      delete from p_accounts where account_id = v_account_id;
    
      delete from acs_permissions p
      where p.object_id  = v_account_id
         or p.grantee_id = v_account_id ;
    
      acs_group.delete(v_account_id);
    end delete;
    
    
    end p_account;
    /
    show errors
    
    Collapse
    Posted by Nikolay Blyumberg on
    Hi Andrew, thank you for your post, it has a lot of useful information. What I was trying actually succeeded to some extent. It was creating special group types like Manager and Supervisor, however, it was not telling ACS to create a group of that type. So if I went to the user interface and made them manually it worked. My code for doing it is below, but I will modify it once I understand your way of doing it a bit better.

    One of the questions I have about your delete stuff is: Does it actually remove the user from the system? And does it keep the data created by that user intact? One of my current problems is that when I try to "delete" a user in OpenACS it simply marks them as "inactive" and hides them but they can be "un-deleted". So if a different person gets the same e-mail address I can't add them to the system.

    My code for creating user types:

    --create priviledged users here
    --first create the manager
    
    declare
    	v_group_id	integer;
    	default_context	acs_objects.object_id%TYPE;
    begin
    	default_context := acs.magic_object_id('default_context');
    	select count(group_id) into v_group_id
    	from groups
    
    
    	where group_name='Manager';
    
    	if v_group_id = 0 then
    		v_group_id :=acs_group.new (group_name => 'Manager');
    	else
    		select group_id into v_group_id from groups where group_name='Manager';
    	end if;
    
    	acs_privilege.create_privilege ( 'manager' );
    	acs_privilege.add_child( 'manager' );
    
    	acs_permission.grant_permission( default_context, v_group_id, 'manager');
    end;
    /
    show errors
    
    And a supervisor which is identical to above but with 'Supervisor' instead of 'Manager'
    Collapse
    Posted by Andrew Piskorski on
    Nick, the code I posted was for handling test users, so it definitely
    does NOT preserve their content.  We used very similar code for load
    testing, and we sure wouldn't have wanted to preserve all that
    "content"!  In fact, it was important to delete it all cleanly so that
    I could change the number of users and groups or whatever and try it
    all again.

    Re. the ACS "delete" function - that's what "delete a user" does by
    design.  It is perhaps poorly named.  Note that a user may in fact
    delete himself, and then undelete himself, with no adverse effects.

    There is "nuke a user", but as you've noticed, there is no "really
    delete a user but preserve content".

    I've never messed around with the user and group type features of ACS
    4, so I can't really comment there.