Here is a variant on the node access filter that allows selecting of view, edit, or delete access on the node.
My specific use case is that I am making a view to populate a cck noderef field only for content that is editable by the user. The content in question uses nodeaccess_userreference, so I need to check the access table rather than a permission or author.

I changed the base filter to use the "in operator" filter, but unfortunately this seems to require an operator otherwise no options are displayed. I gave it a default operator as a workaround.

Here is the current filter. For those who want to try it, the node access handler needs to be changed in node.views.inc as well.

Files: 
CommentFileSizeAuthor
#65 views_handler_filter_node_access-620392-64.patch1.9 KBjromine
PASSED: [[SimpleTest]]: [MySQL] 1,627 pass(es).
[ View ]
#51 cap11.jpg341.64 KBbakr
#33 views_handler_filter_node_access.patch3.82 KBsimg
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch views_handler_filter_node_access_1.patch. Unable to apply patch. See the log in the details link for more information.
[ View ]
#30 views_handler_filter_node_access.patch0 bytessimg
PASSED: [[SimpleTest]]: [MySQL] 1,627 pass(es).
[ View ]
#29 views_handler_filter_node_access.inc_.txt2.99 KBsimg
#16 views-node-access-needs-work.patch2.3 KBdagmar
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch views-node-access-needs-work.patch. Unable to apply patch. See the log in the details link for more information.
[ View ]
#8 views_handler_filter_node_access.inc_.txt1.58 KBRoboPhred
#1 views_handler_filter_node_access.inc_.txt1.65 KBRoboPhred
views_handler_filter_node_access.inc_.txt1.42 KBRoboPhred

Comments

RoboPhred’s picture

Status:Needs work» Needs review
StatusFileSize
new1.65 KB

New version, everything seems to be working.

The filter now uses the many-to-one argument and supports "is one of" and "is all of". It could support "is none of" as well, but right now I have that op removed.

The query now works by building the access and grants checks over all the permissions (my last file did not do this properly; it only looked for the view grants).
In order to stop duplicates appearing, I add a GROUP BY clause to the node id. I am not sure if this will break other things, but it seems to run fine with what I have tried. I tested a multi value cck field to make sure intentional 'duplicates' still show up, and it works fine as the field itself was added to the GROUP BY.

The "Reduce duplicates" option is creating impossible joins, and trying to join the node access nid to the filter's operator:
INNER JOIN node_access node_access_value_0 ON node.nid = node_access_value_0.nid AND node_access_value_0.nid = 'update'
I'm not sure if the better solution is to disable the reduce duplicates option, or somehow override its implementation and cause it to add the nid to GROUP BY.

RoboPhred’s picture

The filter is still showing all nodes for me, I think the issue is node access priority...

Working on a solution.

merlinofchaos’s picture

There's already an issue existing with this feature request -- can you find it and mark it duplicate?

RoboPhred’s picture

Turns out it's an odd issue with the domain access module I was using.

#621290: Domain access grants update and delete permissions for all domain_id realms in the node_access table

So this should be working fine as long as modules don't implement the bulk of their access in hook_node_access().

agentrickard’s picture

You should be using hook_node_grants() to do this, not Views. Or, if you use Views, you have to check the database query against the permissions returned by hook_node_grants(). A straight database query is not reliable.

agentrickard’s picture

Status:Needs review» Needs work

This logic is just plain wrong:

<?php
      $grants
= array();
      foreach(
$this->value as $access) {
       
$access = 'view'; // WHY ARE YOU DOING THIS?
       
foreach (node_access_grants($access) as $realm => $gids) {
          foreach (
$gids as $gid) {
           
$grants[] = "($table.gid = $gid AND $table.realm = '$realm')";
          }
        }
      }
?>

You only check the 'view' grants, not the edit or delete. You can't run one query for all three; they are separate interactions. I would also remove the 'administer nodes' bit. The only reasons to have this feature in Views is to build Views of data that _force_ node access rules on administrators.

This has no place in Views, IMO. Let Node Access work as designed.

agentrickard’s picture

For the record -- and then I'll stop -- OG does the exact same thing, storing up to three grants per row in {node_access}.

RoboPhred’s picture

StatusFileSize
new1.58 KB

Bah, I uploaded the wrong file. That file was partially done and just for testing. Attaching the correct file.

The line forcing the access check to view was just for testing. As you see, it was intended to group all relevant access lists into a single array (and does so inefficiently, I still need to check for duplicates), then check for any of the 3 grants on them.
I chose to make a single filter for this. Would it somehow be better to make 3 filters for the 3 grants?

This is necessary for creating views that list content a user is able to moderate, for example. I don't see how this concept is somehow abhorrent to views. After all, I am adding on to a filter that already exists...

RoboPhred’s picture

TravisCarden’s picture

Subscribing. Thanks for the work, RoboPhred.

merlinofchaos’s picture

Status:Needs work» Needs review

Moving back to needs review.

I am very interested in this functionality so reviews from 3rd parties are encouraged.

agentrickard’s picture

Would it somehow be better to make 3 filters for the 3 grants?

Yes. This is how node access grants function and are enforced. See hook_node_grants and $op. You cannot guarantee that a user will have the same permissions for all three ops.

I would still remove the !user_access(administer nodes) check, since the problem with node access is you can't build lists that apply to super admins. You want to use Views to build those lists, so they should apply to all users.

Or, better, make it a filter option: 'Enforce on admin users'. See #615294: Force node access rules on admins, for an example of this type of setting.

bomarmonk’s picture

Testing this functionality. Thank you for the filter!

Cyberwolf’s picture

I am also interested in this functionality. Subscribing.

olemsa’s picture

I am also interested in this functionality. Subscribing.

dagmar’s picture

Version:6.x-2.x-dev» 6.x-3.x-dev
Status:Needs review» Needs work
StatusFileSize
new2.3 KB
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch views-node-access-needs-work.patch. Unable to apply patch. See the log in the details link for more information.
[ View ]

I reviewed #8 and think that it not working. So I have rerolled this patch against views 3 version with some changes but this patch doesn't work either.

I certainly am not going to touch this patch anymore, so if anybody can take care about this you are Welcome!

RoboPhred’s picture

Version:6.x-2.x-dev» 6.x-3.x-dev

Unfortunately with my eternal time crunch I had to drop this to work on other things. That file isn't all of it, the node access handler needs to be updated in node.views.inc as well.

In node.views.inc node_views_handlers() Change the parent of views_handler_filter_node_access from 'views_handler_filter' to 'views_handler_filter_node_access'.

xjm’s picture

Tracking; I definitely could use this feature.

dobe’s picture

Version:6.x-3.x-dev» 6.x-2.x-dev

Subscribe!

I would also like to have this functionality. However I tried to use the patch on #8 and I was able to set everything up in views: node-access->edit->is_all_of however. Setting it does not provide any results. The user can view all nodes of the content types I filter. Which is not what I want. I only want the nodes that can be edited by the user to be viewed. Any help on fixing this would be much appreciated. Also I don't want the user to have 'administer nodes' permission as this renders this idea kinda mute... Thanks

RoboPhred’s picture

Version:6.x-3.x-dev» 6.x-2.x-dev

It looks like I had a typo in comment 17, I had the wrong handler listed (The handler should be 'views_handler_filter_node_access', not 'views_handler_filter_many_to_one'. I fixed the typo, so go ahead and re-read it and make sure thats what you did.

shushu’s picture

Subscribe...
Needs this feature, can't find time to work on it myself for now.

m4olivei’s picture

subscribe

avner’s picture

subscribe

screenage’s picture

There is a module for this now that adds this filter: Editor Views
http://drupal.org/project/editor_views

screenage’s picture

unfortunately, if your node access setup is enhanced by modules like Tac Lite, this is no option either

bomarmonk’s picture

So the editor_views module will not work with taxonomy permissions? I just wanted to be clear on what you are saying, screenage. At any rate, thanks for the link to the new module.

agentrickard’s picture

I looked, Editor Views is not responsive to the Node Access system. It will only work with core permissions, which is not what this issue is asking for.

The great irony, of course, is that node access rules are applied to all users except user 1 and those with 'administer nodes', so I'm not sure what this filter tries to accomplish.

You'd have to do what I suggest in #12, which is survey the node_grants for the user and then apply them to the view query.

jhedstrom’s picture

I just added a patch for #862072: allow node_access operation to be changed from 'view' to 'edit' or 'delete' for nid arguments, which is related to this, but works at the argument level rather than the filter level.

simg’s picture

StatusFileSize
new2.99 KB

I've done some work on this based on RoboPhreds (and others) excellent work.

It's early days, it's needs testing and it's only on Drupal 7 at the moment.

But it works ;)

The code should handle the node_access table and core permissions correctly (maybe someone could check this for me).

The attached is a replacement for the original "views_handler_filter_node_access" so needs to be copied to modules/views/modules/node/views_handler_filter_node_access.inc

Disclaimers:
1. There appears to be a bug which involves a null AND condition appearing in the query when you add this filter. I haven't been able to work out why this is happening, so I've hacked a solution by clearing the query->where array in my handler. This means this filter has to be the first in the filters list or else it removes the other filters. Maybe someone has some ideas about why this is happening, however for now it isn't a show stopper.
2. I think to get a 100% "drupal compliant" list of "my content" a query would have to call "node_access()" on every node in the database. I think this would *kill* any kind of scalability with even moderate numbers of nodes, so care should be taken to understand the implications of having modules which override the node_access table. (If that makes sense?)

Anyway, I'd be grateful for any testing / feedback anyone would like to contribute.

simg’s picture

StatusFileSize
new0 bytes
PASSED: [[SimpleTest]]: [MySQL] 1,627 pass(es).
[ View ]

Apologies for the delay in getting back to this post.

I've now created a patch for views_handler_filter_node_access to allow edit and delete access checking in a filter.

Issues still apply as in my previous post, but other than that it works nicely.

Patch based on Views 7.x-3.x-dev

agentrickard’s picture

Patch file is empty.

I created something similar here:

http://drupalcode.org/project/workbench_access.git/blob/HEAD:/includes/w...

My approach adds node_load() overhead (which is likely unavoidable) but is much simpler.

[Edit]: Sorry, I don't provide a filter, just a field.

agentrickard’s picture

That said, given how hook_node_access() works in Drupal 7, it is simply not possible to use a single database query to return a list of editable objects.

That's because any module, for any reason, can return FALSE on an access check and deny the request.

Best to have fields in Views that display edit/delete, and let access control modules let people build their own filters.

simg’s picture

StatusFileSize
new3.82 KB
FAILED: [[SimpleTest]]: [MySQL] Unable to apply patch views_handler_filter_node_access_1.patch. Unable to apply patch. See the log in the details link for more information.
[ View ]

ah, thanks agentrickard, for pointing out my "deliberate" error with empty patch. non-empty one attached :)

you make a good point about letting access control modules create their own filters, so I'm going to leave this patch here and the Views maintainers can do whatever they like with it. I'll probably turn into a module for now - what I probably should have done in the first place.

one thing is though, as I suspect you're aware, your node_load approach will absolutely kill any kind of scalability in terms of the number of nodes that could be stored in a Drupal instance. Imagine (say) a thousand calls to node_load followed by another 1000 to node_access (ie 1 per stored node), each of which generating at least 1 database access. I suspect latency issues would start to be come noticeable at even a hundred or so nodes?

dawehner’s picture

Just in general could you please try to use drupal codestyle?
This would help to get this feature in, thanks!

simg’s picture

I thought I did use drupal codestyle ?

agentrickard’s picture

Yes, but you have no other option than to use node_load(). Otherwise you will never get an accurate result unless you control every aspect of the installed modules on a user's site (and therefore know which queries and hooks are being used).

This is because any module can break your query like so:

<?php
function custom_node_access($node, $op, $account) {
  return
NODE_ACCESS_DENY;
}
?>

In that case, your query will return false positives, which is a security issue.

simg’s picture

Agreed, but that seems to me to be an architectural "gotcha" with Drupal? The node_access hook is there, but you'd have to be *very* careful how you use it. Better not use it at all? If do use it, you almost certainly can't build any useful permissions model whilst also being able to list all "permissible" nodes in a way that is even remotely scalable.

I'm fairly new to Drupal (but not web development or content management) - so I could be missing something ?

dawehner’s picture

The filter could use the pre_render method and throw everything out which is not allowed, but sure this would for example lead to not correct working pager queries.

agentrickard’s picture

hook_node_access() is fine if only used on Create, Edit and Delete (which are single node operations) or for providing "preview" functionality to individual nodes. Listing queries should be handled by the Node Access API so that View operations perform consistently for lists of node.

The Node Access API should, IMO, no longer be used for Edit and Delete. See http://groups.drupal.org/node/137939

The patch here tries to use the Node Access API to determine edit/delete on node lists. Which may or may not return accurate results.

simg’s picture

agentrickard: I agree with your comments BUT the ability to list all the content that user has permission to edit (or in fact any permission) seems to me to be basic content management functionality?

If the above is accepted to be true, then the permissions *must* be stored in the database (ie via node access api?) to allow for queries to efficiently get lists of "permissible nodes". If it ever became necessary to make an api call for each node as per #31, I would have serious problems using Drupal for many projects.

If you were to argue that my patch should be "rejected", I wouldn't disagree and would happily just release it as a module whilst making clear it's limitations.

agentrickard’s picture

I don't disagree.

bakr’s picture

I agree with #32

That said, given how hook_node_access() works in Drupal 7, it is simply not possible to use a single database query to return a list of editable objects.

Best to have fields in Views that display edit/delete, and let access control modules let people build their own filters.

But the shortcoming of that approach is the lack of filtering capability in the views module against the (say: "Edit Link") column of the node.

This could prove to be a shortcut for all the issue.

agentrickard’s picture

@bakr

That's the problem in a nutshell. You cannot accurately filter edit/delete queries. And it's not Views' fault. The data simply isn't always stored in the database.

bakr’s picture

THIS COMMENT HAS BEEN RERWITTEN FOR CLARITY

How about benefiting from the Module Grants Monitor Queries to dump the output into a custom table as follows

==============================
uid  | nid | create   | view   | update  | delete
------------------------------------------------------
int  | int | boolean | boolean | boolean | boolean
==============================

Then above table can be exposed to views modules, and to be updated dynamically somehow.

This way we can relate this missing table and properly relate with in the sql query for better filtering handling

Modue Grants Monitor Module ( http://drupal.org/project/module_grants ) Already having such a thing, it comes with a report showing:

-List of Modules I can view
-List of Modules I can Update
-List of Module I can Delete

Maybe some code can be adabted with helper funtions provided therein.

bakr’s picture

Youreka,

I guess by now that Computed fields could be the soltution (http://drupal.org/project/computed_field)

You can also choose whether to store your computed field values in the database with other content fields,
[x] Store using the database settings below (required for Views use)

If we pass the node_access() forumla (http://api.drupal.org/api/drupal/modules--node--node.module/function/nod...) and one extra if-statement to handle output back to field with proper value presentation...

And Last but not least, this solution does not affect performance at all regardless of site scale.

VIOLA!

agentrickard’s picture

Something like that would seem to be the only proper solution. I just wonder about whether that data can go stale.

I suppose as long as that table is rebuilt on the following conditions, it should work:

-- New module installs (that affect node access).
-- Permission changes (that affect node access).
-- User role changes.
-- Content updates.
-- Module removal.

Rebuilding that table could be quite a task, however, even for the BatchAPI. And for sites with > 100 users, it could get very large very quickly.

bakr’s picture

Recall that 'content updates' leads to computed fields being recomputed at node save time :)

and this pulls back all the dependencies that you have mentioned as being subcontracted in the node_access() formula.

This scenario serves the purpose of custom workflows as well, where we generate a view telling users these are the current worklist for approvals at your side... now this view is possible finally. (in theory)

agentrickard’s picture

Content updates are insufficient triggers. If I grant the 'editor' role the permission to 'edit all page nodes', then the entire table has to be updated for all page nodes and all editors.

bakr’s picture

How about this Computed field code, I tested and is working :))

global $user;
$op = "update";
node_access($op, $node);
$node_field[0]['value'] = $user->uid."_editable";

Like you mentioned the issue of trigger point still exists for your scenario.

Here is a diversion point, that is, from here onwards some room for further configuration/customization has to be tailored for each use case.

agentrickard’s picture

No. That won't give you what you want. That will only save a record for the active user.

You need to iterate over all user accounts and pass $account to node_access().

And as soon as you do this on a site with > 1000 users, the server may melt. At the least, the operation will likely time out.

bakr’s picture

StatusFileSize
new341.64 KB

I have developed an external middle-ware page using lasso (lassosoft.com) that brings a new GUI to manage field-level access grants for nodes as they travel through different workflow states (see attachment snap view)

This Ajax enabled GUI is an overlay to workflow-access helpder module.

I have different user roles, clearly, whenever each one logs in, I would show him a list of nodes pending approval among other things.

For this I have created several views and arranged them through panels view panes.
The views-or module helped me tweak some of these views, and occasionally i came across the drupal limitation of not allowing me to ..(subject matter)..

So, I am really still interested into getting a better solution.
Unfortunately, I do not program php :(

bakr’s picture

In reply to #50 and referring back to #44:

And Away back from the \limited\ computed-field solution..

The concept of Iterating the $account on node_access can be done in queued batches @ cron level,
[ the same way search index is being rebuilt]

Add to this the idea of new table saving results and serving views module sql joins purpose.

How about this..? a custom module can be built for this purpose

It is interesting that drupal did not pay attention to this earlier

agentrickard’s picture

Well, the {node_access} table _should_ provide this behavior in Drupal 6 and lower -- you can query against {node_access}.grant_update to get a list of nodes to edit and {node_access}.grant_delete for delete.

The problem is really in Drupal 7 and higher, where modules can affect access control more loosely, and without registering in the database. And in Drupal 6, there are ways around that, too, plus the {node_access} table does nothing for the 'edit all page nodes' permission.

Don't think that Drupal hasn't addressed this issue, it's just a trade off that lists of editable content is not as high a priority as making access controls easy to use. In general, Views allows for enough filtering that users can find their editable content easily enough.

bakr’s picture

Then the following module would help surfacing the node access to views
http://drupal.org/project/tw

hmmm, I shall give it a try.

Maybe to your interest, I can provide you with the full source code for the workflow access matrix along with intructions to setup the middleware.

Thanks Rick.

agentrickard’s picture

You don't need table wizard. Node Access is _already_ surfaced to Views (and to all queries), via db_rewrite_sql() (Drupal 6) or hook_query_alter() (Drupal7).

You should start at the API level. For example, http://api.drupal.org/api/drupal/modules--node--node.module/function/nod...

The problem isn't that {node_access} isn't available to Views, it's that items *outside of {node_access}* can affect access control rules.

simg’s picture

unless I've missed something node_access isn't *fully* surfaced to Views, the "view" permission is, but edit and delete are not.

however, I agree that the items *outside of {node_access}* (ie calls to hook_node_access) are a problem. If you've made use of hook_node_access in your site, it's hard to imagine how you would get a list of accessible nodes with any kind of reasonable performance for more than a few 10's of nodes.

personally, I think it would be a fair compromise to say the default Views node_access filter simply does not take into account the node_access hook?

bakr’s picture

It is possible to implement some caching mechanism? or may make things worse, due to further gap between cached snapshot and new recent changes on actual grounds due to other factors like you mentioned.

agentrickard’s picture

I do wonder if we could structure a filter in D6 that changes the node_access query operation from 'view' to 'edit' or 'delete'.

That would get you there for D6.

agentrickard’s picture

Actually, it won't, because of the 'edit all X' permission, which is not stored in {node_access}.

bakr’s picture

REWRITTEN FOR BETTER CLARITY

Maybe we can decouple from the "edit All X" permission.. and follow the foot steps of compromise and get some mostly good usable results from {node_access}

Optionally,

Then create another complementary function to cover up for the skipped permission(edit all X) rather virtually than physically from the nodes_access table

This can be achieved by creating an alternative query that supersedes the node_access query and fetches back every thing as far as "edit all X" is enabled


The end user would seamlessly see a rendered result.

bkosborne’s picture

Subscribe... I don't (yet) know enough about node access tables and handling to contribute at the moment, but having three sep. filters for "view", "edit", and "delete" would be great.

aaron.r.carlton’s picture

subscribe

xjm’s picture

#62: You don't need to comment any more to follow an issue. Instead, click the "Follow" button at the top right of a page. :)

giorgio79’s picture

Version:6.x-2.x-dev» 7.x-3.x-dev

I guess this wont happen for Views 6, perhaps 7? I would love to be able to filter for content that the user can edit.

jromine’s picture

Status:Needs work» Needs review
StatusFileSize
new1.9 KB
PASSED: [[SimpleTest]]: [MySQL] 1,627 pass(es).
[ View ]

Here's an updated, simplified version of this for views-7.x-3.x. It does what is purports to do: allows an option for checking for node grant access for Edit or Delete (instead of View). Note that this is not necessarily the same as whether the user has permission to edit or delete the node for the reasons described in comment 53 (and others).

I'm using this patch on a site with http://drupal.org/project/taxonomy_access and it does what I need it to do and it might be useful to others as-is.

alisonjo2786’s picture

@jromine Thank you for posting your patch. It did what I was hoping it would do!
EDIT: My bad, it actually isn't working for me :( I thought it was, but turns out I just did a poor job testing. My first guess is that this is because of the organic groups stuff I have on my site. (The rest of my comment re: help text stands, though, I suppose.)

You should probably also edit the help text for this filter (line 618 of node.views.inc):
'help' => t('Filter for content by view access. <strong>Not necessary if you are using node as your base table.</strong>'),

Maybe...
Filter for content by access [or, "by view, edit, or delete access"]. Filtering by view access is not necessary if you are using node as your base table.

...or remove the bolded sentence altogether, and add a second "Note" to your $form['caution'] in views_handler_filter_node_access.inc, like...
Note: Filtering by View access is not necessary if you are using node as your base table.
Note: For Edit and Delete access, only node access grants are checked. Modules can override node access grants to allow or deny actions, so this check does not necessarily reflect whether the user can actually perform the Edit or Delete action.

(or something)

nicholas.alipaz’s picture

Issue summary:View changes

I have taken the patch in #65 and packaged as a separate module for those whom might need a solution now without patching views or waiting for the patch to be RTBTC and added to views.

https://drupal.org/sandbox/nicholasalipaz/2285469
UPDATE: have changed this to a full project: https://www.drupal.org/project/views_node_access_level

It is lightly tested so please let me know if there are issues.