8

I am building a school site on Drupal 8. Among others, I have two content types, one for teachers, one for courses. Teachers also have user accounts and belong to a role, say 'teacher'.

I want teachers (authenticated site users who belong to the 'teacher' role) to be able to edit the pages of the courses they teach. The problem is, there are courses which are being taught by more than one teacher, hence I can't solve this simply by enabling 'edit own content' and have them as owners.

So all in all, I want to give 'edit access' for specific nodes, to specific, sometimes multiple, users.

I researched before asking this fairly simple question.

There is a very similar question here - however its four years old, and the node access module which is suggested as a solution is not usable for Drupal 8 yet.

There is a mention of another module, flexi access, but that is only available for Drupal 7.

There is also a link to ACL, "an API for other modules to create lists of users and give them access to nodes", but that in itself is only in pre-release for Drupal 8, and a module which seems to be using it, Content Access has open security issues (and also is in pre-release status).

Searching around, I also found Permissions by Term module, seems stable and very well documented, however I didn't find it very intuitive to be honest, and also it seems to cater basically for restricting view access to nodes (as suggested here, but also from its video tutorial).

I want something simpler. And I obviously want all nodes to still be publicly viewable by anyone (even anonymous users, of course). So although Permissions by Term seemed a possible choice, I don't know if I can/should use it.

There is also the Group module which is frequently referenced, but that also seems an overkill and way too complicated for the simple task I want to accomplish.

I 'm a bit lost on this one .. It seems quite simple, yet I can't find a way to do it. Any help would be greatly appreciated ...

4
  • 2
    It's not exactly simple since Drupal checks the author of the node which is a single field. Since forever, Drupal OOTB has anchored to that 'authored by' field as the point of access, which is why there are many contributed modules solving this in different ways. Group is probably the best bet here, but I guess another option would be adding a reference field to node types needing it and setting unlimited reference to users, then implement your own access check for node edit/delete that checks that list, in addition to node author, for if the current user should have access to edit or not.
    – Kevin
    Apr 23, 2018 at 18:44
  • You mean reference field to 'users' I guess.. I thought about this, but I 'd rather avoid it if I can. I 'm on a fairly tight schedule (with respect to time), and site is actually quite small, only a few users, and a few courses, so a dynamic solution, although elegant, won't be so useful and will take me much more time to implement. Also, I have limited Drupal experience.. I am experimenting with drupal.org/project/nodeaccess at the moment, although it is in Beta and listed as 'not usable' .. I hope I can find something more solid.. Thanks for your feedback.
    – thomas
    Apr 23, 2018 at 19:02
  • 2
    Instead of looking for modules you can add some lines of code in mymodule_node_access(), similar to node_node_access(), which is responsible for applying the "Edit own content" permission.
    – 4uk4
    Apr 23, 2018 at 19:39
  • so a custom module which kind of 'overrides' node_node_access() ? Perhaps another else-if which crudely checks, somehow, if for example user-id belongs to a specific pool of allowed user-ids for each node. That pool of user-ids could be inserted in the node even, as a field (?) .. Trying to understand - I 've only been using Drupal for a couple of months, I 'm still in the Desert of Despair, as aptly described here: drupalize.me/blog/201607/why-learning-drupal-hard
    – thomas
    Apr 23, 2018 at 19:49

5 Answers 5

8

The Group module is what you should be looking at ... It's not °overkill° (as in your question), instead it's the only stable contributed D8 module available today that will also address your needs.

For this specific question, you'd enable the gnode submodule, and for each group type you would define the appropriate permissions (view, edit, delete, etc) for the various Content Types. Refer to my answer to "How to configure access to courses for teachers and students?" for a sample configuration.

Note:

Let me address (part of) your additional comment below this answer also, which is like so:

I will need to have quite a few Groups in my case - one for each course taught by more than 1 teacher.

If I was to configure the Group module for your case, I would use an approach like so:

  • Create a Group type = Courses.
  • Create Group roles = Teacher and Student.
  • Create exactly 1 Group for each possible Course, labeled (say) C1, C2, C3, ....
  • Only grant the Group Permission to "edit" a node of content type "Course" to users who have been granted the "Group role" Teacher. And as per your "I want all nodes to still be publicly viewable by anyone (even anonymous users)", you want to grant "View" access to "Outsiders" and "Anonymous", and probably also to "Students".
  • If only teacher (user) T1 is teaching Course C1, then only T1 is granted the Group role "Teacher" for (group) C1.
  • If teachers (users) T2 and T3 are teaching Course C2, then only T2 and T3 are granted the Group role "Teacher" for (group) C2.
  • When creating nodes of type "Course", assign them to 1 (and only one) Group (so either C1, C2, or C3, or ...). And decide about which teacher(s) (user(s)) Tx the newly created Course will be granted the Group role "Teacher".

Done ...

Resources

3
  • thanks. I was a bit put off by what I read in the 'Permissions by Term' documentation, where it is implied that Groups module adds a significant overhead. See under heading 'What about Organic Groups and the Group module?' here: drupal.org/project/permissions_by_term - specifically the lines: <i>"Group introduces a lot of it's own entity types to group the content. It adds an own sub-system for content grouping to Drupal, which is already possible by nodes and taxonomy terms".</i> I will need to have quite a few Groups in my case - one for each course taught by more than 1 teacher.
    – thomas
    Apr 23, 2018 at 19:54
  • hey @thomas check my updated answer (note I added). Apr 24, 2018 at 18:51
  • 1
    Thanks for the very detailed answer Pierre. It seems like a viable choice, and certainly a flexible solution for similar cases. I did solve my problem, using "nodeaccess" module in the end. Despite its UI being not very intuitive, and the module being in beta, I did some testing and it seems to do what I want. I will find some time in the next few days to write a detailed answer for others who might end up in this page looking for help.
    – thomas
    Apr 25, 2018 at 19:04
5

If you have a content type course with an entity reference field field_teachers you can enable edit for multiple users like this:

mymodule.module:

use Drupal\node\NodeInterface;
use Drupal\Core\Access\AccessResult;

/**
 * Implements hook_node_access().
 */
function mymodule_node_access(NodeInterface $node, $op, $account) {
  $type = $node->bundle();

  if ($type != 'course' || $op != 'update') {
    return AccessResult::neutral();
  }

  $uids = array_column($node->field_teachers->getValue(), 'target_id');

  return AccessResult::allowedIf(in_array($account->id(), $uids))->cachePerUser()->addCacheableDependency($node);
}

If field_teachers is not referencing users but another content type, then the uid of the teacher is probably stored in the referenced content type and you have to fetch the uid of each teacher from there. In this case add all nodes involved as cacheable dependencies, so that when a teacher's node is modified with a different uid the access result is invalidated.

2
  • thanks a lot for the detailed answer. I managed to solve my problem last night, using a fairly simple module, called nodeAccess (drupal.org/project/nodeaccess). It's in beta, but seems to work. I will comment further later, with an answer to my question, for future reference. However, your answer is helpful to me since I want to learn how Drupal works, and writing/understanding code is a good way of achieving this. I will probably try at a later stage to use a custom module for this. Thanks again.
    – thomas
    Apr 24, 2018 at 9:04
  • @4k4 I'm trying to build a module on the script you added above. It works but the users with no access to the node do get the edit button in the content overview page. Is there a way to solve this?
    – Joost
    Oct 28, 2020 at 15:37
2

You can look into the Workbench Access module. This allows you to restrict editing rights to nodes based on menu structure or a taxonomy.

You can create a taxonomy vocabulary for the different editor groups. Example terms may be 4th Grade Math, 5th grade Science, etc, or even just Math, Science, etc. Add a taxonomy reference field to your Courses node, this is used to assign your content to your Groups. Then you can assign your users (teachers) to the correct Group (which are just based on your taxonomy vocabulary) and all teachers in the group can edit the node.

You could implement a situation where each course creates a corresponding taxonomy term automagically when a course node is created. You can do this with hook_ENTITY_TYPE_insert.

Something like the following:

function hook_node_insert($node) {
  if ($node->bundle() == 'course') {
    // Check if a term with the $node->title() already exists. (See below [1])
    // Or create a term (See below [2])

    // Then set your taxonomy term reference field with the new tid, or existing tid
    $node->field_my_tax_group_field[] = ['target_id' => $the_tid];

    // Then save the node.
    $node->save();
  } 
}

If you use this technique, the only thing you'll need to do manually after creating a Course node is assign the correct users to the Group to allow them to edit it.

[1] Check if a term exists.

[2] Create a new taxonomy term

1

Another option heavily used in some D7 instances, and like other contrib, not fully ready for D8 is Organic Groups. Even if ready for prime time, though, it does have a bit of a learning curve, but can be quite handy. A use case (although still in D7) similar to your needs is COD (Conference Organizer Distribution), which is used to run major events like DrupalCon.

You may want to see if it works for you—but be forewarned—some solutions architects I work with have been pretty frustrated with the D8 version. This is due to the significant architectural changes between D7 and D8, but it may work in your case.

2
  • Thanks for your feedback .. I 'll have a look at that, I need something for D8 though.
    – thomas
    Apr 23, 2018 at 19:03
  • From everything I've read, if you're looking for Organic Groups behavior in D8 you should use the Group module you referenced above.
    – sonfd
    Apr 23, 2018 at 19:04
1

It's been a long time, but I thought of answering this question so that it could perhaps be more helpful to people ending up here, looking for an answer.

First, I 'd like to thank all those who took the time and effort to write answers and comments - as a Drupal newbie myself, it helps a lot to have this kind of feedback from more experienced users (something that, in my opinion, Drupal lacks a little bit..)

Anyway, as I mentioned in my question, I had found a very similar question but I was reluctant to use the answer there because it was quite old, and the module suggested seemed unstable for Drupal 8 (still in beta - and with that note suggesting: "This module has a pre-release version for Drupal 8. ").

However, I did solve my problem using the Nodeaccess module mentioned in that (now 5 years old) thread - it works alright, although still in beta for D8. I tested on a development site, and then used it on the production site, and it does what I want (i.e. - grant edit access to specific, sometimes multiple, users).

So I just leave this here for future reference.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.