As a result of asking many questions, studying code, and tinkering, I have documented the process I used to create additional acs-subsite roles (in addition to Members and Administrators).
This document describes the use of relation types, relational segments, and application groups, within the context of an acs-subsite. It adds two roles: Guests and Managers, and contains sample tcl api and db calls used to implement the expansion. It should be general enough to be used as guide for others.
I am interested in scrutiny by "those that know", but my real purpose is to provide a shortcut for others that may wish to do the same.
Randy
OACS Subsite Community Roles
Author: Randy O'Meara <omeara at got dot net>
Date: 17 August 2003
The reason I created this extended role system was to provide more granularity in assigning rights and permissions to community members. I wanted to allow access and services to four levels of users, where each increasing level included the rights of the next lower level *plus* some additional rights. The levels I defined, from lowest to highest, were: Guest, Member, Manager, and Administrator. In order to enforce and control access to each separate community, it is necessary to change some default settings including turning of inheritance of permissions from the main site. These steps are included below but are optional if strict community member control and privacy are not at issue.
This document describes one way to go about creating the system. There are decisions to be made at every step, the results of which may lead to other ways to achieve an equivalent end result. For example, it is not necessary to create the pretty-named roles. The decision to not do this would result in the role names not being available through a DB query later to generate a drop-down selection list. However, the role names and their values could be hard coded at the appropriate place and used in place of the query that retrieves this information.
Beware... This document was created after I spent hours researching, perusing code, posting to forums, tinkering, and testing. Thanks to the few that guided me in the right direction! Part of the difficulty in creating this code was that there really are (at least, were) no working examples of a role system based on acs-subsite and application groups. As such, there may be far easier methods to do what I've done here. I have (minimally) tested the code included in the examples below. But...not exhaustively, and NOT IN PRODUCTION. I am interested in errors you may find. Please let me know what you find.
The process described below consists of the following steps:
1) Create Relation Types
2) Instantiate Subsite
3) Modify Default Subsite Policy
4) Create Relational Segments and Apply Privileges
5) Assign User to a Role
6) Use the OACS permissions:: System to Control Actions and Access
The first step is to create pretty-named roles:
# Create rel_types
set m_rel_type [rel_types::new \
-supertype "membership_rel" \
-role_one "" \
-role_two "guest" \
"guest_rel" \
"Guest" \
"Guests" \
"group" \
"0" \
"" \
"person" \
"0" \
"1"]
rel_types::add_permissible application_group guest_rel
set m_rel_type [rel_types::new \
-supertype "membership_rel" \
-role_one "" \
-role_two "manager" \
"manager_rel" \
"Manager" \
"Managers" \
"group" \
"0" \
"" \
"person" \
"0" \
"1"]
rel_types::add_permissible application_group manager_rel
Subsite Policy Modification
Subsite permission inheritance can be eliminated with the permissions
subsystem.
The subsite is created, mounted in the site map, and accessible at "/subsite1". The community package_id (comm_obj_id) is returned and used to further modify the subsite. All of the information for this subsite node (including its package_id) may be retrieved at a later time with the site_node::get_from_url -url "/subsite1" tcl api call.
1) a gurantee that the applicant is a Main Site "Registered User", and
2) the applicant possesses the correct invitation code.
Once these conditions are staisfied, the user-join page adds the applicant to the subsite's application group, but with a member_state of "needs approval". Until a subsite Manager or Administrator assigns the applicant to one of the pre-defined roles, the applicant cannot access the subsite. The action of assigning the applicant to a role simultaneously changes the applicant's member_state to "approved".
The process of assigning the applicant to a community role can be performed any number of ways. One way might be to use ad_form with a drop-down role list populated by
Ultimately, to change/add/remove a user in a role, the following tcl api calls are used. To change a user's role, first remove the existing relation and then add the new relation:
OACS Subsite Community Roles
Author: Randy O'Meara <omeara at got dot net>Date: 17 August 2003
Summary
This document describes the addition and utilization of an expanded role system. This expanded role system is based on acs-subsite, its associated application group, and relational segments. We assume that the application group is created (as it is in oacs 4.6) at subsite instantiation. At the same time, two relational segments are also created: the Members and Administrators segments. This document describes the steps and calls required to create and assign additional roles within an subsite-based community.The reason I created this extended role system was to provide more granularity in assigning rights and permissions to community members. I wanted to allow access and services to four levels of users, where each increasing level included the rights of the next lower level *plus* some additional rights. The levels I defined, from lowest to highest, were: Guest, Member, Manager, and Administrator. In order to enforce and control access to each separate community, it is necessary to change some default settings including turning of inheritance of permissions from the main site. These steps are included below but are optional if strict community member control and privacy are not at issue.
This document describes one way to go about creating the system. There are decisions to be made at every step, the results of which may lead to other ways to achieve an equivalent end result. For example, it is not necessary to create the pretty-named roles. The decision to not do this would result in the role names not being available through a DB query later to generate a drop-down selection list. However, the role names and their values could be hard coded at the appropriate place and used in place of the query that retrieves this information.
Beware... This document was created after I spent hours researching, perusing code, posting to forums, tinkering, and testing. Thanks to the few that guided me in the right direction! Part of the difficulty in creating this code was that there really are (at least, were) no working examples of a role system based on acs-subsite and application groups. As such, there may be far easier methods to do what I've done here. I have (minimally) tested the code included in the examples below. But...not exhaustively, and NOT IN PRODUCTION. I am interested in errors you may find. Please let me know what you find.
The process described below consists of the following steps:
1) Create Relation Types
2) Instantiate Subsite
3) Modify Default Subsite Policy
4) Create Relational Segments and Apply Privileges
5) Assign User to a Role
6) Use the OACS permissions:: System to Control Actions and Access
Relation Types Creation
Recall that we need only create the Guest and Manager roles since the Member and Administrator roles already exist.The first step is to create pretty-named roles:
set role guest; set pn Guest; set pp GuestsThe second step is to create relation types:
db_1row new_role {
select acs_rel_type__create_role(:role, :pn, :pp)
}
set role manager; set pn Manager; set pp Managers
db_1row new_role {
select acs_rel_type__create_role(:role, :pn, :pp)
}
# Create rel_types
set m_rel_type [rel_types::new \
-supertype "membership_rel" \
-role_one "" \
-role_two "guest" \
"guest_rel" \
"Guest" \
"Guests" \
"group" \
"0" \
"" \
"person" \
"0" \
"1"]
rel_types::add_permissible application_group guest_rel
set m_rel_type [rel_types::new \
-supertype "membership_rel" \
-role_one "" \
-role_two "manager" \
"manager_rel" \
"Manager" \
"Managers" \
"group" \
"0" \
"" \
"person" \
"0" \
"1"]
rel_types::add_permissible application_group manager_rel
Subsite Instantiation
A subsite can be instantiated and mounted directly below the root (Main Site) with the following tcl api call:set comm_obj_id [site_node::instantiate_and_mount \The subsite is created, mounted in the site map, and accessible at "/subsite1". The community package_id (comm_obj_id) is returned and used to further modify the subsite. All of the information for this subsite node (including its package_id) may be retrieved at a later time with site_node::get_from_url -url "/subsite1" .
-node_name "subsite1" \
-package_name "subsite1 Community" \
-package_key "acs-subsite"]
Subsite Policy Modification
Subsite permission inheritance can be eliminated with the permissions
subsystem.# Do not inherit permissions from the main siteThe subsite member join policy can be restricted.
permission::set_not_inherit -object_id $comm_obj_id
# Get the subsite application group
set app_grp [application_group::group_id_from_package_id \
-package_id $comm_obj_id]
# Set subsite application group join_policy to "needs approval"
db_dml update_join_policy {
update groups
set join_policy = 'needs approval'
where group_id = :app_grp
}
# There is another location to set the join policy?
# Oh well, for good measure...
parameter::set_value -package_id $comm_obj_id \
-parameter RegistrationRequiresApprovalP -value 1
Relational Segments Create & Permission
When all is said and done, we want four relational segments that coincide with the four roles we defined earlier. Two of these segments already exist by way of acs-subsite instantiation: Members and Administrators. We need to create the Guests and Managers segments. In addition to creating the segments, we need to assign the standard oacs privileges to each segment. The code below actually removes the "create" privilege from the previously created Members segment. You may not want to do this. Later, a user will be related to the subsite application group through a particular type of relation, and the user will obtain privileges based on the relation.# Create and grant: GuestsThe last section "Get the Administrators segment" is shown for completeness although it's not necessary. This also shows how to retrieve the segment IDs if needed. You might want to stash g_seg, u_seg, m_seg, and a_seg.
set g_seg [rel_segments_new $app_grp \
guest_rel "subsite1 Guests"]
permission::grant -party_id $g_seg \
-object_id $comm_obj_id -privilege read
# Create and grant: Managers
set m_seg [rel_segments_new $app_grp \
manager_rel "subsite1 Managers"]
permission::grant -party_id $m_seg \
-object_id $comm_obj_id -privilege read
permission::grant -party_id $m_seg \
-object_id $comm_obj_id -privilege create
permission::grant -party_id $m_seg \
-object_id $comm_obj_id -privilege write
# Get the "Members" segment and remove the create priv
set u_seg [db_string rel_seg_id_get {
select segment_id
from rel_segments
where group_id = :app_grp
and rel_type= 'membership_rel'
} -default ""]
permission::revoke -party_id $u_seg \
-object_id $comm_obj_id -privilege create
# Get the "Administrators" segment
set a_seg [db_string rel_seg_id_get {
select segment_id
from rel_segments
where group_id = :app_grp
and rel_type= 'admin_rel'
} -default ""]
The subsite is created, mounted in the site map, and accessible at "/subsite1". The community package_id (comm_obj_id) is returned and used to further modify the subsite. All of the information for this subsite node (including its package_id) may be retrieved at a later time with the site_node::get_from_url -url "/subsite1" tcl api call.
Community Member Role Assignment
Ahhh! We can finally assign a prospective community member to a role. I'm certain that there are many methods of obtaining the user_id that we wish to use in role assignment. The method I used was to have the cummunity applicant apply for membership through a slightly modified /register/user-join page. The standard oacs user-join page was modified to accept (in its query vars) a valid application group_id, an invitation code, and then to validate the user by a call to ad_maybe_redirect_for_registration. This modified page, along with the subsite "join policy" changes that were made above, result in:1) a gurantee that the applicant is a Main Site "Registered User", and
2) the applicant possesses the correct invitation code.
Once these conditions are staisfied, the user-join page adds the applicant to the subsite's application group, but with a member_state of "needs approval". Until a subsite Manager or Administrator assigns the applicant to one of the pre-defined roles, the applicant cannot access the subsite. The action of assigning the applicant to a role simultaneously changes the applicant's member_state to "approved".
The process of assigning the applicant to a community role can be performed any number of ways. One way might be to use ad_form with a drop-down role list populated by
# Get subsite node_idand use the "-REMOVE-" flag to trigger a relation removal.
set role_opts [group::get_rel_types_options \
-group_id $app_grp]
lappend role_opts [list -REMOVE- -REMOVE-]
Ultimately, to change/add/remove a user in a role, the following tcl api calls are used. To change a user's role, first remove the existing relation and then add the new relation:
# Retrieve a user's role along with other user information
set rel_id [db_0or1row role_get {
select
pe.last_name || ', ' || pe.first_names as name,
pa.email as email,
pe.person_id as member_id,
mm.rel_type as role,
mm.rel_id as rel_id,
mr.member_state as member_state
from group_member_map mm, membership_rels mr,
parties pa, persons pe
where mm.member_id = pe.person_id
and mm.member_id = pa.party_id
and mm.rel_id = mr.rel_id
and mm.group_id = :app_grp
and pe.person_id = :member_id
}]
# Remove a user from a role
relation_remove $rel_id
# Add a user in a role
relation_add -member_state "approved" \
$role $app_grp $member_id
Request notifications