[drupal-devel] Working around node_access in node/add
Hello drupal-devel, Lately, I've been working on the Node Relativity module, and I've come up against some issues that I'm having trouble overcoming. The main thing this module does is allow parent/child relationships to exist between nodes. One of the features of this module is the ability to require that a given type of node not exist unless it is a child of an appropriate parent node. This works all well and good from within the module (except for the occasional bug), but when a user goes to the "create content" page (node/add), they see listed before them every type of node that they have permission to create. I want to limit this view and the menu associated with it. This brings me to my question: How do I override what is displayed on the node/add page or override the node_access permissions in general for node types not defined by my module? I know that node.module checks node_list() and calls node_access('create',$node) on each of the node types to see if the current user has rights to create it. I suspect that there's some way that I haven't seen yet that the node is mapped back to the module that defines it. I would like to restrict this view even further such that users can create these nodes, but only under the appropriate circumstances. Any ideas would be greatly appreciated. Thanks, Mark Howell (javanaut)
Mark wrote:
Hello drupal-devel,
Lately, I've been working on the Node Relativity module, and I've come up against some issues that I'm having trouble overcoming.
This module sounds real interesting. I hope to check it out soon. In short, there is no way today limit node creation permission as you wish. The node_access API was designed to limit/grant permission on existing nodes, not on unborn nodes. I think your only hope is to hack the user's permissions from within hook_init() or something like that. you would want to strip the 'create x' permission unless the user is creating from within your module. You should be sure that noone has called user_access() before you do in hook_init() because otherwise $perm is cached there and you can't affect that. -moshe
Mark, two small things: Did you look at my clipper.module. It does node relations already. It is a pity you did not post anything about node relations earlier, for i am in need of extending or even rewriting clipper. module, to have more advanced relations. But it might not be too late yet. :) Bèr Op vrijdag 11 februari 2005 03:10, schreef Mark:
Hello drupal-devel,
Lately, I've been working on the Node Relativity module, and I've come up against some issues that I'm having trouble overcoming. The main thing this module does is allow parent/child relationships to exist between nodes. One of the features of this module is the ability to require that a given type of node not exist unless it is a child of an appropriate parent node. This works all well and good from within the module (except for the occasional bug), but when a user goes to the "create content" page (node/add), they see listed before them every type of node that they have permission to create. I want to limit this view and the menu associated with it.
This brings me to my question: How do I override what is displayed on the node/add page or override the node_access permissions in general for node types not defined by my module? I know that node.module checks node_list() and calls node_access('create',$node) on each of the node types to see if the current user has rights to create it. I suspect that there's some way that I haven't seen yet that the node is mapped back to the module that defines it. I would like to restrict this view even further such that users can create these nodes, but only under the appropriate circumstances.
Any ideas would be greatly appreciated.
Thanks, Mark Howell (javanaut) Bèr -- | Bèr Kessels | webschuur.com | website development | | Turnhoutsebaan 34/3 | 2140 Antwerpen | België | | IM: ber@jabber.org.uk | MSN: berkessels@gmx.net | | pers: bler.webschuur.com | prof: www.webschuur.com |
Hello Bèr, I did respond to your clipper.module suggestion (http://drupal.org/node/16207#comment-27372). It appeared to me that you were attaching nodes to taxonomy terms automatically. Now that I'm looking at the code in more detail, it doesn't appear to be doing what it's supposed to. When it creates new terms, it's not setting the parent correctly for some reason. I'll submit an issue with more details. Fundamentally, however, it works differently from the module that I've written. Clipper attaches nodes to taxonomy terms, whereas Node Relativity attaches nodes to nodes. The level of flexibility and configuration that I needed for my project goes beyond what the taxonomy system currently allows. I needed a way to restrict parenting/childing based on node types and parental ordinality. Putting this into taxonomy would be very difficult for me, and I'm not sure it would end up serving the purpose that I want (or that anybody else would want this in the taxonomy module). I think that adapting clipper to my needs would mean abandoning it's use of taxonomy for storing the relations, which appears to be a fundamental feature of it. It is a very useful module, but not one that fits my current needs. Thanks, Mark Bèr Kessels wrote:
Mark,
two small things: Did you look at my clipper.module. It does node relations already. It is a pity you did not post anything about node relations earlier, for i am in need of extending or even rewriting clipper. module, to have more advanced relations. But it might not be too late yet. :)
Bèr
Op vrijdag 11 februari 2005 03:10, schreef Mark:
Hello drupal-devel,
Lately, I've been working on the Node Relativity module, and I've come up against some issues that I'm having trouble overcoming. The main thing this module does is allow parent/child relationships to exist between nodes. One of the features of this module is the ability to require that a given type of node not exist unless it is a child of an appropriate parent node. This works all well and good from within the module (except for the occasional bug), but when a user goes to the "create content" page (node/add), they see listed before them every type of node that they have permission to create. I want to limit this view and the menu associated with it.
This brings me to my question: How do I override what is displayed on the node/add page or override the node_access permissions in general for node types not defined by my module? I know that node.module checks node_list() and calls node_access('create',$node) on each of the node types to see if the current user has rights to create it. I suspect that there's some way that I haven't seen yet that the node is mapped back to the module that defines it. I would like to restrict this view even further such that users can create these nodes, but only under the appropriate circumstances.
Any ideas would be greatly appreciated.
Thanks, Mark Howell (javanaut)
Bèr
Mark, this may seem like a very silly question, but what will your module do that book.module doesn't do - or what doesn't book.module do that you need? andre
The underlying table structure of the book module is similar to this one's. Admittedly, I've never used the book module on a live site, but I read over the code and played with its functionality. The main thing that the book module didn't offer that I need is a way of restricting what types of nodes can be related to each other as well as the ordinality of the relationships. I would need book chapters with pages that go around in circles, for instance. I also need a way of traversing the graph and searching for indexed content while traversing. It didn't seem like any of this was the goal of the book module, or any other module that I had seen at the time I started working on this (about 2 weeks ago). I figured the module would be quite simple, but this turned out to be a bit more of a challenge than I was expecting. Thanks, Mark Andre Molnar wrote:
Mark, this may seem like a very silly question, but what will your module do that book.module doesn't do - or what doesn't book.module do that you need?
andre
I think the goal is to have views that are composed of more than one node. This is something Drupal doesn't support in any way, really, at this point. The best you can do is either use a filter to spit some output into the body of a node, in which case both nodes are unaware of the association, or attach a node to another which ususally takes the form of lumping their combined output onto one page. As I understand it, Mark is writing a module where you can make complex n level relations between nodes. This will help us move away from Drupal's almost exclusive web-publishing content-oriented features (blogs, books, pages, stories, articles) and approach the needs of the web-application developer who models data and relationships, collects that data, and presents it in different views. I'll take an example from Gavin King's Hibernate book. There he models Cats. Cats can have relationships to other Cats. In fact, they can have three types of relationship; parent-child, rival, mate. When objects (nodes) are aware of their relationships you can do queries. You can then say, "give me all Cats who are rivals of this Cat", or "give me all Cats who are mates of this Cat's rivals", or "give me all Cats who have no mate". You can also have complex views. When showing a Cat, you not only show it's information (name, age, color), but also what it's relationships are. In the best case you can theme these as you wish. Perhaps you want hyperlinks to their pages, or perhaps you just want to display thier name and color. In any case, from the context of Cat X, you can access the information of Cat Z just because the two of them are joined by a relationship. Not that Mark's module is going to be able to do all this right off, but I think this is the type of functionality he is dreaming of. -Robert Andre Molnar wrote:
Mark, this may seem like a very silly question, but what will your module do that book.module doesn't do - or what doesn't book.module do that you need?
andre
Gotcha, I suppose taxonomy does this to an extent - and Bèr project seems to be building on that. I was just curious about the desired relationship. Clearly its more than just parent child. I'll be taking a look at this when its done. andre Robert Douglass wrote:
I think the goal is to have views that are composed of more than one node. This is something Drupal doesn't support in any way, really, at this point. The best you can do is either use a filter to spit some output into the body of a node, in which case both nodes are unaware of the association, or attach a node to another which ususally takes the form of lumping their combined output onto one page.
As I understand it, Mark is writing a module where you can make complex n level relations between nodes. This will help us move away from Drupal's almost exclusive web-publishing content-oriented features (blogs, books, pages, stories, articles) and approach the needs of the web-application developer who models data and relationships, collects that data, and presents it in different views.
I'll take an example from Gavin King's Hibernate book. There he models Cats. Cats can have relationships to other Cats. In fact, they can have three types of relationship; parent-child, rival, mate. When objects (nodes) are aware of their relationships you can do queries. You can then say, "give me all Cats who are rivals of this Cat", or "give me all Cats who are mates of this Cat's rivals", or "give me all Cats who have no mate".
You can also have complex views. When showing a Cat, you not only show it's information (name, age, color), but also what it's relationships are. In the best case you can theme these as you wish. Perhaps you want hyperlinks to their pages, or perhaps you just want to display thier name and color. In any case, from the context of Cat X, you can access the information of Cat Z just because the two of them are joined by a relationship.
Not that Mark's module is going to be able to do all this right off, but I think this is the type of functionality he is dreaming of.
-Robert
Andre Molnar wrote:
Mark, this may seem like a very silly question, but what will your module do that book.module doesn't do - or what doesn't book.module do that you need?
andre
Robert, You are correct that my goal is to use this and other existing drupal modules to make complex models. The possible types of relationships are between parent and child of each combination of node type with the ordinality of each relationship specified (in both directions) as well. Visually representing the connected nodes hasn't been addressed very much yet (currently just linked node titles) and thoughts on the subject are appreciated. I'm using this to glue a bunch of mostly flexinode nodes together as metadata to identify event logs of another application. The one non-flexinode node essentially glues all of the other pieces together, and it's nid gets propagated into another system. I use a connected node query (several, actually) to find all nodes related to this one and populate a metadata reporting table from that. This table will have a column for each node type in the system as well as a unique identifier for each specific event type, a timestamp and several "roll-up" columns of the previous period's data. There will be a reporting interface on top of this table that will let me navigate the report in a hierarchical way. I'm going to use the structure of the connected nodes to direct the reporting "data cube" view. I couldn't really see how to do that with the existing set of drupal features at the time. Also, my set of metadata types (now up to 19 node types) seems to change everytime a client gets a new idea or some nifty whatnot comes out that needs to be tracked and reported on. I just add another flexinode to the system somewhere, another table column, and it shows up on the reports. That's the plan, anyways, I'm still working on it :) Andre, I have all of the basic functionality implemented in the CVS HEAD version as of this afternoon (gmt-6). Please give it a run. I'm particularly happy with how the query tool is coming along. -Mark Robert Douglass wrote:
I think the goal is to have views that are composed of more than one node. This is something Drupal doesn't support in any way, really, at this point. The best you can do is either use a filter to spit some output into the body of a node, in which case both nodes are unaware of the association, or attach a node to another which ususally takes the form of lumping their combined output onto one page.
As I understand it, Mark is writing a module where you can make complex n level relations between nodes. This will help us move away from Drupal's almost exclusive web-publishing content-oriented features (blogs, books, pages, stories, articles) and approach the needs of the web-application developer who models data and relationships, collects that data, and presents it in different views.
I'll take an example from Gavin King's Hibernate book. There he models Cats. Cats can have relationships to other Cats. In fact, they can have three types of relationship; parent-child, rival, mate. When objects (nodes) are aware of their relationships you can do queries. You can then say, "give me all Cats who are rivals of this Cat", or "give me all Cats who are mates of this Cat's rivals", or "give me all Cats who have no mate".
You can also have complex views. When showing a Cat, you not only show it's information (name, age, color), but also what it's relationships are. In the best case you can theme these as you wish. Perhaps you want hyperlinks to their pages, or perhaps you just want to display thier name and color. In any case, from the context of Cat X, you can access the information of Cat Z just because the two of them are joined by a relationship.
Not that Mark's module is going to be able to do all this right off, but I think this is the type of functionality he is dreaming of.
-Robert
Andre Molnar wrote:
Mark, this may seem like a very silly question, but what will your module do that book.module doesn't do - or what doesn't book.module do that you need?
andre
Ok, so redirecting back to my original issue, I'm considering 2 solutions: 1. From my hook_menu(), iterate over all existing node/add/$type paths and replace the access parameter with one of my module's choosing. The global $_menu variable doesn't appear to be populated yet at the time hook_menu is called. It sets its menu items after the module_invoke_all('menu',TRUE) gets executed. This, therefore, will not work :( 2. Add another pass to the nodeapi hook for "access" that lets modules restrict access to specific nodes on a situational basis. This could be called from node_access(). I think this would address my needs. Thoughts on another nodeapi operation? -Mark Mark wrote:
Hello drupal-devel,
Lately, I've been working on the Node Relativity module, and I've come up against some issues that I'm having trouble overcoming. The main thing this module does is allow parent/child relationships to exist between nodes. One of the features of this module is the ability to require that a given type of node not exist unless it is a child of an appropriate parent node. This works all well and good from within the module (except for the occasional bug), but when a user goes to the "create content" page (node/add), they see listed before them every type of node that they have permission to create. I want to limit this view and the menu associated with it. This brings me to my question: How do I override what is displayed on the node/add page or override the node_access permissions in general for node types not defined by my module? I know that node.module checks node_list() and calls node_access('create',$node) on each of the node types to see if the current user has rights to create it. I suspect that there's some way that I haven't seen yet that the node is mapped back to the module that defines it. I would like to restrict this view even further such that users can create these nodes, but only under the appropriate circumstances.
Any ideas would be greatly appreciated.
Thanks, Mark Howell (javanaut)
2. Add another pass to the nodeapi hook for "access" that lets modules restrict access to specific nodes on a situational basis. This could be called from node_access(). I think this would address my needs.
-1. Consider the case when we are retrieving a list of nodes. We don't want to call a hook against every single node we've retrieved. We want to retrieve only the right nodes in SQL. That is the whole point of the node_access table.
Moshe Weitzman wrote:
2. Add another pass to the nodeapi hook for "access" that lets modules restrict access to specific nodes on a situational basis. This could be called from node_access(). I think this would address my needs.
-1. Consider the case when we are retrieving a list of nodes. We don't want to call a hook against every single node we've retrieved. We want to retrieve only the right nodes in SQL. That is the whole point of the node_access table.
I'm looking to further restrict access using the node_access table as well. I only want to allow the creation of certain node types if 1) they don't require a parent to exist or 2) I can tell from the query params/environment/etc which node is the parent. Failing both of these, I don't want them to appear on the "create content" list. Can you think oa another way to do this? Thanks, -Mark
On Sat, 12 Feb 2005, Mark wrote:
Moshe Weitzman wrote:
-1. Consider the case when we are retrieving a list of nodes. We don't want to call a hook against every single node we've retrieved. We want to retrieve only the right nodes in SQL. That is the whole point of the node_access table.
I'm looking to further restrict access using the node_access table as well. I only want to allow the creation of certain node types if 1) they don't require a parent to exist or 2) I can tell from the query params/environment/etc which node is the parent. Failing both of these, I don't want them to appear on the "create content" list.
Can you think oa another way to do this?
Can't you just hide or disable the /node url and add a node creation interface for yourself? Cheers, Gerhard
Gerhard Killesreiter wrote:
On Sat, 12 Feb 2005, Mark wrote:
Moshe Weitzman wrote:
-1. Consider the case when we are retrieving a list of nodes. We don't want to call a hook against every single node we've retrieved. We want to retrieve only the right nodes in SQL. That is the whole point of the node_access table.
I'm looking to further restrict access using the node_access table as well. I only want to allow the creation of certain node types if 1) they don't require a parent to exist or 2) I can tell from the query params/environment/etc which node is the parent. Failing both of these, I don't want them to appear on the "create content" list.
Can you think oa another way to do this?
Can't you just hide or disable the /node url and add a node creation interface for yourself?
Cheers, Gerhard
Thats's basically what I'm trying to do. I use a path of node/add/$type/parent/$parent_nid, and only want to require certain types to be created this way. Other nodes should be created using the normal node/add/$type url. For the types that require a parent, I've tried overriding the menu path, but that doesn't seem to work. Here's a snippet from my hook_menu: function relativity_menu($may_cache) { global $_menu; $items = array(); // * not working how I wanted it to // iterate through all node types and take over their node/add handlers foreach(node_list() as $type){ if(relativity_requires_parent($type)) { drupal_set_message("<pre>$type: ".print_r($_menu['path index']['node/add/'.$type],1)."</pre>\n"); if($_menu['path index']['node/add/'.$type]) { drupal_set_message("altering access for type $type"); $_menu['items'][$_menu['path index']['node/add/'.$type]]['access'] = user_access('administer content'); $_menu['items'][$_menu['path index']['node/add/'.$type]]['title'] .= t(' requires parent'); } else { drupal_set_message("setting access for type $type"); $items[] = array('path' => 'node/add/'. $type, 'title' => t('content type requires parent'), 'callback' => 'node_page', 'access' => user_access('administer content'), 'type' => MENU_CALLBACK, 'weight' => 1 ); } } } ..... } At best, however, this only deals with the menu. When node_add lists out possible node types to create, it calls upon node_access('create', $type) to determine whether to display the link or not. I see node_access('create', $type) as being somewhat different from the other node_access operations. It makes logical sense that the 'create' operation be part of this, but I don't think that the same restrictions that the other operations have comes into play. There's generally no interaction with the node_access table when the 'create' operation is performed, since no specific node is named when the function is called. I think even a hook_nodeapi($type, 'create') that only gets invoked for the 'create' operation might work. Anything that lets me override what node_access('create', $type) returns will suffice for my purposes, I think. If you can think of non-core changes that would help me out here, I welcome your thoughts. Thanks again, -Mark
On Sun, 13 Feb 2005, Mark wrote:
Gerhard Killesreiter wrote:
Can't you just hide or disable the /node url and add a node creation interface for yourself?
Thats's basically what I'm trying to do. I use a path of node/add/$type/parent/$parent_nid, and only want to require certain
Can't you use an entirely new path? create/$type/$parent for example. Then disable or hide node/add through menu.module. I agree that it is hackish but less hackish than what you proposed. Cheers, Gerhard
Gerhard Killesreiter wrote:
Thats's basically what I'm trying to do. I use a path of node/add/$type/parent/$parent_nid, and only want to require certain
Can't you use an entirely new path?
create/$type/$parent for example.
Then disable or hide node/add through menu.module. I agree that it is hackish but less hackish than what you proposed.
My main goal is to keep the nodes from showing up in the node/add list and from being created . To additionally keep them out of the menu would just be a bonus for me. I could just put in the README.txt for my module that admins should remove these node types from the menu, but it still wouldn't keep clever folks from hand-entering an inappropriate node type and creating inconsistent node structures. I was attempting to override the various node/add/$type paths to set the security on them explicitly. This is not working, however. I wish there were a way around this other than patching core modules, but I have yet to see a way around it other than modifying node_access('create',$type) to look elsewhere before invoking hook_access('create',$type). -Mark
On Sun, 13 Feb 2005, Mark wrote:
Gerhard Killesreiter wrote:
Thats's basically what I'm trying to do. I use a path of node/add/$type/parent/$parent_nid, and only want to require certain
Can't you use an entirely new path?
create/$type/$parent for example.
Then disable or hide node/add through menu.module. I agree that it is hackish but less hackish than what you proposed.
My main goal is to keep the nodes from showing up in the node/add list and from being created .
node/add will be unavailable if you disable that menu entry.
To additionally keep them out of the menu would just be a bonus for me. I could just put in the README.txt for my module that admins should remove these node types from the menu, but it still wouldn't keep clever folks from hand-entering an inappropriate node type and creating inconsistent node structures.
Nope. The menu controls what urls work. Cheers, Gerhard
Bèr Kessels wrote:
Op maandag 14 februari 2005 07:58, schreef Gerhard Killesreiter:
node/add will be unavailable if you disable that menu entry.
Make sure you place it outside the if ($maycache) clause.
Regards, Bèr
This successfully removes it from the menu and appears to deny access as appropriate, but node_add doesn't seem to refer to menu settings when displaying links to the various node/add/$type pages. Therefore, whatever settings I change in the menu have no bearing on what shows up on the node/add page. I end up with a bunch of links to "access denied" pages. Should node_add be checking the menu settings when displaying its links? Thanks, -Mark
This successfully removes it from the menu and appears to deny access as appropriate, but node_add doesn't seem to refer to menu settings when displaying links to the various node/add/$type pages. Therefore, whatever settings I change in the menu have no bearing on what shows up on the node/add page. I end up with a bunch of links to "access denied" pages. Should node_add be checking the menu settings when displaying its links?
Considering that the user will be denied access if he follows one of those links, I agree that node/add should be generated based on the menu. -moshe
Mark wrote:
This successfully removes it from the menu and appears to deny access as appropriate, but node_add doesn't seem to refer to menu settings when displaying links to the various node/add/$type pages. Therefore, whatever settings I change in the menu have no bearing on what shows up on the node/add page. I end up with a bunch of links to "access denied" pages. Should node_add be checking the menu settings when displaying its links?
Well, actually, it works for any node of a module with a name that comes before "relativity" alphabetically. It won't work for story.module, for example. Looking over menu.inc, it appears that the later path items overwrite previous ones of the same path. I suppose I could rename this module "zzrelativity" to put it at the end? ;-) -Mark
Mark wrote:
Well, actually, it works for any node of a module with a name that comes before "relativity" alphabetically. It won't work for story.module, for example. Looking over menu.inc, it appears that the later path items overwrite previous ones of the same path. I suppose I could rename this module "zzrelativity" to put it at the end? ;-)
Any suggestions on how to make this module override other modules' settings with menu.inc given the reverse-alphabetic priority? I'm considering a feature request for menu.inc to allow modules to specify a 'priority' attribute to resolve path conflicts. Dynamic security modules would tend to want higher priority than regular modules. Thanks, -Mark
Mark wrote:
Mark wrote:
Well, actually, it works for any node of a module with a name that comes before "relativity" alphabetically. It won't work for story.module, for example. Looking over menu.inc, it appears that the later path items overwrite previous ones of the same path. I suppose I could rename this module "zzrelativity" to put it at the end? ;-)
Any suggestions on how to make this module override other modules' settings with menu.inc given the reverse-alphabetic priority? I'm considering a feature request for menu.inc to allow modules to specify a 'priority' attribute to resolve path conflicts. Dynamic security modules would tend to want higher priority than regular modules.
Thanks, -Mark
Oddly enough this topic has come up with a partial resolution for path conflicts: http://drupal.org/node/17386 Different situation, but the thread should be of interest to this discussion. andre
Andre Molnar wrote:
Oddly enough this topic has come up with a partial resolution for path conflicts:
Thanks for pointing that out. I proposed a patch for prioritizing menu items, but in retrospect, I'm not sure if it's a complete fix for the path module issue there. The path module needs to know when a path is already taken for validation purposes and my patch won't address that. The previously suggested fix there wouldn't help my issue any, but indeed the problems are similar. -Mark
participants (6)
-
Andre Molnar -
Bèr Kessels -
Gerhard Killesreiter -
Mark -
Moshe Weitzman -
Robert Douglass