diff --git a/css/field_permissions.field.settings.css b/css/field_permissions.field.settings.css new file mode 100644 index 0000000..a5d7b26 --- /dev/null +++ b/css/field_permissions.field.settings.css @@ -0,0 +1,19 @@ +/** + * @file + * CSS for the permissions matrix on the field settings page. + */ + +/** + * Do not display the hide/show descriptions link above the permissions matrix. + */ +#field-ui-field-edit-form .compact-link { + display: none; +} + +/** + * Indent the matrix and make it appear inline with the corresponding radio button. + */ +#field-ui-field-edit-form table#permissions { + margin-left: 1.5em; + width: 98%; +} diff --git a/field_permissions.install b/field_permissions.install index 831c606..5f9b070 100644 --- a/field_permissions.install +++ b/field_permissions.install @@ -26,3 +26,101 @@ function field_permissions_update_7000(&$sandbox) { ->execute(); } +/** + * Migrate field permission settings to the new system (public/hidden/custom). + */ +function field_permissions_update_7001() { + foreach (field_info_fields() as $field_name => $field) { + // If the field has any field permissions enabled, it will be using custom + // permissions under the new system and needs to be converted. Otherwise, + // it is a public field (the default) and can be ignored. + if (!empty($field['settings']['field_permissions']) && array_filter($field['settings']['field_permissions'])) { + // Set the type to FIELD_PERMISSIONS_CUSTOM. (The module may be disabled + // when this update function runs, so we need to use the numeric value + // rather than relying on the constant being defined.) + $field['field_permissions']['type'] = 2; + + $field_permissions = $field['settings']['field_permissions']; + $permissions_by_operation = array( + // View-related permissions. + array( + 'view' => "view $field_name", + 'view own' => "view own $field_name", + ), + // Edit-related permissions. + array( + 'create' => "create $field_name", + 'edit' => "edit $field_name", + 'edit own' => "edit own $field_name", + ), + ); + + // Loop through each type of operation (view or edit). + foreach ($permissions_by_operation as $permissions) { + $actions = array_keys($permissions); + // If none of the related permissions were enabled, all users were + // allowed to perform the relevant actions on this field, so we need to + // assign permissions here to preserve that behavior. + $has_enabled_permissions = (bool) array_filter(array_intersect_key($field_permissions, array_flip($actions))); + if (!$has_enabled_permissions) { + _update_7000_user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, $permissions, 'field_permissions'); + _update_7000_user_role_grant_permissions(DRUPAL_AUTHENTICATED_RID, $permissions, 'field_permissions'); + } + // Otherwise, for each permission that was disabled, no users should be + // allowed to perform that action; therefore, make sure to unassign any + // (stale) permissions that they may have. + else { + foreach ($actions as $action) { + if (empty($field_permissions[$action])) { + if ($action != 'create') { + $permission = $permissions[$action]; + $rids = array_keys(user_roles(FALSE, $permission)); + foreach ($rids as $rid) { + user_role_revoke_permissions($rid, array($permission)); + } + } + // The 'create' action needs special handling, since previously, + // if create permissions were not enabled the code would have + // fallen back on checking edit permissions. Now, though, create + // permissions are always enabled (and always checked when an + // entity is being created). Therefore, we need to figure out + // what the fallback would have been and assign new create + // permissions based on that. + else { + $rids_with_create_access = array(); + // The first fallback is edit permissions; if those are + // enabled, any role with edit permission would have been + // granted access. + if (!empty($field_permissions['edit'])) { + $rids_with_create_access = array_keys(user_roles(FALSE, $permissions['edit'])); + } + // The final fallback is 'edit own' permissions; if those are + // enabled, any role with 'edit own' permission would have been + // granted access. (It is additionally required that the entity + // being checked is owned by the current user, but in the case + // of nodes being created that will always be the case anyway, + // and nodes are the only entities we need to support for the + // D6-to-D7 upgrade.) + if (!empty($field_permissions['edit own'])) { + $rids_with_create_access = array_unique(array_merge($rids_with_create_access, array_keys(user_roles(FALSE, $permissions['edit own'])))); + } + // Assign create permissions to all the relevant roles. + foreach ($rids_with_create_access as $rid) { + _update_7000_user_role_grant_permissions($rid, array($permissions['create']), 'field_permissions'); + } + } + } + } + } + } + } + // Remove the old field permissions settings if necessary, and save the + // field. + if (isset($field['settings']['field_permissions'])) { + // We can't unset this or field_update_field() will automatically add it + // back (using the prior field data), so do the next best thing. + $field['settings']['field_permissions'] = NULL; + field_update_field($field); + } + } +} diff --git a/field_permissions.module b/field_permissions.module index 0a70d00..6f9cbe2 100644 --- a/field_permissions.module +++ b/field_permissions.module @@ -9,6 +9,24 @@ */ /** + * Indicates that a field does not have any access control. + */ +define('FIELD_PERMISSIONS_PUBLIC', 0); + +/** + * Indicates that a field is hidden. + * + * Hidden fields are never displayed, and are only editable by the author (and + * by site administrators with the 'bypass field access' permission). + */ +define('FIELD_PERMISSIONS_HIDDEN', 1); + +/** + * Indicates that a field has custom permissions. + */ +define('FIELD_PERMISSIONS_CUSTOM', 2); + +/** * Implements hook_help(). */ function field_permissions_help($path, $arg) { @@ -115,21 +133,34 @@ function field_permissions_form_field_ui_field_edit_form_alter(&$form, $form_sta */ function field_permissions_field_access($op, $field, $obj_type, $object, $account) { // Ignore the request if permissions have not been enabled for this field. - $field_permissions = (isset($field['settings']['field_permissions']) && is_array($field['settings']['field_permissions']) ? array_filter($field['settings']['field_permissions']) : array()); - if (empty($field_permissions)) { + if (!isset($field['field_permissions']['type']) || $field['field_permissions']['type'] == FIELD_PERMISSIONS_PUBLIC) { return; } - - if ($op == 'view') { - if (!empty($field_permissions['view']) || !empty($field_permissions['view own'])) { + // If the field is hidden, then no one is allowed to see it when the object + // is being viewed, and only the author (and administrators with the 'bypass + // field access' permissions) can edit it. + elseif ($field['field_permissions']['type'] == FIELD_PERMISSIONS_HIDDEN) { + if ($op == 'view') { + return FALSE; + } + elseif ($op == 'edit') { module_load_include('inc', 'field_permissions', 'includes/field_access'); - return _field_permissions_field_view_access($field['field_name'], $field_permissions, $obj_type, $object, $account); + return _field_permissions_object_is_owned_by_account($object, $account) || user_access('bypass field access', $account); } } - elseif ($op == 'edit') { - if (!empty($field_permissions['edit']) || !empty($field_permissions['edit own']) || !empty($field_permissions['create'])) { + // Otherwise, check access by permission. + elseif ($field['field_permissions']['type'] == FIELD_PERMISSIONS_CUSTOM) { + if (user_access('bypass field access', $account)) { + return TRUE; + } + else { module_load_include('inc', 'field_permissions', 'includes/field_access'); - return _field_permissions_field_edit_access($field['field_name'], $field_permissions, $obj_type, $object, $account); + if ($op == 'view') { + return _field_permissions_field_view_access($field['field_name'], $obj_type, $object, $account); + } + elseif ($op == 'edit') { + return _field_permissions_field_edit_access($field['field_name'], $obj_type, $object, $account); + } } } } diff --git a/includes/admin.inc b/includes/admin.inc index b79da03..fda7e21 100644 --- a/includes/admin.inc +++ b/includes/admin.inc @@ -7,38 +7,90 @@ /** * Obtain the list of field permissions. + * + * @param $field_label + * The human readable name of the field to use when constructing permission + * names. Usually this will be derived from one or more of the field instance + * labels. */ -function field_permissions_list($field_name = '') { +function field_permissions_list($field_label = '') { return array( 'create' => array( - 'label' => t('Create field'), - 'title' => t('Create @field', array('@field' => $field_name)), - 'description' => t('Create @field (edit on content creation).', array('@field' => $field_name)), - ), - 'edit' => array( - 'label' => t('Edit field'), - 'title' => t('Edit any @field', array('@field' => $field_name)), - 'description' => t('Edit @field, regardless of content author.', array('@field' => $field_name)), + 'label' => t('Add field'), + 'title' => t('Add own value for field %field', array('%field' => $field_label)), ), 'edit own' => array( 'label' => t('Edit own field'), - 'title' => t('Edit own @field', array('@field' => $field_name)), - 'description' => t('Edit own @field on content created by the user.', array('@field' => $field_name)), + 'title' => t('Edit own value for field %field', array('%field' => $field_label)), ), - 'view' => array( - 'label' => t('View field'), - 'title' => t('View any @field', array('@field' => $field_name)), - 'description' => t('View @field, regardless of content author.', array('@field' => $field_name)), + 'edit' => array( + 'label' => t('Edit field'), + 'title' => t('Edit any value for field %field', array('%field' => $field_label)), ), 'view own' => array( 'label' => t('View own field'), - 'title' => t('View own @field', array('@field' => $field_name)), - 'description' => t('View own @field on content created by the user.', array('@field' => $field_name)), + 'title' => t('View own value for field %field', array('%field' => $field_label)), + ), + 'view' => array( + 'label' => t('View field'), + 'title' => t('View any value for field %field', array('%field' => $field_label)), ), ); } /** + * Returns field permissions in a format suitable for use in hook_permission(). + * + * @param $field + * The field to return permissions for. + * @param $label + * (optional) The human readable name of the field to use when constructing + * permission names; for example, this might be the label of one of the + * corresponding field instances. If not provided, an appropriate label will + * be automatically derived from all the field's instances. + * + * @return + * An array of permission information, suitable for use in hook_permission(). + */ +function field_permissions_list_field_permissions($field, $label = NULL) { + $description = ''; + + // If there is no preferred label, construct one from all the instance + // labels. + if (!isset($label)) { + $labels = array(); + foreach ($field['bundles'] as $entity_type => $bundles) { + foreach ($bundles as $bundle_name) { + $instance = field_info_instance($entity_type, $field['field_name'], $bundle_name); + $labels[] = $instance['label']; + } + } + // If all the instances have the same label, just use that. Otherwise, use + // the field name (with the full list of instance labels as the permission + // description). + $labels = array_unique($labels); + if (count($labels) == 1) { + $label = array_shift($labels); + } + else { + $label = $field['field_name']; + $description = t('This field appears as: %instances', array('%instances' => implode(', ', $labels))); + } + } + + $permissions = array(); + foreach (field_permissions_list($label) as $permission_type => $permission_info) { + $permission = $permission_type . ' ' . $field['field_name']; + $permissions[$permission] = array( + 'title' => $permission_info['title'], + 'description' => $description, + ); + } + + return $permissions; +} + +/** * Implementation of hook_permission(). */ function _field_permissions_permission() { @@ -46,20 +98,21 @@ function _field_permissions_permission() { 'administer field permissions' => array( 'title' => t('Administer field permissions'), 'description' => t('Manage field permissions and field permissions settings.'), + 'restrict access' => TRUE, + ), + 'bypass field access' => array( + 'title' => t('Bypass field access control'), + 'description' => t('Create, edit and view all field values, regardless of permission restrictions.'), + 'restrict access' => TRUE, ), ); - foreach (field_info_fields() as $field_name => $field) { - if (!empty($field['settings']['field_permissions'])) { - foreach (field_permissions_list($field_name) as $permission_type => $permission_info) { - if (!empty($field['settings']['field_permissions'][$permission_type])) { - $perms[$permission_type . ' ' . $field_name] = array( - 'title' => $permission_info['title'], - 'description' => $permission_info['description'], - ); - } - } + + foreach (field_info_fields() as $field) { + if (isset($field['field_permissions']['type']) && $field['field_permissions']['type'] == FIELD_PERMISSIONS_CUSTOM) { + $perms += field_permissions_list_field_permissions($field); } } + return $perms; } @@ -67,50 +120,193 @@ function _field_permissions_permission() { * Alter the field settings form. */ function _field_permissions_field_settings_form_alter(&$form, $form_state, $form_id) { - // Obtain the field name from the form itself. - $field_name = isset($form['instance']['field_name']['#value']) ? $form['instance']['field_name']['#value'] : ''; + // Put the field permissions extensions at the top of the field settings + // fieldset. + $form['field']['field_permissions'] = array( + '#weight' => -10, + '#access' => user_access('administer field permissions'), + ); - // Try to obtain information about this field. - $field = field_info_field($field_name); - if (empty($field)) { - return; + $form['field']['field_permissions']['type'] = array( + '#title' => t('Field visibility and permissions'), + '#type' => 'radios', + '#options' => array( + FIELD_PERMISSIONS_PUBLIC => t('Everyone can view'), + FIELD_PERMISSIONS_HIDDEN => t('Administrators can view'), + FIELD_PERMISSIONS_CUSTOM => t('Custom permissions'), + ), + '#default_value' => isset($form['#field']['field_permissions']['type']) ? $form['#field']['field_permissions']['type'] : FIELD_PERMISSIONS_PUBLIC, + ); + + // Add the container in which the field permissions matrix will be displayed. + // (and make it so that it is only visible when custom permissions are being + // used). + $form['field']['field_permissions']['permissions'] = array( + '#type' => 'container', + '#states' => array( + 'visible' => array( + // We must cast this to a string until http://drupal.org/node/879580 is + // fixed. + ':input[name="field[field_permissions][type]"]' => array('value' => (string) FIELD_PERMISSIONS_CUSTOM), + ), + ), + // Custom styling for the permissions matrix on the field settings page. + '#attached' => array( + 'css' => array(drupal_get_path('module', 'field_permissions') . '/css/field_permissions.field.settings.css'), + ), + ); + + // Add the field permissions matrix itself. Wait until the #pre_render stage + // to move it to the above container, to avoid having the permissions data + // saved as part of the field record. + $form['field_permissions']['#tree'] = TRUE; + $form['field_permissions']['permissions'] = field_permissions_permissions_matrix($form['#field'], $form['#instance']); + $form['#pre_render'][] = '_field_permissions_field_settings_form_pre_render'; + + // Add a submit handler to process the field permissions settings. Note that + // it is important for this to run *after* the main field UI submit handler + // (which saves the field itself), since when a new field is being created, + // our submit handler will try to assign any new custom permissions + // immediately, and our hook_permission() implementation relies on the field + // info being up-to-date in order for that to work correctly. + $form['#submit'][] = '_field_permissions_field_settings_form_submit'; +} + +/** + * Returns a field permissions matrix that can be inserted into a form. + * + * The matrix's display is based on that of Drupal's default permissions page. + * + * Note that this matrix must be accompanied by an appropriate submit handler + * (attached to the top level of the form) in order for the permissions in it + * to actually be saved. For an example submit handler, see + * _field_permissions_field_settings_form_submit(). + * + * @param $field + * The field whose permissions will be displayed in the matrix. + * @param $instance + * The field instance for which the permissions will be displayed. Although + * the permissions are per-field rather than per-instance, the instance label + * will be used to display an appropriate human-readable name for each + * permission. + * + * @return + * A form array defining the permissions matrix. + * + * @see user_admin_permissions() + * @see _field_permissions_field_settings_form_submit() + */ +function field_permissions_permissions_matrix($field, $instance) { + // This function primarily contains a simplified version of the code from + // user_admin_permissions(). + $form['#theme'] = 'user_admin_permissions'; + $options = array(); + $status = array(); + + // Retrieve all role names for use in the submit handler. + $role_names = user_roles(); + $form['role_names'] = array( + '#type' => 'value', + '#value' => $role_names, + ); + + // Retrieve the permissions for each role, and the field permissions we will + // be assigning here. + $role_permissions = user_role_permissions($role_names); + $field_permissions = field_permissions_list_field_permissions($field, $instance['label']); + + // Determine if it is safe to reset the default values for this field's + // permissions. If this is a new field (never saved with field permission + // data before), or if it's an existing field that is not currently using + // custom permissions and doesn't have any previously-saved ones already in + // the database, then it will be safe to reset them. + $reset_permissions_defaults = FALSE; + if (!isset($field['field_permissions']['type'])) { + $reset_permissions_defaults = TRUE; + } + elseif ($field['field_permissions']['type'] != FIELD_PERMISSIONS_CUSTOM) { + $all_assigned_permissions = call_user_func_array('array_merge_recursive', $role_permissions); + $assigned_field_permissions = array_intersect_key($all_assigned_permissions, $field_permissions); + $reset_permissions_defaults = empty($assigned_field_permissions); } - // Enhance the field settings form with field permissions extensions. - $field_permissions = array(); - foreach (field_permissions_list($field_name) as $permission_type => $permission_info) { - $field_permissions[$permission_type] = $permission_info['description']; + // Go through each field permission we will display. + foreach ($field_permissions as $permission => $info) { + // Display the name of the permission as a form item. + $form['permission'][$permission] = array( + '#type' => 'item', + '#markup' => $info['title'], + ); + // Save it to be displayed as one of the role checkboxes. + $options[$permission] = ''; + // If we are in a situation where we can reset the field permissions + // defaults, we do so by pre-checking the admin role's checkbox for this + // permission. + if ($reset_permissions_defaults) { + if (($admin_rid = variable_get('user_admin_role', 0)) && isset($role_names[$admin_rid])) { + $status[$admin_rid][] = $permission; + } + } + // Otherwise (e.g., for fields with custom permissions already saved), + // determine whether the permission is already assigned and check each + // checkbox accordingly. + else { + foreach ($role_names as $rid => $name) { + if (isset($role_permissions[$rid][$permission])) { + $status[$rid][] = $permission; + } + } + } } - $form['field']['settings']['field_permissions'] = array( - '#title' => t('Field permissions'), - '#type' => 'checkboxes', - '#checkall' => TRUE, - '#options' => $field_permissions, - '#default_value' => (isset($field['settings']['field_permissions']) && is_array($field['settings']['field_permissions']) ? array_filter($field['settings']['field_permissions']) : array()), - '#description' => t('Use these options to enable role based permissions for this field. -When permissions are enabled, access to this field is denied by default and explicit permissions should be granted to the proper user roles from the permissions administration page. -On the other hand, when these options are disabled, field permissions are inherited from the content view and/or edit permissions. In example, users allowed to view a particular node will also be able to view this field, and so on.', array( - '@admin-permissions' => url('admin/people/permissions', array('fragment' => 'module-field_permissions')), - )), - '#weight' => -1, - ); - // Hide the option to non-privileged users. - if (!user_access('administer field permissions')) { - $form['field']['settings']['field_permissions']['#type'] = 'value'; - $form['field']['settings']['field_permissions']['#value'] = $form['field']['settings']['field_permissions']['#default_value']; + // Build the checkboxes for each role. + foreach ($role_names as $rid => $name) { + $form['checkboxes'][$rid] = array( + '#type' => 'checkboxes', + '#options' => $options, + '#default_value' => isset($status[$rid]) ? $status[$rid] : array(), + '#attributes' => array('class' => array('rid-' . $rid)), + ); + $form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE); } - // Submit handler to grant the new permissions to the administrator role. - $form['#submit'][] = '_field_permissions_field_settings_form_submit'; + // Attach the default permissions page JavaScript. + $form['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.permissions.js'; + + return $form; +} + +/** + * Pre-render function for the permissions matrix on the field settings form. + */ +function _field_permissions_field_settings_form_pre_render($form) { + // Move the permissions matrix to its final location. + $form['field']['field_permissions']['permissions']['matrix'] = $form['field_permissions']['permissions']; + unset($form['field_permissions']); + return $form; } /** * Form callback; Submit handler for the Field Settings form. */ -function _field_permissions_field_settings_form_submit() { - // Grant any new permissions to the admin role. - user_modules_installed(array('field_permissions')); +function _field_permissions_field_settings_form_submit($form, &$form_state) { + // Save the field permissions when appropriate to do so. + $new_field_permissions_type = $form_state['values']['field']['field_permissions']['type']; + if ($new_field_permissions_type == FIELD_PERMISSIONS_CUSTOM && isset($form_state['values']['field_permissions']['permissions'])) { + $field_permissions = $form_state['values']['field_permissions']['permissions']; + foreach ($field_permissions['role_names'] as $rid => $name) { + user_role_change_permissions($rid, $field_permissions['checkboxes'][$rid]); + } + } + + // We must clear the page and block caches whenever the field permission type + // setting has changed (because users may now be allowed to see a different + // set of fields). For similar reasons, we must clear these caches whenever + // custom field permissions are being used, since those may have changed too; + // see user_admin_permissions_submit(). + if (!isset($form['#field']['field_permissions']['type']) || $new_field_permissions_type != $form['#field']['field_permissions']['type'] || $new_field_permissions_type == FIELD_PERMISSIONS_CUSTOM) { + cache_clear_all(); + } } /** @@ -130,6 +326,9 @@ function field_permissions_overview() { $field_types = field_info_field_types(); $bundles = field_info_bundles(); + // Retrieve the permissions for each role. + $role_permissions = user_role_permissions(user_roles()); + // Based on field_ui_fields_list() in field_ui.admin.inc. $rows = array(); foreach ($instances as $obj_type => $type_bundles) { @@ -143,36 +342,50 @@ function field_permissions_overview() { $rows[$field_name]['data'][2] = $obj_type; $rows[$field_name]['data'][3][] = l($bundles[$obj_type][$bundle]['label'], $admin_path . '/fields/'. $field_name, array( 'query' => $destination, - 'fragment' => 'edit-field-settings-field-permissions', + 'fragment' => 'edit-field-field-permissions-type', )); $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array(''); // Append field permissions information to the report. - $field_permissions = (isset($field['settings']['field_permissions']) && is_array($field['settings']['field_permissions']) ? array_filter($field['settings']['field_permissions']) : array()); - foreach (array_keys(field_permissions_list()) as $index => $permission_type) { + $type = isset($field['field_permissions']['type']) ? $field['field_permissions']['type'] : FIELD_PERMISSIONS_PUBLIC; + foreach (array_keys(field_permissions_list_field_permissions($field)) as $index => $permission) { // Put together the data value for the cell. $data = ''; - if (!empty($field_permissions[$permission_type])) { - // Link the Enabled permission to the permissions page. + $full_colspan = FALSE; + if ($type == FIELD_PERMISSIONS_PUBLIC) { + $data = t('Public field (everyone can access)'); + $full_colspan = TRUE; + } + elseif ($type == FIELD_PERMISSIONS_HIDDEN) { + $data = t('Hidden field (only the author and administrators can edit)'); + $full_colspan = TRUE; + } + else { + // This is a field with custom permissions. Link the field to the + // appropriate row of the permissions page, and theme it based on + // whether all users have access. + $all_users_have_access = isset($role_permissions[DRUPAL_ANONYMOUS_RID][$permission]) && isset($role_permissions[DRUPAL_AUTHENTICATED_RID][$permission]); + $status_class = $all_users_have_access ? 'field-permissions-status-on' : 'field-permissions-status-off'; + $title = $all_users_have_access ? t('All users have this permission') : t('Not all users have this permission'); $data = l('', 'admin/people/permissions', array( 'attributes' => array( - 'class' => array('field-permissions-status', 'field-permissions-status-on'), - 'title' => t('Enabled'), + 'class' => array('field-permissions-status', $status_class), + 'title' => $title, ), - 'fragment' => drupal_html_class("edit $permission_type $field_name"), + 'query' => $destination, + 'fragment' => drupal_html_class("edit $permission"), )); } - else { - // Simply display the status off text. - $title = t('Disabled'); - $data = ''; - } // Construct the cell. $rows[$field_name]['data'][4 + $index] = array( 'data' => $data, 'class' => array('field-permissions-cell'), ); + if ($full_colspan) { + $rows[$field_name]['data'][4 + $index]['colspan'] = 5; + break; + } } } } diff --git a/includes/field_access.inc b/includes/field_access.inc index 6d845b7..a09fc4e 100644 --- a/includes/field_access.inc +++ b/includes/field_access.inc @@ -8,15 +8,15 @@ /** * Implementation of hook_field_access('view'). */ -function _field_permissions_field_view_access($field_name, $field_permissions, $obj_type, $object, $account) { +function _field_permissions_field_view_access($field_name, $obj_type, $object, $account) { // Check if user has access to view this field in any object. - if (!empty($field_permissions['view']) && user_access('view '. $field_name, $account)) { + if (user_access('view '. $field_name, $account)) { return TRUE; } - // If 'view own' permission has been enabled for this field, then we can - // check if the user has the right permission, and ownership of the object. - if (!empty($field_permissions['view own']) && user_access('view own '. $field_name, $account)) { + // If the user has permission to view objects that they own, return TRUE if + // they own this object or FALSE if they don't. + if (user_access('view own '. $field_name, $account)) { // When field_access('view') is invoked, it may or may not provide // an object. It will, almost always, except when this function is @@ -31,27 +31,7 @@ function _field_permissions_field_view_access($field_name, $field_permissions, $ return TRUE; } - // Try to get the uid of the object author from the object itself. - // When invoked by Views to render a field, we may not have the uid of the - // object, so we need to retrieve it from the object table. - if (isset($object->uid)) { - $object_uid = $object->uid; - } - // @todo: what to do with non-node objects? - elseif (!empty($object->vid)) { - $object_uid = db_query('SELECT uid FROM {node_revision} WHERE vid = :vid', array(':vid' => $object->vid))->fetchField(); - } - elseif (!empty($object->nid)) { - $object_uid = db_query('SELECT uid FROM {node} WHERE nid = :nid', array(':nid' => $object->nid))->fetchField(); - } - else { - // Deny access to view the field if we have not been able to get the uid - // of the object author. - return FALSE; - } - - // Finally, we can now check if ownership of the object matches. - return (is_numeric($object_uid) && $object_uid == $account->uid); + return _field_permissions_object_is_owned_by_account($object, $account); } return FALSE; @@ -60,22 +40,49 @@ function _field_permissions_field_view_access($field_name, $field_permissions, $ /** * Implementation of hook_field_access('edit'). */ -function _field_permissions_field_edit_access($field_name, $field_permissions, $obj_type, $object, $account) { +function _field_permissions_field_edit_access($field_name, $obj_type, $object, $account) { // Check if user has access to edit this field on object creation. - if (empty($object->nid) && !empty($field_permissions['create'])) { + if (empty($object->nid)) { return user_access('create '. $field_name, $account); } // Check if user has access to edit this field in any object. - if (!empty($field_permissions['edit']) && user_access('edit '. $field_name, $account)) { + if (user_access('edit '. $field_name, $account)) { return TRUE; } - // If 'edit own' permission has been enabled for this field, then we can - // check if the user has the right permission, and ownership of the object. - if (!empty($field_permissions['edit own']) && user_access('edit own '. $field_name, $account) && $object->uid == $account->uid) { + // If the user has permission to edit objects that they own, check if they + // own this object and return TRUE if they do. + if (user_access('edit own '. $field_name, $account) && _field_permissions_object_is_owned_by_account($object, $account)) { return TRUE; } return FALSE; } + +/** + * Returns TRUE if an object is owned by a user account, FALSE otherwise. + */ +function _field_permissions_object_is_owned_by_account($object, $account) { + // Try to get the uid of the object author from the object itself. When + // invoked by Views to render a field, we may not have the uid of the object, + // so we need to retrieve it from the object table. + if (isset($object->uid)) { + $object_uid = $object->uid; + } + // @todo: what to do with non-node objects? + elseif (!empty($object->vid)) { + $object_uid = db_query('SELECT uid FROM {node_revision} WHERE vid = :vid', array(':vid' => $object->vid))->fetchField(); + } + elseif (!empty($object->nid)) { + $object_uid = db_query('SELECT uid FROM {node} WHERE nid = :nid', array(':nid' => $object->nid))->fetchField(); + } + else { + // Deny access to view the field if we have not been able to get the uid of + // the object author. + return FALSE; + } + + // Finally, we can now check if ownership of the object matches. + return (is_numeric($object_uid) && $object_uid == $account->uid); +}