FINAL suepr merge step : added all modules to this super repos

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-19 16:46:59 +02:00
7585 changed files with 1723356 additions and 18 deletions

View File

@@ -0,0 +1,27 @@
7.x-1.0-beta1
==============
- #1312596 by Rob Loach: Clean up the module file structure.
- #1307312 by Rob Loach: Remove troubleshooting interface as we now have tests.
- #1230284 by zhgenti, David_Rothstein | dboulet: Use form_load_include()
instead of module_load_include() to fix form submits.
- #1306780 by David_Rothstein: Private fields should allow administrators view
access.
- #1298966 by David_Rothstein: Fix static caching in tests.
- #1298966 by Gabor Hojtsy: Initial tests.
- #1279712 by David_Rothstein, Jeff Noyes, Stellina McKinney, Gabor Hojtsy:
Revamp Field Permissions user interface to make it more intuitive.
- #1141330 by David_Rothstein: Fix Field Permissions support with Views.
- #1073284 by joelstein, Rob Loach: Administrator permissions for new fields.
7.x-1.0-alpha1
==============
- #1063162 by jide, Rob Loach: Field Permissions not accessible for some fields.
- #965110 by Danic: Move Field Permissions UI to Reports.
- #965094 by Danic, Rob Loach: Group Title and Description in modules page.
- #1043522 by erikwebb: Permissions administration link wrong on Edit Field page.
- Small documentation changes.
- Added support for create field permission.
- Every permission type can be enabled independently.
- Sync code base from 6.x-1.0 release.
- Fix node revisions table name.

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,84 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Field Permissions module
;;
;; Original author: markus_petrux (http://drupal.org/user/39593)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CONTENTS OF THIS FILE
=====================
* OVERVIEW
* USAGE
* REQUIREMENTS
* INSTALLATION
OVERVIEW
========
The Field Permissions module allows site administrators to set field-level
permissions for fields that are attached to any kind of entity (such as nodes
or users).
Permissions can be set for editing or viewing the field (either in all
contexts, or only when it is attached to an entity owned by the current user).
Permissions can also be set for editing the field while creating a new entity.
Permissions for each field are not created by default. Instead, administrators
can enable these permissions explicitly for the fields where this feature is
needed.
USAGE
=====
Once Field Permissions module is installed, you need to edit the field settings
form to enable permissions for each field where you need this feature. You can
choose from three options:
* Public (author and administrators can edit, everyone can view)
* Private (only author and administrators can edit and view)
* Custom permissions
The default value ("Public") does not impose any field-level access control,
meaning that permissions are inherited from the entity view or edit
permissions. For example, users who are allowed to view a particular node that
the field is attached to will also be able to view the field.
"Private" provides quick and easy access to a commonly used form of field
access control.
Finally, if "Custom permissions" is chosen, a standard permissions matrix will
be revealed allowing you full flexibility to assign the following permissions
to any role on your site:
* Create own value for field FIELD
* Edit own value for field FIELD
* Edit anyone's value for field FIELD
* View own value for field FIELD
* View anyone's value for field FIELD
These permissions will also be available on the standard permissions page at
Administer -> People -> Permissions.
INSTALLATION
============
1) Copy all contents of this package to your modules directory preserving
subdirectory structure.
2) Go to Administer -> Modules to install module. If the (Drupal core) Field UI
module is not enabled, do so.
3) Review the settings of your fields. You will find a new option labelled
"Field visibility and permissions" that allows you to control access to the
field.
4) If you chose the setting labelled "Custom permissions", you will be able to
set this field's permissions for any role on your site directly from the
field edit form, or later on by going to the Administer -> People ->
Permissions page.
5) Get an overview of the Field Permissions at:
Administer -> Reports -> Field list -> Permissions

View File

@@ -0,0 +1,74 @@
/* Table cells. */
.field-permissions-cell,
.field-permissions-header {
text-align: center;
}
/* Status icons. */
.field-permissions-status-on {
display: inline-block;
width: 16px;
height: 16px;
background: url(images/field_permissions.status-on.png) no-repeat 0 0;
}
.field-permissions-status-off {
display: inline-block;
width: 16px;
height: 16px;
background: url(images/field_permissions.status-off.png) no-repeat 0 0;
}
/* Quick tooltips behavior. */
html.js .field-permissions-tooltip {
display: none;
}
#field-permissions-tooltip {
display: none;
padding: 1em 2em 1em 1em;
color: #444;
background-color: #f0f0f0;
border: 1px solid #aaa;
/* CSS3 properties not supported by all browsers. */
-webkit-box-shadow: 2px 2px 2px #ccc;
-khtml-box-shadow: 2px 2px 2px #ccc;
-icab-box-shadow: 2px 2px 2px #ccc;
-moz-box-shadow: 2px 2px 2px #ccc;
-o-box-shadow: 2px 2px 2px #ccc;
box-shadow: 2px 2px 2px #ccc;
-webkit-border-radius: 5px;
-khtml-border-radius: 5px;
-icab-border-radius: 5px;
-moz-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
}
.field-permissions-tooltip .item-list,
#field-permissions-tooltip .item-list {
text-align: left;
}
.field-permissions-tooltip h3,
#field-permissions-tooltip h3 {
font-size: 1.2em;
font-weight: bold;
}
/**
* Administration 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%;
}

View File

@@ -0,0 +1,426 @@
<?php
/**
* @file
* Administrative interface for the Field Permissions module.
*/
/**
* 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_label = '') {
return array(
'create' => array(
'label' => t('Create field'),
'title' => t('Create own value for field %field', array('%field' => $field_label)),
),
'edit own' => array(
'label' => t('Edit own field'),
'title' => t('Edit own value for field %field', array('%field' => $field_label)),
),
'edit' => array(
'label' => t('Edit field'),
'title' => t("Edit anyone's value for field %field", array('%field' => $field_label)),
),
'view own' => array(
'label' => t('View own field'),
'title' => t('View own value for field %field', array('%field' => $field_label)),
),
'view' => array(
'label' => t('View field'),
'title' => t("View anyone's 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() {
$perms = array(
'administer field permissions' => array(
'title' => t('Administer field permissions'),
'description' => t('Manage field permissions and field permissions settings.'),
'restrict access' => TRUE,
),
'access private fields' => array(
'title' => t("Access other users' private fields"),
'description' => t('View and edit the stored values of all private fields.'),
'restrict access' => TRUE,
),
);
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;
}
/**
* Alter the field settings form.
*/
function _field_permissions_field_settings_form_alter(&$form, $form_state, $form_id) {
// 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'),
);
$form['field']['field_permissions']['type'] = array(
'#title' => t('Field visibility and permissions'),
'#type' => 'radios',
'#options' => array(
FIELD_PERMISSIONS_PUBLIC => t('Public (author and administrators can edit, everyone can view)'),
FIELD_PERMISSIONS_PRIVATE => t('Private (only author and administrators can edit and 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') . '/field_permissions.admin.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']['#access'] = user_access('administer field permissions');
$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);
}
// Store this information on the form so that other modules can use it (for
// example, if they want to set default permissions for other roles besides
// the admin role which we use it for below).
$form['#field_permissions_are_new'] = $reset_permissions_defaults;
// 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;
}
// For fields attached to users, we also pre-check the anonymous user's
// checkbox for the permission to create the field, since that is the
// most common way in which new user entities are created.
if ($instance['entity_type'] == 'user' && $permission == 'create ' . $field['field_name']) {
$status[DRUPAL_ANONYMOUS_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;
}
}
}
}
// 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);
}
// Attach the default permissions page JavaScript.
$form['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.permissions.js';
// Attach our custom JavaScript for the permission matrix.
$form['#attached']['js'][] = drupal_get_path('module', 'field_permissions') . '/field_permissions.admin.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($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();
}
}
/**
* Menu callback; Field permissions overview.
*/
function field_permissions_overview() {
drupal_add_css(drupal_get_path('module', 'field_permissions') .'/field_permissions.admin.css');
$headers = array(t('Field name'), t('Field type'), t('Entity type'), t('Used in'));
foreach (field_permissions_list() as $permission_type => $permission_info) {
$headers[] = array('data' => $permission_info['label'], 'class' => 'field-permissions-header');
}
$destination = drupal_get_destination();
// Load list of field instances, types and bundles in the system.
$instances = field_info_instances();
$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) {
foreach ($type_bundles as $bundle => $bundle_instances) {
foreach ($bundle_instances as $field_name => $instance) {
// Each field will have a row in the table.
$field = field_info_field($field_name);
$admin_path = _field_ui_bundle_admin_path($obj_type, $bundle);
$rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
$rows[$field_name]['data'][1] = t($field_types[$field['type']]['label']);
$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-field-permissions-type',
));
$rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
// Append field permissions information to the report.
$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 = '';
$full_colspan = FALSE;
if ($type == FIELD_PERMISSIONS_PUBLIC) {
$data = t('Public field (author and administrators can edit, everyone can view)');
$full_colspan = TRUE;
}
elseif ($type == FIELD_PERMISSIONS_PRIVATE) {
$data = t('Private field (only author and administrators can edit and view)');
$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', $status_class),
'title' => $title,
),
'query' => $destination,
'fragment' => drupal_html_class("edit $permission"),
));
}
// 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;
}
}
}
}
}
foreach ($rows as $field_name => $cell) {
$rows[$field_name]['data'][3] = implode(', ', $cell['data'][3]);
}
if (empty($rows)) {
$output = t('No fields have been defined for any content type yet.');
}
else {
// Sort rows by field name.
ksort($rows);
// Allow external modules alter the table headers and rows.
foreach (module_implements('field_permissions_overview_alter') as $module) {
$function = $module .'_field_permissions_overview_alter';
$function($headers, $rows);
}
$output = theme('table', array('header' => $headers, 'rows' => $rows));
}
return $output;
}

View File

@@ -0,0 +1,63 @@
(function ($) {
Drupal.behaviors.fieldPermissionsSettings = {
attach: function (context) {
// For user fields, we want the "Create own value for field X" permission
// row to only be displayed when it's meaningful (i.e., when the "Display
// on user registration form" checkbox is checked).
var $user_register_form_checkbox, $required_field_checkbox, $create_permission_row;
$user_register_form_checkbox = $('.form-item-instance-settings-user-register-form .form-checkbox', context);
if ($user_register_form_checkbox.length) {
// The "Required field" checkbox can cause the user registration checkbox
// to change, so we need it also.
$required_field_checkbox = $('.form-item-instance-required .form-checkbox', context);
if ($required_field_checkbox.length) {
// Get the permissions table row corresponding to the "Create own value
// for field X" permission. The theme_user_admin_permissions() function
// does not give us a good way to directly detect which row contains
// the create permissions, so we have rely on the fact that it will be
// the first row.
$create_permission_row = $('table#permissions tbody tr', context).filter(':first');
new Drupal.fieldPermissions.HideCreatePermission($user_register_form_checkbox, $required_field_checkbox, $create_permission_row);
}
}
}
};
Drupal.fieldPermissions = {};
/**
* Constructor for the HideCreatePermission object.
*
* This object hides and shows the "Create own value for field X" permission
* for user fields when it is appropriate to do so, depending on the state of
* the "Display on user registration form" and "Required field" checkboxes.
*/
Drupal.fieldPermissions.HideCreatePermission = function ($user_register_form_checkbox, $required_field_checkbox, $create_permission_row) {
this.$user_register_form_checkbox = $user_register_form_checkbox;
this.$create_permission_row = $create_permission_row;
// Start off by making sure the create permission row has the correct
// visibility.
this.setCreatePermissionVisibility();
// Set the row's visibility again whenever the user registration checkbox
// changes, or when the required field checkbox (which controls it) changes.
$user_register_form_checkbox.bind('change', $.proxy(this.setCreatePermissionVisibility, this));
$required_field_checkbox.bind('change', $.proxy(this.setCreatePermissionVisibility, this));
};
/**
* Set the correct visibility of the "Create own value for field X" permission.
*/
Drupal.fieldPermissions.HideCreatePermission.prototype.setCreatePermissionVisibility = function () {
// Granting permissions for "Create own value for field X" only makes sense
// when the field is configured to appear on the user registration form, so
// only show the row in the permissions table then.
if (this.$user_register_form_checkbox.is(':checked')) {
this.$create_permission_row.show();
}
else {
this.$create_permission_row.hide();
}
};
})(jQuery);

View File

@@ -0,0 +1,15 @@
name = Field Permissions
description = Set field-level permissions to create, update or view fields.
package = Fields
core = 7.x
files[] = field_permissions.module
files[] = field_permissions.admin.inc
files[] = field_permissions.test
configure = admin/reports/fields/permissions
; Information added by drupal.org packaging script on 2012-01-25
version = "7.x-1.0-beta2"
core = "7.x"
project = "field_permissions"
datestamp = "1327510549"

View File

@@ -0,0 +1,127 @@
<?php
/**
* @file
* Install, update and uninstall functions for the Field Permissions module.
*/
/**
* Implements hook_install().
*/
function field_permissions_install() {
// Set a larger weight for the module.
db_update('system')
->fields(array('weight' => 50))
->condition('name', 'field_permissions')
->execute();
}
/**
* Sets a larger weight for the module so that the Field Permissions become available.
*/
function field_permissions_update_7000(&$sandbox) {
db_update('system')
->fields(array('weight' => 50))
->condition('name', 'field_permissions')
->execute();
}
/**
* Migrate field permission settings to the new system (public/private/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);
}
}
}

View File

@@ -0,0 +1,262 @@
<?php
/**
* @file
* This is the main script for the Field Permissions module. It merely contains
* the implementation of hooks invoked by Drupal core and CCK.
* All common functions are externalized into several scripts that are included
* on demand to save memory consumption during normal site operation.
*/
/**
* Indicates that a field does not have any access control.
*/
define('FIELD_PERMISSIONS_PUBLIC', 0);
/**
* Indicates that a field is private.
*
* Private fields are never displayed, and are only editable by the author (and
* by site administrators with the 'access private fields' permission).
*/
define('FIELD_PERMISSIONS_PRIVATE', 1);
/**
* Indicates that a field has custom permissions.
*/
define('FIELD_PERMISSIONS_CUSTOM', 2);
/**
* Implements hook_help().
*/
function field_permissions_help($path, $arg) {
switch ($path) {
// Main module help for the Field Permissions module.
case 'admin/help#field_permissions':
return '<p>' . t('Set field-level permissions to edit or view CCK fields in any node, edit field during node creation, and edit or view permissions for nodes owned by the current user.') . '</p>';
// Help for the Field Permissions overview page.
case 'admin/reports/fields/permissions':
return '<p>' . t('Report and troubleshoot field permissions.') . '</p>';
}
}
/**
* Implements hook_menu().
*/
function field_permissions_menu() {
$items['admin/reports/fields/list'] = array(
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['admin/reports/fields/permissions'] = array(
'title' => 'Permissions',
'description' => 'Report and troubleshoot field permissions.',
'page callback' => 'field_permissions_overview',
'access arguments' => array('administer field permissions'),
'file' => 'field_permissions.admin.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 0,
);
return $items;
}
/**
* Implementation of hook_permission().
*/
function field_permissions_permission() {
module_load_include('inc', 'field_permissions', 'field_permissions.admin');
return _field_permissions_permission();
}
/**
* Implements of hook_form_FORM_ID_alter().
*/
function field_permissions_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
// Injects the Field Permissions settings on the Edit field tab.
form_load_include($form_state, 'inc', 'field_permissions', 'field_permissions.admin');
return _field_permissions_field_settings_form_alter($form, $form_state, $form_id);
}
/**
* Implementation of hook_field_access().
*
* @param $op
* The operation to be performed. Possible values:
* - 'edit'
* - 'view'
* @param $field
* The field on which the operation is to be performed.
* @param $entity_type
* The type of entity; e.g. 'node' or 'user'.
* @param $entity
* The entity on which the operation is to be performed.
* @param $account
* The account to check.
*
* @return
* FALSE if the operation is not allowed.
* Note when field_access() is invoked, access is granted unless one
* implementation of hook_field_access() explicitly returns FALSE.
*
* @see field_access()
*/
function field_permissions_field_access($op, $field, $entity_type, $entity, $account) {
// Ignore the request if permissions have not been enabled for this field.
if (!isset($field['field_permissions']['type']) || $field['field_permissions']['type'] == FIELD_PERMISSIONS_PUBLIC) {
return;
}
// If the field is private, then only the author (and administrators with the
// 'access private fields' permissions) can view and edit it.
elseif ($field['field_permissions']['type'] == FIELD_PERMISSIONS_PRIVATE) {
if (isset($entity)) {
return _field_permissions_entity_is_owned_by_account($entity, $account) || user_access('access private fields', $account);
}
// If the entity does not exist, we must check if there is access to any
// entity; see comments in field_permissions_empty_entity_access(). In this
// case that will always be true, since private fields are always editable
// by their authors and in theory any user account can be the author of
// some entity on the site.
else {
return TRUE;
}
}
// Otherwise, check access by permission.
elseif ($field['field_permissions']['type'] == FIELD_PERMISSIONS_CUSTOM) {
if (!isset($entity)) {
return field_permissions_empty_entity_access($op, $field['field_name'], $account);
}
elseif ($op == 'view') {
return _field_permissions_field_view_access($field['field_name'], $entity_type, $entity, $account);
}
elseif ($op == 'edit') {
return _field_permissions_field_edit_access($field['field_name'], $entity_type, $entity, $account);
}
}
}
/**
* Determines custom field permissions access when the entity is unknown.
*
* When a module calls field_access() without providing an entity (which the
* API allows it to do), it is doing so in order to check generic access to the
* field. Therefore, we should only deny access if we know that there is no
* entity anywhere on the site for which the user has access to the provided
* field.
*
* For example, Views calls field_access('view') without providing the entity,
* in order to determine if the field can be included in the query itself. So
* we only want to return FALSE if we know that there are no entities for which
* access will be granted. Later on, Views will invoke field_access('view')
* again, indirectly, when rendering the fields using field_view_field(), and
* at that point the entity will be passed along so we can do our normal checks
* on it.
*
* As another example, the FileField Sources module uses field_access('edit')
* as a menu access callback for the IMCE file browser and does not pass along
* the entity. So we must return TRUE here if there is any entity for which the
* user is allowed to edit the field (otherwise the user would not have access
* to the IMCE file browser interface when editing the fields they do have
* permission to edit).
*
* @param $op
* The operation to be performed ('view' or 'edit').
* @param $field_name
* The name of the field whose access is being checked.
* @param $account
* The user account whose access is being checked.
*
* @return
* TRUE if access should be allowed, or FALSE if it shouln't.
*/
function field_permissions_empty_entity_access($op, $field_name, $account) {
$all_permissions['view'] = array(
'view ' . $field_name,
'view own ' . $field_name,
);
$all_permissions['edit'] = array(
'create ' . $field_name,
'edit ' . $field_name,
'edit own ' . $field_name,
);
// If there's any scenario where the user might have permission to perform
// the operation on the field, return TRUE.
if (isset($all_permissions[$op])) {
foreach ($all_permissions[$op] as $permission) {
if (user_access($permission, $account)) {
return TRUE;
}
}
}
return FALSE;
}
/**
* Implementation of hook_field_access('view').
*/
function _field_permissions_field_view_access($field_name, $entity_type, $entity, $account) {
// Check if user has access to view this field in any entity.
if (user_access('view ' . $field_name, $account)) {
return TRUE;
}
// If the user has permission to view entities that they own, return TRUE if
// they own this entity or FALSE if they don't.
if (user_access('view own ' . $field_name, $account)) {
return _field_permissions_entity_is_owned_by_account($entity, $account);
}
return FALSE;
}
/**
* Implementation of hook_field_access('edit').
*/
function _field_permissions_field_edit_access($field_name, $entity_type, $entity, $account) {
// If this is a new entity, check if the user has access to edit the field on
// entity creation.
if (isset($entity->is_new)) {
// Some entities provide an "is_new" property. If that is present, respect
// whatever it's set to.
$is_new = $entity->is_new;
}
else {
// Otherwise, try to find out if the entity is new by checking its ID. Note
// that checking empty() rather than !isset() is important here, to deal
// with the case of entities that store "0" as their ID while the final
// entity is in the process of being created (user accounts are a good
// example of this).
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
$is_new = empty($id);
}
if ($is_new) {
return user_access('create ' . $field_name, $account);
}
// Check if user has access to edit this field in any entity.
if (user_access('edit ' . $field_name, $account)) {
return TRUE;
}
// If the user has permission to edit entities that they own, return TRUE if
// they own this entity or FALSE if they don't.
if (user_access('edit own ' . $field_name, $account)) {
return _field_permissions_entity_is_owned_by_account($entity, $account);
}
return FALSE;
}
/**
* Returns TRUE if an entity is owned by a user account, FALSE otherwise.
*/
function _field_permissions_entity_is_owned_by_account($entity, $account) {
// Try to get the uid of the entity owner from the entity itself. If it's not
// set (for example, if the entity type does not store a uid or does not have
// a concept of "ownership"), we need to assume that the provided user
// account does not own it.
return isset($entity->uid) && $entity->uid == $account->uid;
}

View File

@@ -0,0 +1,339 @@
<?php
/**
* @file
* Tests for field_permissions.module.
*/
/**
* Tests the Field Permissions module.
*/
class FieldPermissionsTestCase extends DrupalWebTestCase {
private $admin_user = NULL;
private $limited_user = NULL;
private $admin_rid = NULL;
private $limited_rid = NULL;
public static function getInfo() {
return array(
'name' => 'Field permissions functionality',
'description' => 'Test field permissions.',
'group' => 'Field permissions'
);
}
function setUp() {
parent::setUp('field_ui', 'field_permissions');
// Create test user.
$admin_permissions = array('access content', 'administer nodes', 'bypass node access', 'administer content types', 'administer taxonomy', 'administer permissions', 'create page content');
$this->limited_user = $this->drupalCreateUser($admin_permissions);
$all_rids = array_keys($this->limited_user->roles);
sort($all_rids);
$this->limited_rid = array_pop($all_rids);
$admin_permissions[] = 'administer field permissions';
$admin_permissions[] = 'administer users';
$this->admin_user = $this->drupalCreateUser($admin_permissions);
$all_rids = array_keys($this->admin_user->roles);
sort($all_rids);
$this->admin_rid = array_pop($all_rids);
$this->drupalLogin($this->limited_user);
}
function testPermissionsUI() {
// This depends on a page node type with a body field, standard install.
// Could alternatively extend field_ui.test classes, but would be much
// slower to run. Tradeoffs.
$field_info = array(
'admin_path' => 'admin/structure/types/manage/page/fields/body',
'machine_name' => 'body',
'add_path' => 'node/add/page',
'name' => 'Body',
'form_field' => 'body[und][0][value]',
'value' => $this->randomName(),
);
// Check if we can see the field on the entity creation form.
$this->drupalGet($field_info['add_path']);
$this->assertText($field_info['name']);
// Admin users cannot access field permissions without specifically being
// granted the permission to do so.
$this->drupalGet($field_info['admin_path']);
$this->assertNoText(t('Field visibility and permissions'));
// Switch to admin user who can see the field permissions UI.
$this->drupalGet('user/logout');
$this->drupalLogin($this->admin_user);
$this->drupalGet($field_info['admin_path']);
$this->assertText(t('Field visibility and permissions'));
// == PUBLIC FIELD =========================================================
$this->assertFieldChecked('edit-field-field-permissions-type-0');
// Although simpletest could create a node for us, we are doing this directly
// to ensure we have full control over the process. Given that we work with
// field permissions.
$this->drupalGet('user/logout');
$this->drupalLogin($this->limited_user);
$node1_values = array(
'title' => $this->randomName(),
$field_info['form_field'] => $field_info['value'],
);
$this->drupalPost($field_info['add_path'], $node1_values, t('Save'));
$this->assertText($node1_values['title']);
$this->assertText($field_info['value']);
$url = $this->getUrl();
$nid1 = preg_replace('!^.*node/(\d+)$!', '\1', $url);
// Switch to admin user to check we can see the body.
$this->drupalGet('user/logout');
$this->drupalLogin($this->admin_user);
$this->drupalGet('node/' . $nid1);
$this->assertText($node1_values['title']);
$this->assertText($field_info['value']);
// And we can edit the title and body.
$this->drupalGet('node/' . $nid1 . '/edit');
$this->assertText('Title');
$this->assertText($node1_values['title']);
$this->assertText($field_info['name']);
$this->assertText($field_info['value']);
// == PRIVATE FIELD ========================================================
// Switch to admin user to set field to private.
$edit = array(
'field[field_permissions][type]' => 1,
);
$this->drupalPost($field_info['admin_path'], $edit, t('Save settings'));
// Now we should not have access to see or edit this field.
$this->drupalGet('node/' . $nid1);
$this->assertText($node1_values['title']);
$this->assertNoText($field_info['value']);
$this->drupalGet($field_info['add_path']);
$this->assertText('Title');
$this->assertText($field_info['name']);
$this->drupalGet('node/' . $nid1 . '/edit');
$this->assertText('Title');
$this->assertNoText($field_info['name']);
$this->assertNoText($field_info['value']);
// Grant this user the Drupal core administrator role. This will give them
// the 'access private fields' permission (tested here), and it also means
// that when custom field permissions are created later on in this test,
// the admin user will automatically get those permissions granted also.
$user_admin_rid = variable_get('user_admin_role', 0);
$edit = array(
"roles[$user_admin_rid]" => TRUE,
);
$this->drupalPost('user/' . $this->admin_user->uid . '/edit', $edit, t('Save'));
// Now we should have access to see or submit or edit this field again.
$this->drupalGet('node/' . $nid1);
$this->assertText($node1_values['title']);
$this->assertText($field_info['value']);
$this->drupalGet($field_info['add_path']);
$this->assertText('Title');
$this->assertText($field_info['name']);
$this->drupalGet('node/' . $nid1 . '/edit');
$this->assertText('Title');
$this->assertText($field_info['name']);
$this->assertText($field_info['value']);
// == CUSTOM PERMISSIONS ===================================================
// Introduce body creation permission.
$edit = array(
'field[field_permissions][type]' => 2,
);
$this->drupalPost($field_info['admin_path'], $edit, t('Save settings'));
$this->drupalGet($field_info['admin_path']);
$this->assertRaw(t('Create own value for field %field', array('%field' => $field_info['name'])));
$this->assertRaw(t('Edit own value for field %field', array('%field' => $field_info['name'])));
$this->assertRaw(t("Edit anyone's value for field %field", array('%field' => $field_info['name'])));
$this->assertRaw(t('View own value for field %field', array('%field' => $field_info['name'])));
$this->assertRaw(t("View anyone's value for field %field", array('%field' => $field_info['name'])));
// See if we have that exposed on the permissions UI as well now.
$this->drupalGet('admin/people/permissions');
$this->assertText(t('Field Permissions'));
$this->assertRaw(t('Create own value for field %field', array('%field' => $field_info['name'])));
$this->assertRaw(t('Edit own value for field %field', array('%field' => $field_info['name'])));
$this->assertRaw(t("Edit anyone's value for field %field", array('%field' => $field_info['name'])));
$this->assertRaw(t('View own value for field %field', array('%field' => $field_info['name'])));
$this->assertRaw(t("View anyone's value for field %field", array('%field' => $field_info['name'])));
// == CREATE ===============================================================
// The admin user should have been automatically granted the create
// permission, but the limited user shouldn't have it yet.
$this->assertUserHasPermission($this->admin_user, 'create ' . $field_info['machine_name'], t('Admin user does have "create @field" permission.', array('@field' => $field_info['machine_name'])));
$this->assertUserDoesNotHavePermission($this->limited_user, 'create ' . $field_info['machine_name'], t('Limited user does not have "create @field" permission.', array('@field' => $field_info['machine_name'])));
// Should not see the field on the entity creation form anymore for limited_user.
$this->drupalGet('user/logout');
$this->drupalLogin($this->limited_user);
$this->drupalGet($field_info['add_path']);
$this->assertNoText($field_info['name']);
// Grant body creation permission to limited users too.
$edit = array(
$this->limited_rid .'[create '. $field_info['machine_name'] .']' => TRUE,
);
$this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
$this->assertUserHasPermission($this->admin_user, 'create ' . $field_info['machine_name'], t('Admin user does have "create @field" permission.', array('@field' => $field_info['machine_name'])));
$this->assertUserHasPermission($this->limited_user, 'create ' . $field_info['machine_name'], t('Limited user does have "create @field" permission.', array('@field' => $field_info['machine_name'])));
// Should see the field again on the entity creation form.
$this->drupalGet($field_info['add_path']);
$this->assertText($field_info['name']);
// Although simpletest could create a node for us, we are doing this directly
// to ensure we have full control over the process. Given that we work with
// field permissions.
$node2_values = array(
'title' => $this->randomName(),
$field_info['form_field'] => $field_info['value'],
);
$this->drupalPost($field_info['add_path'], $node2_values, t('Save'));
$this->assertText($node2_values['title']);
// The body will not yet be visible to this user.
$this->assertNoText($field_info['value']);
$url = $this->getUrl();
$nid2 = preg_replace('!^.*node/(\d+)$!', '\1', $url);
// Switch to admin user and prove she has access to body.
$this->drupalGet('user/logout');
$this->drupalLogin($this->admin_user);
$this->drupalGet('node/' . $nid2);
$this->assertText($node2_values['title']);
$this->assertText($field_info['value']);
// == VIEW =================================================================
// Grant body view permission to limited users too.
$edit = array(
$this->limited_rid .'[view '. $field_info['machine_name'] .']' => TRUE,
);
$this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
$this->assertUserHasPermission($this->admin_user, 'view ' . $field_info['machine_name'], t('Admin user does have "view @field" permission.', array('@field' => $field_info['machine_name'])));
$this->assertUserHasPermission($this->limited_user, 'view ' . $field_info['machine_name'], t('Limited user does have "view @field" permission.', array('@field' => $field_info['machine_name'])));
// Limited user can now see the field.
$this->drupalGet('user/logout');
$this->drupalLogin($this->limited_user);
$this->drupalGet('node/' . $nid2);
$this->assertText($node2_values['title']);
$this->assertText($field_info['value']);
// == EDIT =================================================================
// We still don't have access to edit our field.
$this->drupalGet('node/' . $nid2 . '/edit');
$this->assertNoText($field_info['value']);
// Switch to admin user to configure edit permissions.
$this->drupalGet('user/logout');
$this->drupalLogin($this->admin_user);
// Ensure the editing screen now has the body.
$this->drupalGet('node/' . $nid2 . '/edit');
$this->assertText($field_info['value']);
// Grant body editing permission for the limited role.
$edit = array(
$this->limited_rid .'[edit '. $field_info['machine_name'] .']' => TRUE,
);
$this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
$this->assertUserHasPermission($this->admin_user, 'edit ' . $field_info['machine_name'], t('Admin user does have "edit @field" permission.', array('@field' => $field_info['machine_name'])));
$this->assertUserHasPermission($this->limited_user, 'edit ' . $field_info['machine_name'], t('Limited user does have "edit @field" permission.', array('@field' => $field_info['machine_name'])));
// Ensure the editing screen still has the body.
$this->drupalGet('node/' . $nid2 . '/edit');
$this->assertText($field_info['value']);
// Switch to limited user to check that we can edit body now.
$this->drupalGet('user/logout');
$this->drupalLogin($this->limited_user);
$this->drupalGet('node/' . $nid2 . '/edit');
$this->assertText($field_info['value']);
}
function testUserFields() {
// Create a field attached to users and make it appear on the user
// registration form with (default) custom permissions.
$this->drupalLogin($this->admin_user);
$label = 'Field attached to users';
$edit = array(
'fields[_add_new_field][label]' => $label,
'fields[_add_new_field][field_name]' => 'attached_to_users',
'fields[_add_new_field][type]' => 'text',
'fields[_add_new_field][widget_type]' => 'text_textfield',
);
$this->drupalPost('admin/config/people/accounts/fields', $edit, t('Save'));
$this->drupalPost(NULL, array(), t('Save field settings'));
$edit = array(
'field[field_permissions][type]' => 2,
'instance[settings][user_register_form]' => TRUE,
);
$this->drupalPost(NULL, $edit, t('Save settings'));
// Log out, go to the registration form and make sure the field appears
// there for anonymous users.
$this->drupalLogout();
$this->drupalGet('user/register');
$this->assertText($label);
// Log in and make sure the user does not have access to edit the field
// (i.e., there are only default permissions to create it).
$this->drupalLogin($this->limited_user);
$this->drupalGet('user/' . $this->limited_user->uid . '/edit');
$this->assertResponse(200);
$this->assertNoText($label);
}
/**
* Asserts that a user account has a permission.
*/
protected function assertUserHasPermission($account, $permission, $message) {
$this->_assertUserPermissionState($account, $permission, $message, TRUE);
}
/**
* Asserts that a user account does not have a permission.
*/
protected function assertUserDoesNotHavePermission($account, $permission, $message) {
$this->_assertUserPermissionState($account, $permission, $message, FALSE);
}
/**
* Helper function for asserting user permissions.
*/
protected function _assertUserPermissionState($account, $permission, $message, $should_have_permission) {
// We need to clear static caches since the tests may have recently changed
// the permissions via the UI (i.e., in a different thread than the one
// running the tests).
drupal_static_reset('user_access');
drupal_static_reset('user_role_permissions');
// Load the full user account, since we may have been provided an out of
// date pseudo-account of the kind SimpleTest uses (e.g. as returned by
// drupalCreateUser()), rather than an up to date object that actually
// contains the full list of roles this user has been assigned.
$full_account = user_load($account->uid);
// Now check the permission.
$has_permission = user_access($permission, $full_account);
if ($should_have_permission) {
$this->assertTrue($has_permission, $message);
}
else {
$this->assertFalse($has_permission, $message);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B