Custom user-roles and -permissions in installation script - php

Is it possible to write some code in your .install-file of your D7 website which allows you to generate user roles and permissions automatically? I always though so, but right now, I can't think of a way to do it.
Any advice?

Absolutely:
function mymodule_install() {
// Make the new role
$role = new stdClass;
$role->name = 'new role name';
$role->weight = 3;
user_role_save($role);
// Permissions to assign to the role.
// Note these are defined in hook_permission()
$perms = array(
'access administration pages',
'view content',
'any other permission you want'
);
// Grant the permissions. This function takes care of all necessary cache resets
user_role_grant_permissions($role->rid, $perms);
}

Related

Laravel Entrust, how to attach existing permission to role

Here is my code I am using, it runs fine but when I'm inside the database checking if everything went okay I get this result
Why am I getting 0 for the permission ID and Role ID?
$developer = new Role();
$developer->name = 'Test';
$view_customers = new Permission();
$view_customers->name = 'view_customers';
$view_customers->display_name = 'View Customers';
$developer->attachPermission($view_customers->id);
try this
$developer = Role::where('name','=','Test')->get->first();
//if you want to attach new permission
$view_customers = new Permission();
$view_customers->name = 'view_customers';
$view_customers->display_name = 'View Customers';
//if you want to attach existing permission ex. you already have 'view_customers' in permission table
$view_customers = Permission::where('name','=','view_customers')->get->first();
$developer->attachPermission($view_customers);
attachPermission() works by model or array, if you want atach or detach by id use this
$developer->perms()->attach($view_customers->id);

Moodle cohort_add_cohort error

I'm developing a custom Moodle authentification plugin for Moodle 2.7.
When a user is authenticated I want them to be added to a specific cohort. If that cohort does not exist I need it to be created automatically. I use the user_authenticated_hook() function in my authentification plugin to achieve this.
My code for creating the cohort is this
$data = new stdClass();
$data->name = 'Name string';
$data->idnumber = 'ID string';
$data->description = 'Description string';
$cohortId = cohort_add_cohort($data);
I have included cohort/lib.php in the auth.php file and I have declared the global variables $DB, $CFG and $SESSION at the first line of the user_authenticated_hook() function.
The authentification works without the part about cohorts. But with the cohort part in place authentication fails and I am redirected to the login page.
The page title is changed to "Error" but that is the only error message I get.
What Am I doing wrong? I hope somebody will be able to help me create cohorts and add members.
It might be because the global $USER object doesn't exist yet or hasn't been populated.
Do you have debug switched on in your config.php?
$CFG->debug = 32767;
$CFG->debugdisplay = 1;
It might be better to respond to the user_created event. So if a user is created by another method, they will still be added to the cohort. eg:
Create a local plugin eg:
/local/add_cohorts
Create an events.php
/local/add_cohorts/db/events.php
Which has something like this
$handlers = array (
'user_created' => array (
'handlerfile' => '/local/add_cohorts/lib.php',
'handlerfunction' => 'local_add_cohorts_user_created',
'schedule' => 'instant',
'internal' => 1,
),
);
Then in /local/add_cohorts/lib.php have
function local_add_cohorts_user_created($user) {
// Do your cohort processing here and add the user
// Use $user->id to add to the cohort members
}
Then create a version.php and install the plugin, then the event handler will be registered.
Events api - https://docs.moodle.org/dev/Events_API

yii : how to display the different menu(s) by user role?

Q : How can I show display different menu(s) by user role?
Description : the app has many roles. e.g HR manager, Account Manager, Operating Manager, Employee, Operator, ...., etc. I used rights and yii-user modules to create those roles. Those roles have different functions. So the app will show different menu for different user's role after logged in. Now, I can lock the function for different user. e.g when HR manger logged in, he/she can't route to other function of user role. But I don't know how to show the HR Menu for Hr Manager, only.
I am not a newbie for yii. but I'm a newbie for those modules (rihgts and yii-user).
If you're using RBAC you can set the 'visible' param of CMenu items depending on the users privileges, for example;
$this->widget('zii.widgets.CMenu',array(
'items'=>array(
array(
'label'=>'Home',
'url'=>array('site/index'),
),
array(
'label'=>'HR',
'url'=>array('/hr/index'),
'visible'=>Yii::app()->user->checkAccess('hr')
),
array(
'label'=>'Accounts',
'url'=>array('/account/index'),
'visible'=>Yii::app()->user->checkAccess('account')
),
array(
'label'=>'Operations',
'url'=>array('/operations/index'),
'visible'=>Yii::app()->user->checkAccess('operations')
),
),
);
This way users will only be able to see the items in the menu if they have access privileges for that area.
[EDIT]
As per simaremare's comment below, you can force caching of this query beyond the current request by extending CWebUser. Firstly, set your user to run through your new class (we'll call it TWebUser), so in your main.php config file;
'components'=>array(
'user'=>array(
...
'class'=>'TWebUser',
...
),
...
),
Now we need to create TWebUser to cache these beyond the current request (which is what CWebUser does (source code):
class TWebUser extends CWebUser
{
private $_access=array();
public function checkAccess($operation,$params=array(),$allowCaching=true)
{
if($allowCaching && $params===array() && isset($this->_access[$operation]))
return $this->_access[$operation];
$cache = Yii::app()->session['checkAccess'];
if($allowCaching && !$this->getIsGuest() && isset($cache[$operation]) && time() - $cache[$operation]['t'] < 1800)
{
$checkAccess = $cache[$operation]['p'];
} else {
$checkAccess = Yii::app()->getAuthManager()->checkAccess($operation,$this->getId(),$params);
if($allowCaching && !$this->getIsGuest())
{
$access = isset($cache) ? $cache : array();
$access[$operation] = array('p'=>$checkAccess, 't'=>time());
Yii::app()->session['checkAccess'] = $access;
}
}
return $this->_access[$operation] = $checkAccess;
}
}
Now your access results will be set for the whole session. This does mean that if you edit the RBAC permissions for a given account, they'll have to log out and log in again to see the new changes reflected in the browser.
I hope that helps! I'm sure I found this workaround from someone else (probably on SO), but I can't find the original post to give them credit.
You would wrap an if-statement around the menu-items that you may or may not want to show.
In the if-statement, you would have to test whether the user qualifies to see your menu-items.
For example:
<?php if (Yii::app()->user->isGuest): ?>
<?php $this->widget('zii.widgets.CMenu',array(
'items'=>array(
array(
'label'=>'this menu item visible only for Guests (not logged in)',
'url'=>array('/site/index')),
),
)); ?>
<?php endif; ?>

Preventing Infinite Redirects in Access Control Library

I am working on an Open Source Role Based Access Control Library for PHP called PHP-Bouncer. PHP-Bouncer allows the user to define a list of roles, which pages each role provides access to, and each role may also define a list of pages which override other pages (so going to the overridden page will redirect you to the overriding page). Here is an example of how this would work (From the Access Managed Example in the documentation):
$bouncer = new Bouncer();
// Add a role Name, Array of pages role provides
$bouncer->addRole("Public", array("index.php", "about.php", "fail.php"));
// Add a role Name, Array of pages role provides
$bouncer->addRole("Registered User", array("myaccount.php", "editaccount.php", "viewusers.php"));
// Add a role Name, Array of pages role provides List of pages that are overridden by other pages
$bouncer->addRole("Admin", array("stats.php", "manageusers.php"), array("viewusers.php" => "manageusers.php"));
// Here we add some users. The user class here extends the BouncerUser class, so it can still do whatever you
// would normally create a user class to do..
$publicUser = new User();
$registeredUser = new User();
$adminUser = new User();
$registeredAndAdmin = new User();
$publicUser->addRole("Public");
$registeredUser->addRole("Public"); // We add the public group to all users since they need it to see index.php
$registeredUser->addRole("Registered User");
$adminUser->addRole("Public"); // We add the public group to all users since they need it to see index.php
$adminUser->addRole("Admin");
$registeredAndAdmin->addRole("Public"); // We add the public group to all users since they need it to see index.php
$registeredAndAdmin->addRole("Registered User");
$registeredAndAdmin->addRole("Admin");
$bouncer->manageAccess($publicUser->getRoles(), substr($_SERVER["PHP_SELF"], 1), "fail.php");
Here's the problem I am having: In the manageAccess function you see above, everything works well as long as the roles are defined sanely, and all users have access to fail.php (or fail.php does not implement the $bouncer object). As soon as someone creates a role which has an inherent conflict (such as overriding a page with itself) or fails to give all users access to the failure page, the manageAccess function results in an infinite loop. Since this is bad, I would like to fix it. I am not sure however, what would be the best approach for allowing a few redirects (it is feasible that redirecting up to two or three times could be desired behaviour) while preventing an infinite loop. Here is the manageAccess function:
/**
* #param array $roleList
* #param string $url
* #param string $failPage
*/
public function manageAccess($roleList, $url, $failPage = "index.php"){
$granted = false;
foreach($roleList as $role){
if(array_key_exists($role, $this->roles)){
$obj = $this->roles[$role];
/** #var $obj BouncerRole */
$response = $obj->verifyAccess($url);
if($response->getIsOverridden()){ // If access to the page is overridden forward the user to the overriding page
$loc = ($obj->getOverridingPage($url) !== false) ? $obj->getOverridingPage($url) : $failPage;
$locationString = "Location: ".$loc;
header($locationString);
// I broke something in the last commit, perhaps this comment will help?
}
if($response->getIsAccessible()){ // If this particular role contains access to the page set granted to true
$granted = true; // We don't return yet in case another role overrides.
}
}
}
// If we are here, we know that the page has not been overridden
// so let's check to see if access has been granted by any of our roles.
// If not, the user doesn't have access so we'll forward them on to the failure page.
if(!$granted){
$locationString = "Location: ".$failPage."?url=".urlencode($url)."&roles=".urlencode(serialize($roleList));
header($locationString);
}
}
Any Suggestions?
Since your desired functionality is to allow "a few redirects", the best way I can think of approaching this is creating either a $_SESSION (or $_GET I suppose would work) parameter that you increment every time you issue a redirect. I should point out that from a user standpoint this would be pretty annoying to deal with, but it is your website.
Let's assume we named the $_SESSION parameter num_redirects:
Before we redirect, check to see if $_SESSION['num_redirects'] is set. If it is not, set it to 0.
Get the current value of $_SESSION['num_redirects'], and see if it is above the redirect threshold.
If it is above the threshold, do not redirect, simply die();
If it is not above the threshold, increment $_SESSION['num_redirects'], store it back, and redirect.
So, that code would look like this (I've also improved your URL query string with a call to http_build_query():
Somewhere, we need to define the threshold:
define( 'MAX_NUM_REDIRECTS', 3);
Then, we can do:
// Assuming session_start(); has already occurred
if(!$granted) {
if( !isset( $_SESSION['num_redirects'])) {
$_SESSION['num_redirects'] = 0;
}
// Check if too many redirects have occurred
if( $_SESSION['num_redirects'] >= MAX_NUM_REDIRECTS) {
die( "Severe Error: Misconfigured roles - Maximum number of redirects reached\n");
}
// If we get here, we can redirect the user, just add 1 to the redirect count
$_SESSION['num_redirects'] += 1;
$query_string = http_build_query( array(
'url' => $url,
'roles' => serialize($roleList)
));
$locationString = "Location: " . $failPage . '?' . $query_string;
header($locationString);
exit(); // Probably also want to kill the script here
}
That's it! Note that you'll have to add the same logic for the first call to header(). If you're going to repeat this functionality elsewhere, it might be worthwhile to encapsulate redirection within a helper function:
function redirect( $url, array $params = array()) {
if( !isset( $_SESSION['num_redirects'])) {
$_SESSION['num_redirects'] = 0;
}
// Check if too many redirects have occurred
if( $_SESSION['num_redirects'] >= MAX_NUM_REDIRECTS) {
die( "Severe Error: Maximum number of redirects reached\n");
}
// If we get here, we can redirect the user, just add 1 to the redirect count
$_SESSION['num_redirects'] += 1;
$query_string = http_build_query( $params);
$locationString = "Location: " . $url . ( !empty( $query_string) ? ('?' . $query_string) : '');
header($locationString);
exit(); // Probably also want to kill the script here
}
Then, you can call it like this:
if(!$granted){
redirect( $failPage, array(
'url' => $url,
'roles' => serialize($roleList)
));
}
This way you can encapsulate all of the logic necessary to redirecting within that one function.

How can I grant a specific role In Ubercart?

I'm trying to grant a specific role to users that order an amount equal or greater than 100.00 €: Conditional Actions is going really near the achievement, but I'm failing on the action (PHP required).
How can I grant a role using a PHP action in Ubercart Conditional Actions?
Based on a couple of related threads, I think you want to add an "Execute custom PHP code" action along the lines of the following (substituting in the appropriate role name in line #3):
if($account) {
$uid = $account->uid;
$role_name = 'YOUR SPECIFIC ROLE NAME GOES HERE';
$rid = db_result(db_query("SELECT rid FROM {role} WHERE name = '%s'", $role_name));
// Load user object
$account = user_load(array('uid' => 1));
// Save the user object with the new roles.
if ($account !== FALSE) {
$roles = $account->roles + array($rid => $role_name);
user_save($account, array('roles' => $roles));
watchdog('user', 'uc ca added role to Ubercart created user');
Code provided needs to close two brackets. I dropped the if statements, grabbed the uid from the order and fixed the uid setting (it was '1'):
$uid = $order->uid;
$role_name = 'customer';
$rid = db_result(db_query("SELECT rid FROM {role} WHERE name = '%s'", $role_name));
// Load user object
$account = user_load(array('uid' => $uid));
// Save the user object with the new roles.
$roles = $account->roles + array($rid => $role_name);
user_save($account, array('roles' => $roles));
watchdog('user', 'uc ca added role to Ubercart created user');

Categories