Drupal user permissions & odd content types - drupal

I have a permissions problem in Drupal. I want users to be able to create a certain node type, but there are two different paths I need to give them permissions for to let them do this. The type is content created by a module called isbn2node, and there are two ways to make content through it, each with different paths:
?=node/add/isbn2node-book
?=node/add/isbn2node_book/isbn2node
One has an underscore and the other one has a hyphen. The first path leads to a form that lets users enter information on a book manually; the second path lets them enter an ISBN, searches for it, and populates the form for them based on the results.
I've changed permissions in the People menu so they can add isbn2node-book content manually using the first path, but there isn't an option to let them use the second method. Aliasing the url so it didn't have node/add in the path didn't work either.
Creating a duplicate content type seems like an ugly solution to this; is there a more elegant way to let users access that second path?

A little code in a custom module using hook_node_access should do it.
$node is either a node object or the machine name of the content type on which to perform the access check (if the node is being created then the $node object is not available so it will be a string instead).
So this should do it:
function MY_MODULE_node_access($node, $op, $account) {
if ($op == 'create') {
$type = $node;
if($type == 'book' && $account->uid) return NODE_ACCESS_ALLOW;
}
}

I figured this out, and the issues I was having were specific to this content type. The ISBN2Node module requires users to have the Administer Nodes permission to use its lookup and bulk import features.
There is some extra code for the module's hook_permission and hook_menu sections submitted as a fix in the module's issues thread.

Related

List of permissions for Drupal8 routing file

I'm working on custom Drupal8 module. My module uses this routing file:
kalvis.routing.yml
kalvis.content:
path: '/kalvis/{from}/{to}'
defaults:
_controller: '\Drupal\kalvis\Controller\kalvisController::content'
_title: ''
requirements:
_permission: 'access content'
What does _permission part stand for and where can I find a list of all possible values for this parameter?(in tut's I've watched were used only access content and access administrative content but I suppose there is a lot more of them)
PS: I'm using Drupal 8 beta 10 installed on WAMP
If you want to see a list of all permission, the code below should work. work. If you are coding your own module you can define your own permissions and test if a user has a role with that permission.
function my_module_page_attachments_alter(array &$attachments) {
$perms = array_keys(\Drupal::service('user.permissions')->getPermissions());
}
To answer the question what is the _permission part of the routing structure. Here is a quote from the drupal docs about what it does.
_permission: A permission string (e.g., _permission: 'access content'). You can specify multiple permissions by separating them with ',' (comma) (e.g., _permission: 'access content,access user profiles') for AND logic or '+' (plus) for OR logic (e.g., _permission: 'access content+access user profiles' means a visitor needs either the access content permission or the access user profiles permission to view the page. Having both is fine, too.). Module-specific permission strings can be defined in my_module_name.permissions.yml. See hook_permission() replaced with permissions defined in a my_module_name.permissions.yml file for details.
source: https://www.drupal.org/docs/drupal-apis/routing-system/structure-of-routes
To put it simply this restricts access to this route by only allowing users with the specified permission(s) to access it. To use it you need to know the system name of the permission(s) you want to use to restrict access. Then you just place then as a string behind this paramerter. Like in the quote above. You can choose to use multiple permissions by separating them with , for AND logic or + for OR logic. Permissions system names are allowed to have spaces in them and frequently do.
I don't think there is any way to directly see it in ui if you are talking about the system names of the permissions. You can ofcource see all permissions on www.site.com/admin/people/permissions. If you are in a hurry and/or looking for a specific permission you can always look through the module.permissions.yml file of the module this permission is defined in.
If you do want to see all permissions you can make your own list of all the system names.
You can use the PermissionHandler service from the core module.
This does the following gets all yaml's and creates a list.
You would call this by calling Drupal::service('user.permissions')->getPermissions() (https://api.drupal.org/api/drupal/core%21modules%21user%21src%21PermissionHandler.php/function/PermissionHandler%3A%3AgetPermissions/8.2.x)
You can use or try to write similar code to the functionality of the user_role_permissions function from the user.module file in drupal core. It looks like this:
function user_role_permissions(array $roles) {
if (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') {
return _user_role_permissions_update($roles);
}
$entities = Role::loadMultiple($roles);
$role_permissions = array();
foreach ($roles as $rid) {
$role_permissions[$rid] = isset($entities[$rid]) ? $entities[$rid]
->getPermissions() : array();
}
return $role_permissions;
}
This code as you can see just loads all the role entities with loadMultiple (although technically you should use the entitytypemanager to load the entities whenever possible like $entities = \Drupal::entityTypeManager()->getStorage($entity_type)->loadMultiple([1, 2, 3]); for more information see the drupal entity api (https://www.drupal.org/docs/drupal-apis/entity-api/working-with-the-entity-api)).
After loading all the roles it makes a list of all permissions.
Source information below. This should stay up to date because drupal keeps their documentation versioned. But because comments suggested it I figured I might as well write it out to save you some clicks.
Original drupal documentation.
https://api.drupal.org/api/drupal/core!modules!user!user.module/function/user_role_permissions/8.2.x
Hope this helps! :)
You can confirm in the page '/admin/people/permissions'.
A quick and dirty way to see them is to create a View with a Page display. Then in the 'Access' section, ensure 'Permission' is selected and open up the options as if you were going to choose a different permission.
You can now inspect the HTML of the <select> element, the Ids of each option is the correct name for each permission:

Drupal: How to restrict apachesolr search results by user/article facets

I have a wiki built with drupal, with a taxonomy category Workgroup, assigned to both the users and the articles. I am using apache solr search module with facet api and my end goal is to set up the search so that by default when users search for the articles, only articles from their workgroup are shown.
That is, when they launch the search from a search box, they should get the same results as for /search/site/hello?f[0]=im_field_kb_workgroups%3A4529 (where 4529 is one workgroup id) instead of just /search/site/hello (current behavior) Users should still be allowed to search in other workgroup facets when they want, by removing the checkbox in the facet block.
I have this working almost by hacking the apachesolr module (not recommended I know but really want this to work). In the function apachesolr_search_custom_page_search_form_submit, I have:
// Get the workgroup id
global $user;
$account = user_load($user->uid);
$user_kb_wg_fieldinfo = field_get_items('user', $account, 'field_kb_workgroups');
$user_kb_wg_tid= '';
if ($user_kb_wg_fieldinfo) {
$user_kb_wg_tid = $user_kb_wg_fieldinfo[0]['tid'];
}
// Add the solr filter for this workgroup facet so that by default, search results are
// fetched only from that workgroup.
if ($user_kb_wg_tid === '4529') {
$get['f[0]'] = 'im_field_kb_workgroups:4529';
}
This does the job but the problem is that this relies on the apachesolr search form. I have users coming to the wiki by searching from sites external to the wiki, where the wiki search form is just a simple POST form pointing to the KB domain and the path /search. So this will work only when people are searching from inside the wiki, where I present them the apachesolr search form.
I have investigated some other options:
In my custom module, I implement this hook (without the user workgroup checks for now, for testing):
function kb_hacks_apachesolr_query_prepare($query) {
$query->addFilter('im_field_kb_workgroups', '4529');
}
This filters the results from searches everywhere, but the filter is applied all the time, and users don't get to deselect this or other filters. (in fact, other filters appear only when passing the filter as a GET param like above with f[0])
I also played with the url_inbound_alter hook, but could not figure out how to pass the solr query param as GET. The following did not work.
function kb_hacks_url_inbound_alter(&$path, $original_path, $path_language) {
if ($path == 'search/site/hello') {
$_GET['f[0]'] = "im_field_kb_workgroups:4529";
//$_GET['f[0]'] = "im_field_kb_workgroups%3A4529";
//$path = 'search/site/hello?f[0]=im_field_kb_workgroups%3A4529;
}
}
Is there a way to set GET params from this hook? But even if this had worked, I would still have to figure out how to do this only by default (when the search form is submitted), and not when the filter itself is deselected. Is there a way to detect checkbox changes in the facet block?
Maybe there's another way to do this? I have been stuck here for the last two days and would really appreciate any help I can get. Thanks!
You can add a relationship to the taxonomy term "Workgroup" and use a contextual filter for the current user. In the contextual filters section, you can change the behavior when the filter is not present.

How do you use a view with arguments as the site front page in Drupal?

I have a Drupal site and I have setup a view to power the front page.
My goal is to be able to pass 0-2 arguments to the home page, that get passed into the view. However, I still need the normal Drupal pages to work. The list of arguments is known.
For example:
mysite.com/berlin/birds would pass in "berlin" as the first argument and "birds" as the second argument to the view that powers the front page.
mysite.com/berlin would just pass in one argument, "berlin"
mysite.com/admin would load the normal admin pages in Drupal
I'm not clear on how to achieve this. Is there a hook I can use? I can't find one or think of one. Is there a way to specify this in the argument for the view itself? Perhaps I can write a hook that interjects when the URL is being loaded, and rewrite in the background?
The solution I currently have is to add these paths (since my arguments are known) to the menu system. This works, except that when I the pages they aren't the front page, so the pages don't use the node themes I want (they use the node details theme).
I don't think you can really do this without custom code. The View needs a path before it starts taking arguments, and your URLs start with the arguments. What you can do is fake it with custom code. I've used something like this:
/**
* Implements hook_init().
*/
function mymodule_custom_init() {
$item = menu_get_item(); // Matching Drupal path
if (!$item) { // There is no matching Drupal path.
$_GET['q'] = 'view_path/' . $_GET['q']; // Fake path path.
} // if
} // mymodule_custom_init
Then you give the view a path of "view_path" and it responds to everything that doesn't match anything else in Drupal's paths.
There is a spot in the views UI for "Argument handling code" that takes a small snippet of php - http://drupal.org/node/70145
You could run some code there that checks to see if you are on the front page (or arguments are not present or whatever)and insert the arguments you want.
Another way is to set arguments via a hook_views_pre_view or hook_views_pre_build. Is better because you are sure you don't break other stuff (like another view block).
function MYMODULE_views_pre_view(&$view){
if ($view->name == 'your_view_name' && drupal_is_front_page()) {
$view->set_arguments(array('you_argument','you_second_argument'));
}
}

How do I list all nodes created by user specified in argument using Views in Drupal?

I have been trying to create a page using views that will list down all the nodes authored by a specific user.
The user name will be specified in the path (like - stuff/[user-name] )
Can someone please tell me how to do this using Views.
I am stuck on a dead end
for the views url path specify: stuff/%
in the arguments section add: user -> user: name
Should do it, but I'm not sure if it isn't buggy (see this issue: http://drupal.org/node/744468)
If you use user:id instead of username, you will be fine.

Drupal - Getting node id from view to customise link in block

How can I build a block in Drupal which is able to show the node ID of the view page the block is currently sitting on?
I'm using views to build a large chunk of my site, but I need to be able to make "intelligent" blocks in PHP mode which will have dynamic content depending on what the view is displaying.
How can I find the $nid which a view is currently displaying?
Here is a more-robust way of getting the node ID:
<?php
// Check that the current URL is for a specific node:
if(arg(0) == 'node' && is_numeric(arg(1))) {
return arg(1); // Return the NID
}
else { // Whatever it is we're looking at, it's not a node
return NULL; // Return an invalid NID
}
?>
This method works even if you have a custom path for your node with the path and/or pathauto modules.
Just for reference, if you don't turn on the path module, the default URLs that Drupal generates are called "system paths" in the documentation. If you do turn on the path module, you are able to set custom paths which are called "aliases" in the documentation.
Since I always have the path module turned on, one thing that confused me at first was whether it was ever possible for the arg function to return part of an alias rather than part of system path.
As it turns out, the arg function will always return a system path because the arg function is based on $_GET['q']... After a bit of research it seems that $_GET['q'] will always return a system path.
If you want to get the path from the actual page request, you need to use $_REQUEST['q']. If the path module is enabled, $_REQUEST['q'] may return either an alias or a system path.
For a solution, especially one that involves a view argument in the midst of a path like department/%/list, see the blog post Node ID as View Argument from SEO-friendly URL Path.
In the end this snippet did the job - it just stripped the clean URL and reported back the very last argument.
<?php
$refer= $_SERVER ['REQUEST_URI'];
$nid = explode("/", $refer);
$nid = $nid[3];
?>
Given the comment reply, the above was probably reduced to this, using the Drupal arg() function to get a part of the request path:
<?php
$nid = arg(3);
?>
You should considder the panels module. It is a very big module and requires some work before you really can tap into it's potential. So take that into considderation.
You can use it to setup a page containing several views/blocks that can be placed in different regions. It uses a concept called context which can be anything related to what you are viewing. You can use that context to determine which node is being viewed and not only change blocks but also layout. It is also a bit more clean since you can move the PHP code away from admin interface.
On a side note, it's also written by the views author.
There are a couple of ways to go about this:
You can make your blocks with Views and pass the nid in through an argument.
You can manually pass in the nid by accessing the $view object using the code below. It's an array at $view->result. Each row in the view is an object in that array, and the nid is in that object for each one. So you could run a foreach on that and get all of the nid of all rows in the view pretty easily.
The first option is a lot easier, so if that suits your needs I would go with that.
New about Drupal 7: The correct way to get the node id is using the function menu_get_object();
Example:
$node = menu_get_object();
$contentType = node_type_get_name($node);
Drupal 8 has another method. Check this out:
arg() is deprecated

Resources