I am loving this module! I've made a small change to provide additional granularity in the access control:

/**
 * This function added to provide granularity for access
 * to files only if the user's role matches the node's
 * primary taxonomy term -- mrtoner 12/27/2007
 */
function filefield_myperms($node='') {
   global $user;
    
   $tids = '';
   $vid = 1;
   if ($node) {
      $terms = taxonomy_node_get_terms_by_vocabulary($node, $vid);
   } else {
      $terms = taxonomy_node_get_terms_by_vocabulary(arg(1), $vid);
   }
   foreach ($terms as $term) {
      $tids[] = $term->name;
   }
   if (in_array($tids[0],$user->roles)) {
      return TRUE;
   } else {
      return FALSE;
   }
}

...

function theme_filefield($file) {
  if ((user_access('view filefield uploads') || filefield_myperms()) && is_file($file['filepath']) && $file['list']) {

...

function filefield_file_download($file) {
    $file = file_create_path($file);
    $result = db_query("SELECT * FROM {files} WHERE filepath = '%s'", $file);
    if ($file = db_fetch_object($result)) {
      if (user_access('view filefield uploads') || filefield_myperms($file->nid)) {

...

My reason for doing this is that -- normally -- all users with 'view filefield uploads' permission can download any file if they have access to its associated node. For my project, all users have access to all nodes, but each user has access to only specific files.

So, I assign a taxonomy term to each node and a corresponding role to the user. Now, any user -- even anonymous -- can view the node, but only those with a role matching the taxonomy term can see the download link or download the file. And I don't need a full-blown access control module, which -- as far as I can tell -- would limit access to the entire node instead of just the associated file.

(If this can be done more elegantly, I'm open to suggestions.)

My reason for posting this: although this works, I need to further my Drupal Continuing Education. How does it work? Specifically, I mean what magic does Drupal use to know to pass the file request through the FileField module so that this access control works?

Don

Comments

agilpwc’s picture

The CCK Field Permissions module already allows you to set access control on individual cck fields based on role.

mrtoner’s picture

Yes, and it suffers from the same problem in this area that any other access control module does. (Of course, CCK Field Permissions isn't necessary at all, since FileField can set access control -- at least for viewing -- based on a role.)

I have a Download Link (a CCK FileField) on every Item node. Role A should be able to download files from some Items, Role B should be able to download files from different Items. All users should be able to view all Items.

If I grant access to Download Link to Role A, but not to Role B, then Role B cannot access the Download Link on his Items. If I grant access to Download Link to both Role A and Role B, then both roles can access files meant only for the other.

This isn't a failing of FileField or CCK Field Permissions or any access control module. It's just a consequence of the requirements of my project, one of which is that the node remain accessible to all users. (I'm not asking that FileField implement this feature; I just posted the snippet because I thought it might be useful to someone else.)

I also don't believe CCK Field Permissions would restrict the actual downloading of the file to a particular role; it would only restrict the viewing of the field. Actually, that was the main reason for my post: to ask, what magic does FileField use to route the request for a file through its access control?

jpetso’s picture

Status: Active » Fixed

Well, it's easy once you know it:
file_download() in includes/file.inc gets called from system.module which has the 'system/files' path registered. It determines the file path and then calls hook_file_download(), and in case any hook_file_download() implementation returns -1, it denies access to that file. Otherwise the file is transferred.

So instead of patching filefield, you could even create your own my_file_permissions.module, implement my_file_permissions_file_download(), and return -1 if you want the download to fail (or an empty array if you're indifferent on that). You could override theme_filefield() in your theme, and when you combine those two approaches you don't have to patch filefield at all :D

As you guessed correctly, I won't include this patch in filefield... but good work nonetheless!

Hope that helps,
-- Jakob

mrtoner’s picture

Thank you, Jakob! Overriding themes and implementing hooks is still confusing to me, but I'll get there. I understand that's preferable to "hacking" modules every time there's an update.

Don

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.