Drupal 7: Using Rules to add user to OG then assign OG role - drupal-7

The idea is to accomplish the following when a new user is added:
Create a new group (OG)
Save it
Add user to saved group (OG)
Assign group role (OG)
I am using Rules with Organic Groups. All is fine apart from assigning the group role. I know you can add general system roles but does anyone know how to assign a group (OG) role programmaticaly so it happens automagically?
Any help much appreciated

I use the following custom php action on a rule, to add user to group and assign OG role.
OG role numbers appear to be in order of OG roles, as viewed through admin/config OG entries.
global $user;
// Load the user we want to add to the group
$account = user_load($user->uid);
// Add the user to the group - hard code group 18 which is my group as cant
// get PID from Ubercart order, to pull gid from nid. User, current user, active,
// etc., all default in 2nd array() param to og_group.
og_group(18);
// Changes the users role in the group (1 = non-member, 2 = member, 3 = administrator member, 4 = Forum Administrator)
og_role_grant(18, $account->uid, 2);
Note, OG role 4 (forum administrator) is a custom OG role I created. Also, 'member' (2) is the default, I believe, but I put this in so I'd remember how to allocate other OG roles if I needed to in future.
I'm not a php guru unfortunately, and I still havent worked out how to pull the pid from the node of the Ubercart product ordered so I can get its gid and hence not hard code the gid of 18.
Hope the above code snipped (og_role_grant mainly) works for you as a rule action custom php code snippet (remember not to include the php tags at top and bottom as rules does this for you).
If you have any thoughts on my problem of getting the gid of the ordered ubercart product, as above, please feel free to share. :)
Best wishes

There is a proposed Organic Group patch that add this functionality to the Organic Group Rules integration.
You can find the patch here: https://drupal.org/node/1327326
It adds Grant and Revoke role actions.

You can use og_role_grant($group_type, $gid, $uid, $rid) to assign a role to a user into an organic group programmatically.
To use this with rules, you can define a custom action using hook_rules_action_info() .

Related

Drupal 7 Organic Groups: Cannot Specify Membership Type

I have an og course group type (not group content). I need to add members to the created groups. I have two groups: students and instructors.
I have added two OG memberships types ("student membership" and "instructor membership") each with a different set of fields that the user should submit when subscribing to a group:
1- Student
2- Instructor
The problem is that the fields that appear are only those in the "default" membership type and neither the members (students or instructors) nor the admin can select the membership type.
I am also struggling to understand where I should specify the membership type for each group type.
Can anyone provide a step by step guide for this?
P.N: I also keep seeing this message Notice: Undefined index: membership_type in og_entity_property_info() (line 236 of /home/devkat/public_html/albinacourses/sites/all/modules/og/og.module).
Thanks a million!

restricting aro scope in cakephp

Ok, I'll preface this by saying i'm a noob to cake and ACL, and MVC architecture. I'm following a cakephp tutorial from its site, http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/part-two.html. I understand the content of the tutorial, but wonder about the easiest way to take this simple group based ACL to the next level. I've searched SO to no avail. So, on with the question.
Lets take a slightly modified version of the function in the above tutorial, for example. It simply sets up ARO permissions for ACOs.
There are many districts, and many departments, all with many users, in each.
relationships are as follows:
A district hasMany Departments -- one to many.
A district has many users, and users can potentially have many districts(so long as they belong to a dept in that district).
A department hasAnBelongsToMany Users -- many to many.
public function initDB() {
$group = $this->User->Group;
//Allow admins to everything
$group->id = 1;
$this->Acl->allow($group, 'controllers');
// issue 1) allow district managers to districts, departments, users
$group->id = 2;
$this->Acl->deny($group, 'controllers');
$this->Acl->allow($group, 'controllers/Districts');
$this->Acl->allow($group, 'controllers/Departments');
$this->Acl->allow($group, 'controllers/Users');
//issue 2) allow department managers to edit departments and users
$group->id = 3;
$this->Acl->deny($group, 'controllers');
$this->Acl->allow($group, 'controllers/Departments');
$this->Acl->allow($group, 'controllers/Users');
//we add an exit to avoid an ugly "missing views" error message
echo "all done";
exit;
}
Ok, so these permissions being set-up, although it's definitely convenient, really solve a small part of the problem. As it stands, I've really only prevented the department admins from performing district level functions. Both district admins and dept admins can perform user CRUD without restrictions
What i'd like to do, is limit the scope of each of the admin types USER CRUD to only those users residing within their department or district. for example, Department Admin Foo can't delete another Dept Admin's Users, and Dist Admin Bar can't change all of another Dist Admin's Users first names to nancy.
lol. I'm seriously at a loss with how to accomplish this.
I guess one approach would be get an administrators rank, dist admin for example, then figure out in which district he is a user. lastly, return all of the users in this district into a variable $userScope. Again, I am new to cake php and would be unsure of how to carry out the this proposal, even if it were a good idea and the best way to handle this. Any suggestions?? Thanks in advance!!!
edit: helpful answer, #nicolae.
however, it still seems that i could write a function that returns all users that any given admin(of any given aco) is permitted to edit. is seems this way to me because i'm assuming the admin, him/herself to be a part of the returned user base. for example, dist admin of dist 9, resides in dist 9; likewise, dept admin of dept 1, resides in dept 1.
could i write something like:
public getUserScope(){
$id = $this->Auth->user('id');
$dept = $this...
$dist = $this...
$access_level = $this->Session->read('Auth.User.group_id');
if($access_level == 3){
//get all users in this user's dept
} elseif($access_level == 2) {
//find all users in this user's dist
} elseif($access_level == 1) {
//find all users
}
}
ouch. granted all of the join tables involved in bringing this info together, this is bound to look like medusas hair when actually typed up. can you see my line of logic. this is a bit difficult for me to articulate. let me know if i should clarify anything further.
So you're trying to set up an ACL system that manages restrictions based on more than group ID and controller/action - you need department- and district-based restrictions.
As far as I know, the embedded ACL system in CakePHP can not manage this level of restrictions.
As a solution, I recommend you allow the users to the places they need to access (e.g. dept admins have ACL access to the user CRUD interface) and insert specific restrictions in the controller.
function editUserFromDepartment($userId = NULL) {
// Custom ACL check
if (! $this->__checkDepartmentByUserId($userId)) {
// Show the user a custom error message and redirect him to index page
}
// User editing code ...
}
function __checkDepartmentByUserId($userId) {
$dept = $this->Department->getByUserId($userId);
// Check if the current user belongs to this department
$currentUserDepartmentId = $this->Session->read('Auth.User.department_id');
return ($dept['Department']['id'] != $currentUserDepartmentId);
}
Good luck and let me know if my explanation was clear enough.
Nicolae
Edit (trying to answer to #Todd's edit):
I get your point.
Your code aims at obtaining all users of that the current user has access of.
Rather than that, I would have an event-based approach: when the user X tries to be edited, perform a query that finds if Auth.User is allowed to perform this action on user X.
E.g. You (Todd) are trying to edit my profile (NicolaeS) to change my employee ID, as my current one is wrong.
The function $this->getUserScope('user-ID-of-NicolaeS') will check if your department ID or district ID is the same as main and allow/disallow you to continue in your actions according to this check.
Does this look clear/straightforward enough?
Greets,
Nicolae

Prepopulating group_audience field in Drupal 7 (Organic Groups)

I'm trying to get the prepopulate module to work with og with little success. From what I understand I can do ?edit[group_audience]=123, and by going through the code it seems the prepopulate plugin does what it is supposed to, and sets the dropdown #value to 123, but for some reason this doesn't work at all.
I've also found some information saying that it is possible to prepopulate the field using ?gids[]=123, has anyone had success with this, or has a real proper solution?
So... the right way to do this for D 7.22 and OG 7.x-2.1 is:
node/add/[content-type-machine-name]?og_group_ref=[group-id]&destination=node/[group-id]
The above answers did not work for my setup.
See how I wasted my Sunday on this here: Drupal Organic Groups Pre-populated Audience Field
Did you try ?edit[group_audience][]=123 ?
Group audience is a multiselect box so it is possible that you need to use this syntax that allow to set multiple values.
?edit[group_audience][]=123&edit[group_audience][]=42&edit[group_audience][]=1
Don't need the prepopulate module:
?gids_group[]=123
Found this in the Organic Groups readme:
You may craft your own URLs which produce useful behavior.
For example,
node/add/group-content?gids_node[]=4
will add a select the group with node ID 4, in the node form.
The prefixed entity can change to indicate other entity
types allowing crafting the URL and you can have multiple variables,
for example,
node/add/group-content?gids_node[]=4&gids_user[]=3&gids_group[]=5,6,7
The above URL will select the group with node ID 4, and the group with user ID
3, and the groups with the unique group ID 5, 6 and 7.
Note that the actual entity of group ID 5, 6 and 7 can be any entity (e.g.
nodes or users).
By appending ?gids[]= to your node/add URL, you can specify the group audience. By throwing in a comma-delimited list of nids, you can specify multiple audiences.
For Drupal 7, with og 7.x-2.1, you need to have the entity reference prepopulate module installed (and follow the instructions in its readme). Once you do that, then the rest works like magic. Without that module installed/enabled, nothing happens when you try to do what is below. This url achieves the desired result of pre-poulating og_group_ref field with the group with id 1135:
http://[site]/node/add/group-post?og_group_ref=1135

CakePHP Access Allocation on Role Based specific Data Access

My project requirement is something like this:
On Top, there will be Administrator, who will have all d access, first level
Under Administrator, there will be Department Heads, who will have all d access, apart from Creating Department Heads
Under Department Head, there will Other Members, who will be managing their allocated department wise data.
Now, all different department heads will have their own information and members, and all department heads / Members will have access to their own specific records, which they are entering / managing.
Now, with CakePHP's ACL Component, I can divide the roles and their access level, but all department heads can see the other department head's information, as they will have same level of access, and All Other Members can see the other members information on diff departments, as of they will have same level of access.
My project complexity is that - they should be visible only their assigned or created information / data, though they have same level / role assignments as of others.
Can anyone suggest me best suitable option, to manage all these things with already available plug-ins with CakePHP.
I can work by customizing the default ACL Component, but that will take some more amount of time, than what is expected.
Any better ideas / suggestions would be appreciated !
the way i see it, ACL is not that magical. For exemple: ACL could manage the permissions to tell who has access to add/edit/remove a product.. but it wont be able to change a query to filter the products accordingly to the defined permissions (like "users from department A can only see products from department A").. well actually that's a lie, ACL could manage that but it might not be practical, because every time you add a product you'd have to create an ACO, and set the permission in the AROS_ACOS table and since the AROS is a tree structure, so it could easily become a nigthmare, if your planning to query your data
I'd use a group-only ACL to control the access to certain pages/actions and make rules like:
"Department Head can access the page
'products list' and add/delete/modify
products"
"Administrators can access
all pages"
"Other users can access
'products list' and they can add
products but not delete them"
and i'd adjust my queries accordingly to the connected user, so in the controller of 'products list' page, i'd do something like:
If connected user blongs to Department Head then select all products where product.department_id=connected_user.department_id
If connected user is Admin then select all products
if you have too much queries and you dont want to do thousands of if's sentences, you could create a component, a behavior or maybe extend the find() method in the app_model. The idea is to catch all queries and check if one of the models used on the query have field called "department_id", if they do then add the model.department_id=connected_user.department_id condition to the query.
I did that for one website that can be seen in multiple languages and each language has it's own users, data, logs, etc., and there's one Admin that can see all the info.. and it's working great for me =)
Good Luck!
EDITED:
the behavior i use is:
<?php
class LocalizableBehavior extends ModelBehavior {
/**
* Filter query conditions with the correct `type' field condition.
*/
function beforeFind(&$model, $query)
{
/**
* Condition for the paginators that uses joins
*/
if(isset($query['joins']) && !empty($query['joins'])){
foreach($query['joins'] as $key => $joinTable){
if(ClassRegistry::init($joinTable['alias'])->hasField('lang')){
$query['joins'][$key]['conditions'][] = $joinTable['alias'].".lang = '".$_SESSION['lang']."'";
}
}
}
/**
* condition for the normal find queries
*/
if($model->hasField('lang') && $model->name != "User"){
$query['conditions'][$model->name.'.lang'] = $_SESSION['lang'];
}
return $query;
}
}
?>
it's quite simple really, i change the query to add a condition to match to the current language ($_SESSION['lang']). In the controller all i need to do is to attach the LocalizableBehavior and use find method as usual:
$this->Products->find('all');

Select distinct users with referrals

I have a bunch of Users. Since Django doesn't really let me extend the default User model, they each have Profiles. The Profiles have a referred_by field (a FK to User). I'm trying to get a list of Users with >= 1 referral. Here's what I've got so far
Profile.objects.filter(referred_by__isnull=False).values_list('referred_by', flat=True)
Which gives me a list of IDs of the users who have referrals... but I need it to be distinct, and I want the User object, not their ID.
Or better yet, it would be nice if it could return the number of referrals a user has.
Any ideas?
Took me a long time to wrap my head around this, but I think I finally got it figured out:
affiliates = User.objects.annotate(num_referrals=Count('referrals')).filter(num_referrals__gt=0)
I didn't think I'd be able to use the reverse relationship
referred_by = models.ForeignKey(User, null=True, blank=True, related_name='referrals')
in Count(), nor did I think you could use the annotated value in the filter... that's pretty cool. I still wish you could use GROUP BY without having to annotate stuff (assuming I didn't need the count).

Resources