FINAL suepr merge step : added all modules to this super repos
This commit is contained in:
22
sites/all/modules/contrib/admin/content_access/CHANGELOG.txt
Normal file
22
sites/all/modules/contrib/admin/content_access/CHANGELOG.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
Content Access 7.x-1.2-beta1, 2011-07-24
|
||||
--------------------------------------
|
||||
#1058526 by BenK, good_man: Rules 2.x integration.
|
||||
#572812 by NikLP, good_man: Add content type to permission title.
|
||||
#1135466 by Firewolf, videographics, good_man: Renaming a content type results
|
||||
in notices.
|
||||
#1144510 by good_man: Fix roles selection in test case.
|
||||
#1110860 by FiNeX, eosrei, good_man: Content access rules integration -
|
||||
missing function.
|
||||
#1159402 by FiNeX, dcmouyard, jjs, good_man: Wrong operations on rules
|
||||
integration.
|
||||
#1057400 by xaverx, dooug, jhayzhon, cnolle, Firewolf, Bitnetix, maciej.zgadzaj,
|
||||
karilu_ec, ChoY, BenK, good_man: Taxonomy access.
|
||||
#1097248 by ordermind, Itangalo, good_man: PDOException error 1062 when using
|
||||
rules on create node.
|
||||
#1209004 by Itangalo, good_man: "Reset content permissions" action doesn't go
|
||||
all the way.
|
||||
#1147526 by tmm360, good_man, Akaoni, danielb, Crusher, mithman, BenK, fago:
|
||||
Unpublished nodes displayed to anonymous users.
|
||||
#1115794 by rorydflynn, Waldknoblauch, aocoder, good_man, SNaKeMe, cgross,
|
||||
commanderflash, bryrock, enrikito, BenK, karilu_ec: Conflict with views
|
||||
module.
|
339
sites/all/modules/contrib/admin/content_access/LICENSE.txt
Normal file
339
sites/all/modules/contrib/admin/content_access/LICENSE.txt
Normal 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.
|
65
sites/all/modules/contrib/admin/content_access/README.txt
Normal file
65
sites/all/modules/contrib/admin/content_access/README.txt
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
Content Access Module
|
||||
-----------------------
|
||||
by Wolfgang Ziegler, nuppla@zites.net
|
||||
|
||||
Yet another node access module.
|
||||
This module allows you to manage permissions for content types by role. It allows you to specifiy
|
||||
custom view, view own, edit, edit own, delete and delete own permissions for each content type.
|
||||
Optionally you can enable per content access settings, so you can customize the access for each
|
||||
content node.
|
||||
|
||||
In particular
|
||||
* it comes with sensible defaults, so you need not configure anything and everything stays working
|
||||
* it is as flexible as you want. It can work with per content type settings, per content node settings
|
||||
as well as with flexible Access Control Lists (with the help of the ACL module).
|
||||
* it trys to reuse existing functionality instead of reimplementing it. So one can install the ACL
|
||||
module and set per user access control settings per content node.
|
||||
Furthermore the module provides conditions and actions for the rules module, which allows one
|
||||
to configure even rule-based access permissions.
|
||||
* it optimizes the written content node grants, so that only the really necessary grants are written.
|
||||
This is important for the performance of your site.
|
||||
* it takes access control as important as it is. E.g. the module has a bunch of simpletests to ensure
|
||||
everything is working right.
|
||||
* it respects and makes use of drupal's built in permissions as far as possible. Which means the
|
||||
access control tab provided by this module takes them into account and provides you a good overview
|
||||
about the really applied access control settings. [1]
|
||||
|
||||
|
||||
So the module is simple to use, but can be configured to provide really fine-grained permissions!
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
* Copy the content access module's directory to your modules directory and activate the module.
|
||||
* Optionally download and install the ACL module too.
|
||||
* Edit a content type at admin/content/types. There will be a new tab "Access Control".
|
||||
|
||||
|
||||
ACL Module
|
||||
-----------
|
||||
You can find the ACL module at http://drupal.org/project/acl. To make use of Access Control Lists
|
||||
you'll need to enable per content node access control settings for a content type. At the access
|
||||
control tab of such a content node you are able to grant view, edit or delete permission for specific
|
||||
users.
|
||||
|
||||
|
||||
Running multiple node access modules on a site (Advanced!)
|
||||
-----------------------------------------------------------
|
||||
A drupal node access module can only grant access to content nodes, but not deny it. So if you
|
||||
are using multiple node access modules, access will be granted to a node as soon as one of the
|
||||
module grants access to it.
|
||||
However you can influence the behaviour by changing the priority of the content access module as
|
||||
drupal applies *only* the grants with the highest priority. So if content access has the highest
|
||||
priority *alone*, only its grants will be applied.
|
||||
|
||||
By default node access modules use priority 0.
|
||||
|
||||
|
||||
|
||||
Footnotes
|
||||
----------
|
||||
|
||||
[1] Note that this overview can't take other modules into account, which might also alter node access.
|
||||
If you have multiple modules installed that alter node access, read the paragraph about "Running
|
||||
multiple node access modules on a site".
|
24
sites/all/modules/contrib/admin/content_access/UPGRADE.txt
Normal file
24
sites/all/modules/contrib/admin/content_access/UPGRADE.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
Upgrade from 5.x
|
||||
----------------
|
||||
|
||||
You can easily upgrade from drupal 5 installations. After upgrading your drupal installation
|
||||
just install the latest module and run update.php - it will automatically run the upgrade routine
|
||||
which is update 6001.
|
||||
|
||||
After that the content access permissions for your site needs to be rebuilt. Just go to your
|
||||
site and follow the instructions.
|
||||
|
||||
|
||||
Notes for workflow-ng users
|
||||
----------------------------
|
||||
The workflow-ng integration has been properly upgraded to its 6.x version, the rules module.
|
||||
However it has been a bit refactored: The 'Set content permissions' action has been removed in
|
||||
favor of the 'Grant content permissions by role' and 'Revoke content permissions by role' as
|
||||
this gives us more flexibility.
|
||||
|
||||
So the automatic upgrade of your configured rules converts the 'Set content permissions' action
|
||||
to an 'Grant content permissions by role' action. If this doesn't fit, you'll have to edit it
|
||||
manually.
|
||||
|
||||
All other conditions and actions have their equivalent in rules and will be automatically converted.
|
@@ -0,0 +1,347 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file Content access administration UI.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Specifies the threshold until we try to mass update node grants immediately.
|
||||
*/
|
||||
define('CONTENT_ACCESS_MASS_UPDATE_THRESHOLD', 1000);
|
||||
|
||||
/**
|
||||
* Per node settings page.
|
||||
*/
|
||||
function content_access_page($form, &$form_state, $node) {
|
||||
drupal_set_title(t('Access control for @title', array('@title' => $node->title)));
|
||||
|
||||
foreach (_content_access_get_operations() as $op => $label) {
|
||||
$defaults[$op] = content_access_per_node_setting($op, $node);
|
||||
}
|
||||
|
||||
// Get roles form
|
||||
content_access_role_based_form($form, $defaults, $node->type);
|
||||
|
||||
// Add an after_build handler that disables checkboxes, which are enforced by permissions.
|
||||
$form['per_role']['#after_build'] = array('content_access_force_permissions');
|
||||
|
||||
// ACL form
|
||||
if (module_exists('acl')) {
|
||||
// This is disabled when there is no node passed.
|
||||
$form['acl'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('User access control lists'),
|
||||
'#description' => t('These settings allow you to grant access to specific users.'),
|
||||
'#collapsible' => TRUE,
|
||||
'#tree' => TRUE,
|
||||
);
|
||||
|
||||
foreach (array('view', 'update', 'delete') as $op) {
|
||||
$acl_id = content_access_get_acl_id($node, $op);
|
||||
acl_node_add_acl($node->nid, $acl_id, (int) ($op == 'view'), (int) ($op == 'update'), (int) ($op == 'delete'), content_access_get_settings('priority', $node->type));
|
||||
|
||||
$form['acl'][$op] = acl_edit_form($form_state, $acl_id, t('Grant !op access', array('!op' => $op)));
|
||||
$form['acl'][$op]['#collapsed'] = !isset($_POST['acl_' . $acl_id]) && !unserialize($form['acl'][$op]['user_list']['#default_value']);
|
||||
}
|
||||
}
|
||||
|
||||
$form_state['node'] = $node;
|
||||
|
||||
$form['reset'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Reset to defaults'),
|
||||
'#weight' => 10,
|
||||
'#submit' => array('content_access_page_reset'),
|
||||
'#access' => count(content_access_get_per_node_settings($node)) > 0,
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
'#weight' => 10,
|
||||
);
|
||||
|
||||
// @todo not true anymore?
|
||||
// http://drupal.org/update/modules/6/7#hook_node_access_records
|
||||
if (!$node->status) {
|
||||
drupal_set_message(t("Warning: Your content is not published, so this settings are not taken into account as long as the content remains unpublished."), 'error');
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit callback for content_access_page().
|
||||
*/
|
||||
function content_access_page_submit($form, &$form_state) {
|
||||
$settings = array();
|
||||
$node = $form_state['node'];
|
||||
|
||||
foreach (_content_access_get_operations() as $op => $label) {
|
||||
// Set the settings so that further calls will return this settings.
|
||||
$settings[$op] = array_keys(array_filter($form_state['values'][$op]));
|
||||
}
|
||||
|
||||
// Save per-node settings.
|
||||
content_access_save_per_node_settings($node, $settings);
|
||||
|
||||
if (module_exists('acl')) {
|
||||
foreach (array('view', 'update', 'delete') as $op) {
|
||||
acl_save_form($form_state['values']['acl'][$op]);
|
||||
module_invoke_all('user_acl', $settings);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply new settings.
|
||||
node_access_acquire_grants($node);
|
||||
|
||||
module_invoke_all('per_node', $settings);
|
||||
|
||||
drupal_set_message(t('Your changes have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit callback for reset on content_access_page().
|
||||
*/
|
||||
function content_access_page_reset($form, &$form_state) {
|
||||
content_access_delete_per_node_settings($form_state['node']);
|
||||
node_access_acquire_grants($form_state['node']);
|
||||
|
||||
drupal_set_message(t('The permissions have been reseted to the content type defaults.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Per content type settings form.
|
||||
*/
|
||||
function content_access_admin_settings($form, &$form_state, $content_type) {
|
||||
$type = $content_type->type;
|
||||
|
||||
$form_state['type'] = $type;
|
||||
|
||||
// Add role based per content type settings
|
||||
$defaults = array();
|
||||
foreach (_content_access_get_operations() as $op => $label) {
|
||||
$defaults[$op] = content_access_get_settings($op, $type);
|
||||
}
|
||||
content_access_role_based_form($form, $defaults, $type);
|
||||
|
||||
// Per node:
|
||||
$form['node'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Per content node access control settings'),
|
||||
'#collapsible' => TRUE,
|
||||
'#description' => t('Optionally you can enable per content node access control settings. If enabled, a new tab for the content access settings appears when viewing content. You have to configure permission to access these settings at the !permissions page.', array('!permissions' => l(t('permissions'), 'admin/people/permissions'))),
|
||||
);
|
||||
$form['node']['per_node'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Enable per content node access control settings'),
|
||||
'#default_value' => content_access_get_settings('per_node', $type),
|
||||
);
|
||||
|
||||
$form['advanced'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Advanced'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
);
|
||||
$form['advanced']['priority'] = array(
|
||||
'#type' => 'weight',
|
||||
'#title' => t('Give content node grants priority'),
|
||||
'#default_value' => content_access_get_settings('priority', $type),
|
||||
'#description' => t('If you are only using this access control module, you can safely ignore this. If you are using multiple access control modules you can adjust the priority of this module.'),
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
'#weight' => 10,
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for per content type settings form.
|
||||
*/
|
||||
function content_access_admin_settings_submit($form, &$form_state) {
|
||||
$roles_permissions = user_role_permissions(user_roles());
|
||||
$permissions = user_permission_get_modules();
|
||||
$type = $form_state['type'];
|
||||
|
||||
// Remove disabled modules permissions, so they can't raise exception
|
||||
// in content_access_save_permissions()
|
||||
foreach ($roles_permissions as $rid => $role_permissions) {
|
||||
foreach ($role_permissions as $permission => $value) {
|
||||
if (!array_key_exists($permission, $permissions)) {
|
||||
unset($roles_permissions[$rid][$permission]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array('update', 'update_own', 'delete', 'delete_own') as $op) {
|
||||
foreach ($form_state['values'][$op] as $rid => $value) {
|
||||
$permission = content_access_get_permission_by_op($op, $form_state['type']);
|
||||
if ($value) {
|
||||
$roles_permissions[$rid][$permission] = TRUE;
|
||||
}
|
||||
else {
|
||||
$roles_permissions[$rid][$permission] = FALSE;
|
||||
}
|
||||
}
|
||||
// Don't save the setting, so its default value (get permission) is applied
|
||||
// always.
|
||||
unset($form_state['values'][$op]);
|
||||
}
|
||||
content_access_save_permissions($roles_permissions);
|
||||
|
||||
// Update content access settings
|
||||
$settings = content_access_get_settings('all', $type);
|
||||
foreach (content_access_available_settings() as $setting) {
|
||||
if (isset($form_state['values'][$setting])) {
|
||||
$settings[$setting] = is_array($form_state['values'][$setting]) ? array_keys(array_filter($form_state['values'][$setting])) : $form_state['values'][$setting];
|
||||
}
|
||||
}
|
||||
content_access_set_settings($settings, $type);
|
||||
|
||||
// Mass update the nodes, but only if necessary.
|
||||
if (content_access_get_settings('per_node', $type) ||
|
||||
content_access_get_settings('view', $type) != $form['per_role']['view']['#default_value'] ||
|
||||
content_access_get_settings('view_own', $type) != $form['per_role']['view_own']['#default_value'] ||
|
||||
content_access_get_settings('priority', $type) != $form['advanced']['priority']['#default_value'] ||
|
||||
content_access_get_settings('per_node', $type) != $form['node']['per_node']['#default_value']
|
||||
) {
|
||||
|
||||
// If per node has been disabled and we use the ACL integration, we have to remove possible ACLs now.
|
||||
if (!content_access_get_settings('per_node', $type) && $form['node']['per_node']['#default_value'] && module_exists('acl')) {
|
||||
_content_access_remove_acls($type);
|
||||
}
|
||||
|
||||
if (content_access_mass_update(array($type))) {
|
||||
drupal_set_message(t('Permissions have been successfully rebuilt for the content type @types.', array('@types' => node_type_get_name($type))));
|
||||
}
|
||||
}
|
||||
|
||||
drupal_set_message(t('Your changes have been saved.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass updates node access records for nodes of the given types.
|
||||
* @param $types
|
||||
* An array of content type names.
|
||||
* @return
|
||||
* Whether the operation has been processed successfully (TRUE) or postponed (FALSE).
|
||||
*/
|
||||
function content_access_mass_update($types) {
|
||||
$q = db_select('node', 'n')
|
||||
->fields('n', array('nid'))
|
||||
->condition('n.type', $types, 'IN');
|
||||
|
||||
$count = $q->countQuery()->execute()->fetchField();
|
||||
|
||||
node_access_needs_rebuild(TRUE);
|
||||
|
||||
// If there not too much nodes affected, try to do it.
|
||||
if ($count <= CONTENT_ACCESS_MASS_UPDATE_THRESHOLD) {
|
||||
$records = $q->execute();
|
||||
foreach ($records as $node) {
|
||||
node_access_acquire_grants(node_load($node->nid));
|
||||
}
|
||||
|
||||
cache_clear_all();
|
||||
node_access_needs_rebuild(FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the given permissions by role to the database.
|
||||
*/
|
||||
function content_access_save_permissions($roles_permissions) {
|
||||
foreach ($roles_permissions as $rid => $permissions) {
|
||||
user_role_change_permissions($rid, $permissions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the role based permission form for the given defaults.
|
||||
*
|
||||
* @param $defaults
|
||||
* Array of defaults for all operations.
|
||||
*/
|
||||
function content_access_role_based_form(&$form, $defaults = array(), $type = NULL) {
|
||||
$form['per_role'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Role based access control settings'),
|
||||
'#collapsible' => TRUE,
|
||||
'#description' => t('Note that users need at least the %access_content permission to be able to deal in any way with content.', array('%access_content' => t('access content'))) .
|
||||
' ' . t('Furthermore note that content which is not @published is treated in a different way by drupal: It can be viewed only by its author or users with the %administer_nodes permission.', array('@published' => t('published'), '%administer_nodes' => t('administer nodes'))),
|
||||
);
|
||||
|
||||
$operations = _content_access_get_operations($type);
|
||||
$roles = array_map('filter_xss_admin', user_roles());
|
||||
foreach ($operations as $op => $label) {
|
||||
// Make sure defaults are set properly
|
||||
$defaults += array($op => array());
|
||||
|
||||
$form['per_role'][$op] = array('#type' => 'checkboxes',
|
||||
'#prefix' => '<div class="content_access-div">',
|
||||
'#suffix' => '</div>',
|
||||
'#options' => $roles,
|
||||
'#title' => $label,
|
||||
'#default_value' => $defaults[$op],
|
||||
'#process' => array('form_process_checkboxes', 'content_access_disable_checkboxes'),
|
||||
);
|
||||
}
|
||||
|
||||
$form['per_role']['clearer'] = array(
|
||||
'#value' => '<br clear="all" />',
|
||||
);
|
||||
|
||||
drupal_add_css(drupal_get_path('module', 'content_access') . '/content_access.css');
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formapi #after_build callback, that disables checkboxes for roles without access to content.
|
||||
*/
|
||||
function content_access_force_permissions($element, &$form_state) {
|
||||
foreach (array('update', 'update_own', 'delete', 'delete_own') as $op) {
|
||||
foreach (content_access_get_settings($op, $form_state['node']->type) as $rid) {
|
||||
$element[$op][$rid]['#disabled'] = TRUE;
|
||||
$element[$op][$rid]['#attributes']['disabled'] = 'disabled';
|
||||
$element[$op][$rid]['#value'] = TRUE;
|
||||
$element[$op][$rid]['#checked'] = TRUE;
|
||||
$element[$op][$rid]['#prefix'] = '<span' . drupal_attributes(array('title' => t("Permission is granted due to the content type's access control settings."))) . '>';
|
||||
$element[$op][$rid]['#suffix'] = "</span>";
|
||||
}
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit callback for the user permissions form.
|
||||
* Trigger changes to node permissions to rebuild our grants.
|
||||
*/
|
||||
function content_access_user_admin_perm_submit($form, $form_state) {
|
||||
// Check for each content type, which has per node access activated
|
||||
// whether permissions have been changed.
|
||||
$types = array();
|
||||
foreach (array_filter(content_access_get_settings('per_node')) as $type => $value) {
|
||||
foreach (_content_access_get_node_permissions($type) as $perm) {
|
||||
foreach (user_roles() as $rid => $role) {
|
||||
if (isset($form_state['values'][$rid]) && in_array($perm, $form['checkboxes'][$rid]['#default_value']) != in_array($perm, $form_state['values'][$rid])) {
|
||||
//permission changed!
|
||||
$types[$type] = node_get_types('name', $type);
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($types && content_access_mass_update(array_keys($types))) {
|
||||
drupal_set_message(format_plural(count($types),
|
||||
'Permissions have been successfully rebuilt for the content type @types.',
|
||||
'Permissions have been successfully rebuilt for the content types @types.',
|
||||
array('@types' => implode(', ', $types))
|
||||
));
|
||||
}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
.content_access-div {
|
||||
width: 25%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
float: left;
|
||||
overflow: hide;
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
name = Content Access
|
||||
description = Provides flexible content access control.
|
||||
core = 7.x
|
||||
package = Access control
|
||||
files[] = content_access.rules.inc
|
||||
files[] = tests/content_access.test
|
||||
files[] = tests/content_access_acl.test
|
||||
; Information added by drupal.org packaging script on 2013-01-22
|
||||
version = "7.x-1.2-beta1+10-dev"
|
||||
core = "7.x"
|
||||
project = "content_access"
|
||||
datestamp = "1358858714"
|
||||
|
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Content access install file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function content_access_uninstall() {
|
||||
foreach (node_type_get_types() as $type_name => $type) {
|
||||
variable_del('content_access_' . $type_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function content_access_schema() {
|
||||
$schema['content_access'] = array(
|
||||
'fields' => array(
|
||||
'nid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0
|
||||
),
|
||||
'settings' => array(
|
||||
'type' => 'text',
|
||||
'not null' => FALSE,
|
||||
'size' => 'medium'
|
||||
),
|
||||
),
|
||||
'primary key' => array('nid')
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert content type settings to a new features-friendly storage format.
|
||||
*/
|
||||
function content_access_update_7101() {
|
||||
$settings = variable_get('content_access_settings', array());
|
||||
foreach ($settings as $setting => $data) {
|
||||
foreach ($data as $type_name => $value) {
|
||||
$settings_new[$type_name][$setting] = $value;
|
||||
}
|
||||
}
|
||||
foreach ($settings_new as $type_name => $data) {
|
||||
variable_set('content_access_' . $type_name, $data);
|
||||
}
|
||||
variable_del('content_access_settings');
|
||||
}
|
@@ -0,0 +1,640 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file Content access module file.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function content_access_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#content_access':
|
||||
$output = '<h3>' . t('About') . '</h3>';
|
||||
$output .= '<p>' . t('Content Access module provides flexible way to control how and who should read or control your site content. Content Access can define custom access control rules for content types and even for every piece of content.') . '</p>';
|
||||
$output .= '<h3>' . t('Uses') . '</h3>';
|
||||
$output .= '<dl>';
|
||||
$output .= '<dt>' . t('Default and custom settings') . '</dt>';
|
||||
$output .= '<dd>' . t("Each <a href='@content-type'>content type</a> can have its own default content access settings configured as: <em>View any content</em> to allow anyone to view content from this content type, <em>View own content</em> to allow only content creators to see their own content, <em>Edit any content</em> to allow anyone to edit content from this content type, <em>Edit own content</em> to allow only content creators to edit their own content, <em>Delete any content</em> to allow anyone to delete content from this content type, <em>Delete own content </em> to allow content creators to delete their own content. This default settings for each content type can be further customized per every piece of content per user if you have <a href='@acl'>ACL</a> module enabled.", array('@content-type' => url('admin/structure/types'), '@acl' => 'http://drupal.org/project/acl/')) . '</dd>';
|
||||
$output .= '</dl>';
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_admin_paths().
|
||||
*/
|
||||
function content_access_admin_paths() {
|
||||
$paths = array(
|
||||
'node/*/access' => TRUE,
|
||||
);
|
||||
return $paths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function content_access_menu() {
|
||||
$items = array();
|
||||
|
||||
$items['node/%node/access'] = array(
|
||||
'title' => 'Access control',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('content_access_page', 1),
|
||||
'access callback' => 'content_access_node_page_access',
|
||||
'access arguments' => array(1),
|
||||
'file' => 'content_access.admin.inc',
|
||||
'theme callback' => '_node_custom_theme',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'weight' => 3,
|
||||
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
|
||||
);
|
||||
|
||||
$items['admin/structure/types/manage/%node_type/access'] = array(
|
||||
'title' => 'Access control',
|
||||
'description' => 'Configure content access control.',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('content_access_admin_settings', 4),
|
||||
'access callback' => 'content_access_admin_settings_access',
|
||||
'access arguments' => array(),
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'content_access.admin.inc',
|
||||
'theme callback' => '_node_custom_theme',
|
||||
'weight' => 1,
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_perm().
|
||||
*/
|
||||
function content_access_permission() {
|
||||
return array(
|
||||
'grant content access' => array(
|
||||
'title' => t('Grant content access'),
|
||||
'description' => t('View and modify content access for any nodes'),
|
||||
),
|
||||
'grant own content access' => array(
|
||||
'title' => t('Grant own content access'),
|
||||
'description' => t('View and modify content access for own nodes'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get access tab page for the viewed node.
|
||||
*/
|
||||
function content_access_node_page_access($node) {
|
||||
global $user;
|
||||
return content_access_get_settings('per_node', $node->type) && user_access('grant content access') ||
|
||||
content_access_get_settings('per_node', $node->type) && (user_access('grant own content access') && ($user->uid == $node->uid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Content access settings for content type.
|
||||
*/
|
||||
function content_access_admin_settings_access() {
|
||||
return user_access('administer nodes') && user_access('administer content types');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_grants().
|
||||
*/
|
||||
function content_access_node_grants($account, $op) {
|
||||
return array(
|
||||
'content_access_author' => array($account->uid),
|
||||
'content_access_rid' => array_keys($account->roles),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_access_records().
|
||||
*/
|
||||
function content_access_node_access_records($node) {
|
||||
if (content_access_disabling() || !$node->status) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply per node settings if necessary.
|
||||
if (content_access_get_settings('per_node', $node->type)) {
|
||||
$grants = array();
|
||||
foreach (array('view', 'update', 'delete') as $op) {
|
||||
foreach (content_access_get_rids_per_node_op($op, $node) as $rid) {
|
||||
$grants[$rid]['grant_' . $op] = 1;
|
||||
}
|
||||
}
|
||||
foreach ($grants as $rid => $grant) {
|
||||
$grants[$rid] = content_access_proccess_grant($grant, $rid, $node);
|
||||
}
|
||||
|
||||
// Care for the author grant.
|
||||
$grant = array();
|
||||
foreach (array('view', 'update', 'delete') as $op) {
|
||||
// Get all roles that have access to use $op on this node.
|
||||
$any_roles = drupal_map_assoc(content_access_per_node_setting($op, $node));
|
||||
$any_roles = $any_roles ? $any_roles : array();
|
||||
$any_roles += ($op != 'view') ? content_access_get_settings($op, $node->type) : array();
|
||||
$grant['grant_' . $op] = content_access_own_op($node, $any_roles, content_access_get_rids_per_node_op($op . '_own', $node));
|
||||
}
|
||||
|
||||
if (array_filter($grant)) {
|
||||
$grant['realm'] = 'content_access_author';
|
||||
$grants[] = content_access_proccess_grant($grant, $node->uid, $node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Apply the content type defaults.
|
||||
$grants = content_access_get_type_grant($node);
|
||||
}
|
||||
|
||||
if (empty($grants)) {
|
||||
// This means we grant no access.
|
||||
$grants[] = content_access_proccess_grant(array(), 0, $node);
|
||||
}
|
||||
else {
|
||||
content_access_optimize_grants($grants, $node);
|
||||
}
|
||||
|
||||
return $grants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_delete().
|
||||
*/
|
||||
function content_access_node_delete($node) {
|
||||
db_delete('content_access')
|
||||
->condition('nid', $node->nid)
|
||||
->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the ACL module.
|
||||
*/
|
||||
function content_access_enabled() {
|
||||
return !content_access_disabling();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_disable().
|
||||
*/
|
||||
function content_access_disable() {
|
||||
content_access_disabling(TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remembers if we have disabled access.
|
||||
*/
|
||||
function content_access_disabling($set = NULL) {
|
||||
static $disabling = FALSE;
|
||||
|
||||
if (isset($set)) {
|
||||
$disabling = $set;
|
||||
}
|
||||
return $disabling;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return content_access' settings.
|
||||
*
|
||||
* @param $setting
|
||||
* One of the content_access_available_settings(), e.g. 'view' or 'per_node'.
|
||||
* If 'all' is passed, all available settings are returned.
|
||||
* @param $type_name
|
||||
* The name of the content type to return settings for.
|
||||
*
|
||||
* @return
|
||||
* The value of the given setting or an array of all settings.
|
||||
*/
|
||||
function content_access_get_settings($setting, $type_name) {
|
||||
$settings = variable_get('content_access_' . $type_name, array());
|
||||
$settings += content_access_get_setting_defaults($type_name);
|
||||
if ($setting == 'all') {
|
||||
return $settings;
|
||||
}
|
||||
return isset($settings[$setting]) ? $settings[$setting] : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save content_access settings of a content type.
|
||||
*/
|
||||
function content_access_set_settings($settings, $type_name) {
|
||||
// Do not store default values so we do not have to care about synching our
|
||||
// settings with the permissions.
|
||||
foreach (content_access_get_setting_defaults($type_name) as $setting => $default_value) {
|
||||
if (isset($settings[$setting]) && $settings[$setting] == $default_value) {
|
||||
unset($settings[$setting]);
|
||||
}
|
||||
}
|
||||
variable_set('content_access_' . $type_name, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array containing all available content_access settings.
|
||||
*/
|
||||
function content_access_available_settings() {
|
||||
return array('view', 'update', 'delete', 'view_own', 'update_own', 'delete_own', 'per_node', 'priority');
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines default values for settings.
|
||||
*/
|
||||
function content_access_get_setting_defaults($type) {
|
||||
$defaults = array();
|
||||
$defaults['view'] = $defaults['view_own'] = array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID);
|
||||
foreach (array('update', 'delete') as $op) {
|
||||
$defaults[$op] = content_access_get_permission_access(content_access_get_permission_by_op($op, $type));
|
||||
$defaults[$op . '_own'] = content_access_get_permission_access(content_access_get_permission_by_op($op . '_own', $type));
|
||||
}
|
||||
$defaults['priority'] = 0;
|
||||
$defaults['per_node'] = FALSE;
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of role ids that contain the given permission.
|
||||
*/
|
||||
function content_access_get_permission_access($perm, $reset = FALSE) {
|
||||
$roles = &drupal_static(__FUNCTION__, array());
|
||||
|
||||
if ($reset) {
|
||||
$roles = array();
|
||||
}
|
||||
if (!isset($roles[$perm]) && $perm) {
|
||||
$roles[$perm] = array_keys(user_roles(0, $perm));
|
||||
}
|
||||
return isset($roles[$perm]) ? $roles[$perm] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of a permission for the given operation, if there is a suiting one.
|
||||
*/
|
||||
function content_access_get_permission_by_op($op, $type) {
|
||||
switch ($op) {
|
||||
default:
|
||||
return FALSE;
|
||||
case 'update':
|
||||
return 'edit any ' . $type . ' content';
|
||||
case 'update_own':
|
||||
return 'edit own ' . $type . ' content';
|
||||
case 'delete':
|
||||
return 'delete any ' . $type . ' content';
|
||||
case 'delete_own':
|
||||
return 'delete own ' . $type . ' content';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default grants for a given node type.
|
||||
*/
|
||||
function content_access_get_type_grant($node) {
|
||||
// Cache per type default grants in a static array
|
||||
static $defaults = array();
|
||||
|
||||
if (!isset($defaults[$node->type])) {
|
||||
$grants = array();
|
||||
|
||||
// Only process the 'view' op as node_access() will take care of edit and delete
|
||||
foreach (content_access_get_settings('view', $node->type) as $rid) {
|
||||
$grants[$rid]['grant_view'] = 1;
|
||||
$grants[$rid] = content_access_proccess_grant($grants[$rid], $rid, $node);
|
||||
}
|
||||
$defaults[$node->type] = $grants;
|
||||
}
|
||||
|
||||
// Care for the author grant.
|
||||
$grant = $grants = array();
|
||||
$grant['grant_view'] = content_access_own_op($node, content_access_get_settings('view', $node->type), content_access_get_settings('view_own', $node->type));
|
||||
if ($grant['grant_view']) {
|
||||
$grant['realm'] = 'content_access_author';
|
||||
$grants = array('author' => content_access_proccess_grant($grant, $node->uid, $node));
|
||||
}
|
||||
|
||||
return $defaults[$node->type] + $grants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a grant, which means add priority, realm and other properties.
|
||||
*/
|
||||
function content_access_proccess_grant($grant, $gid, $node) {
|
||||
$grant += array('grant_view' => 0, 'grant_update' => 0, 'grant_delete' => 0, 'realm' => 'content_access_rid');
|
||||
$grant['gid'] = $gid;
|
||||
$grant['priority'] = content_access_get_settings('priority', $node->type);
|
||||
return $grant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the grant for the node author and the given allowed roles of a operation.
|
||||
*
|
||||
* @param $any_roles
|
||||
* The roles with which anybody has access (not optimized!)
|
||||
* @param $own_roles
|
||||
* The roles with which only the author has acess (optimized!)
|
||||
*/
|
||||
function content_access_own_op($node, $any_roles, $own_roles) {
|
||||
static $roles = array();
|
||||
|
||||
if (!isset($roles[$node->uid])) {
|
||||
$roles[$node->uid] = $node->uid ? array(DRUPAL_AUTHENTICATED_RID) : array(DRUPAL_ANONYMOUS_RID);
|
||||
$result = db_query('SELECT rid FROM {users_roles} WHERE uid = :uid', array(':uid' => $node->uid));
|
||||
|
||||
foreach ($result as $role) {
|
||||
$roles[$node->uid][] = $role->rid;
|
||||
}
|
||||
}
|
||||
if (array_intersect($roles[$node->uid], $any_roles)) {
|
||||
// If there is access due to "any permissions" there is no need to at an author grant.
|
||||
return 0;
|
||||
}
|
||||
return array_intersect($roles[$node->uid], $own_roles) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns optimized role ids for the given operation and node to
|
||||
* grant access for.
|
||||
*
|
||||
* If to a role access is granted by permissions, it's not necessary
|
||||
* to write a grant for it. So it won't be returned.
|
||||
*
|
||||
* @param $op
|
||||
* One of the supported operations.
|
||||
* @param $node
|
||||
* The node object.
|
||||
*/
|
||||
function content_access_get_rids_per_node_op($op, $node) {
|
||||
$rids = content_access_per_node_setting($op, $node);
|
||||
|
||||
if ($permission = content_access_get_permission_by_op($op, $node->type)) {
|
||||
$perm_roles = content_access_get_permission_access($permission);
|
||||
$rids = array_diff($rids, $perm_roles);
|
||||
|
||||
if (in_array(DRUPAL_AUTHENTICATED_RID, $perm_roles)) {
|
||||
return in_array(DRUPAL_ANONYMOUS_RID, $rids) ? array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID) : array(DRUPAL_AUTHENTICATED_RID);
|
||||
}
|
||||
}
|
||||
return $rids;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the per node role settings. If no per node settings are available,
|
||||
* it will return the content type settings.
|
||||
*
|
||||
* @param $op
|
||||
* One of the supported operations.
|
||||
* @param $node
|
||||
* The node object.
|
||||
* @param $settings
|
||||
* Optional array used to update the settings cache with the given settings.
|
||||
* @return
|
||||
* An array of role ids which have access.
|
||||
*/
|
||||
function content_access_per_node_setting($op, $node, $settings = NULL) {
|
||||
static $grants = array();
|
||||
|
||||
if (isset($settings)) {
|
||||
// Update settings cache
|
||||
$grants[$node->nid] = $settings;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($grants[$node->nid]) || $grants[$node->nid] === FALSE) {
|
||||
$grants[$node->nid] = content_access_get_per_node_settings($node);
|
||||
}
|
||||
|
||||
// Return the content type defaults if no per node settings are available
|
||||
return isset($grants[$node->nid][$op]) ? $grants[$node->nid][$op] : content_access_get_settings($op, $node->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the per node settings of a node.
|
||||
*
|
||||
* @note
|
||||
* This function won't apply defaults, so if there are no other settings
|
||||
* it will return an empty array.
|
||||
*/
|
||||
function content_access_get_per_node_settings($node) {
|
||||
foreach (db_query("SELECT settings FROM {content_access} WHERE nid = :nid", array(':nid' => $node->nid)) as $record) {
|
||||
$settings = $record->settings;
|
||||
if (!$settings) {
|
||||
return array();
|
||||
}
|
||||
return unserialize($settings);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves custom per node settings in the own content_access table.
|
||||
*/
|
||||
function content_access_save_per_node_settings($node, $settings) {
|
||||
$count = db_select('content_access')
|
||||
->condition('nid', $node->nid)
|
||||
->countQuery()->execute()->fetchField();
|
||||
|
||||
if ($count > 0) {
|
||||
db_update('content_access')
|
||||
->condition('nid', $node->nid)
|
||||
->fields(array('settings' => serialize($settings)))
|
||||
->execute();
|
||||
}
|
||||
else {
|
||||
db_insert('content_access')
|
||||
->fields(array('nid' => $node->nid, 'settings' => serialize($settings)))
|
||||
->execute();
|
||||
}
|
||||
|
||||
// Make content_access_per_node_setting() use the new settings
|
||||
content_access_per_node_setting(NULL, $node, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all custom per node settings, so that content type defaults are used again.
|
||||
*/
|
||||
function content_access_delete_per_node_settings($node) {
|
||||
db_delete('content_access')
|
||||
->condition('nid', $node->nid)
|
||||
->execute();
|
||||
|
||||
// Clear the cache.
|
||||
content_access_per_node_setting(NULL, $node, FALSE);
|
||||
|
||||
// Delete possible acl settings
|
||||
if (module_exists('acl')) {
|
||||
// @todo why content_access.admin.inc is not loaded before?
|
||||
module_load_include('inc', 'content_access', 'content_access.admin');
|
||||
foreach (array('view', 'update', 'delete') as $op) {
|
||||
$acl_id = content_access_get_acl_id($node, $op);
|
||||
acl_delete_acl($acl_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes grants that doesn't change anything.
|
||||
*
|
||||
* @note
|
||||
* The grants are compared with the normal access control settings.
|
||||
*/
|
||||
function content_access_optimize_grants(&$grants, $node) {
|
||||
$rids = array('view' => array(), 'update' => array(), 'delete' => array());
|
||||
|
||||
foreach ($grants as $key => $grant) {
|
||||
foreach (array('view', 'update', 'delete') as $op) {
|
||||
if (is_numeric($key) && !empty($grant['grant_' . $op])) {
|
||||
$rids[$op][] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Detect if all are allowed to view
|
||||
$all = array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID);
|
||||
if (count(array_diff($all, $rids['view'])) == 0) {
|
||||
//grant view access to all instead of single roles
|
||||
$rids['view'] = array('all');
|
||||
$grants['all'] = array('realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0, 'priority' => content_access_get_settings('priority', $node->type));
|
||||
}
|
||||
|
||||
// If authenticated users are involved, remove unnecessary other roles.
|
||||
foreach (array('view', 'update', 'delete') as $op) {
|
||||
if (in_array(DRUPAL_AUTHENTICATED_RID, $rids[$op])) {
|
||||
$rids[$op] = in_array(DRUPAL_ANONYMOUS_RID, $rids[$op]) ? array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID) : array(DRUPAL_AUTHENTICATED_RID);
|
||||
}
|
||||
}
|
||||
|
||||
// Now let's remove unnecessary grants, if any.
|
||||
foreach ($grants as $key => $grant) {
|
||||
if (!is_numeric($key)) {
|
||||
continue;
|
||||
}
|
||||
foreach (array('view', 'update', 'delete') as $op) {
|
||||
if ($grant['grant_' . $op] && in_array($key, $rids[$op])) {
|
||||
//it's still here, so we can't remove this grant
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
//ok, remove it
|
||||
unset($grants[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_type_delete().
|
||||
*/
|
||||
function content_access_node_type_delete($info) {
|
||||
variable_del('content_access_' . $info->type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_type_update().
|
||||
*
|
||||
* Updates settings on node type name change.
|
||||
*/
|
||||
function content_access_node_type_update($info) {
|
||||
if (!empty($info->old_type) && $info->old_type != $info->type) {
|
||||
$settings = content_access_get_settings('all', $info->old_type);
|
||||
content_access_set_settings($settings, $info->type);
|
||||
variable_del('content_access_' . $info->old_type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_access_explain().
|
||||
*/
|
||||
function content_access_node_access_explain($row) {
|
||||
static $roles;
|
||||
|
||||
if (!isset($roles)) {
|
||||
$roles = user_roles();
|
||||
}
|
||||
if (!$row->gid && $row->realm == 'content_access_rid') {
|
||||
return t('Content access: No access is granted.');
|
||||
}
|
||||
switch ($row->realm) {
|
||||
case 'content_access_author':
|
||||
return t('Content access: author of the content can access');
|
||||
case 'content_access_rid':
|
||||
return t('Content access: %role can access', array('%role' => $roles[$row->gid]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_alter().
|
||||
*/
|
||||
function content_access_form_alter(&$form, $form_state, $form_id) {
|
||||
if ($form_id == 'user_admin_perm') {
|
||||
module_load_include('inc', 'content_access', 'content_access.admin');
|
||||
$form['#submit'][] = 'content_access_user_admin_perm_submit';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of possible operations on content and their labels.
|
||||
*/
|
||||
function _content_access_get_operations($type = NULL) {
|
||||
$operations = array(
|
||||
'view' => t('View any @type content', array('@type' => $type)),
|
||||
'view_own' => t('View own @type content', array('@type' => $type)),
|
||||
'update' => t('Edit any @type content', array('@type' => $type)),
|
||||
'update_own' => t('Edit own @type content', array('@type' => $type)),
|
||||
'delete' => t('Delete any @type content', array('@type' => $type)),
|
||||
'delete_own' => t('Delete own @type content', array('@type' => $type)),
|
||||
);
|
||||
return $operations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formapi #process callback, that disables checkboxes for roles without access to content
|
||||
*/
|
||||
function content_access_disable_checkboxes($element) {
|
||||
$access_roles = content_access_get_permission_access('access content');
|
||||
$admin_roles = content_access_get_permission_access('administer nodes');
|
||||
|
||||
foreach (element_children($element) as $key) {
|
||||
if (!in_array($key, $access_roles) &&
|
||||
$key == DRUPAL_ANONYMOUS_RID &&
|
||||
!in_array(DRUPAL_AUTHENTICATED_RID, $access_roles)) {
|
||||
$element[$key]['#disabled'] = TRUE;
|
||||
$element[$key]['#default_value'] = FALSE;
|
||||
$element[$key]['#prefix'] = '<span' . drupal_attributes(array('title' => t("This role is lacking the permission '@perm', so it has no access.", array('@perm' => t('access content'))))) . '>';
|
||||
$element[$key]['#suffix'] = "</span>";
|
||||
}
|
||||
elseif (in_array($key, $admin_roles) ||
|
||||
($key != DRUPAL_ANONYMOUS_RID && in_array(DRUPAL_AUTHENTICATED_RID, $admin_roles))) {
|
||||
// Fix the checkbox to be enabled for users with administer node privileges
|
||||
$element[$key]['#disabled'] = TRUE;
|
||||
$element[$key]['#default_value'] = TRUE;
|
||||
$element[$key]['#prefix'] = '<span' . drupal_attributes(array('title' => t("This role has '@perm' permission, so access is granted.", array('@perm' => t('administer nodes'))))) . '>';
|
||||
$element[$key]['#suffix'] = "</span>";
|
||||
}
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets node's access permissions.
|
||||
*/
|
||||
function _content_access_get_node_permissions($type) {
|
||||
return array_filter(array_map('content_access_get_permission_by_op', array_flip(_content_access_get_operations()), array_fill(0, 6, $type)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content access acl id of the node.
|
||||
*/
|
||||
function content_access_get_acl_id($node, $op) {
|
||||
$acl_id = acl_get_id_by_name('content_access', $op . '_' . $node->nid);
|
||||
if (!$acl_id) {
|
||||
$acl_id = acl_create_new_acl('content_access', $op . '_' . $node->nid);
|
||||
}
|
||||
return $acl_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches all our ACLs for the nodes of the given type.
|
||||
*/
|
||||
function _content_access_remove_acls($type) {
|
||||
$result = db_query("SELECT n.nid FROM {node} n WHERE type = :type", array('type' => $type));
|
||||
foreach ($result as $node) {
|
||||
acl_node_clear_acls($node->nid, 'content_access');
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
name = Content Access Rules Integrations
|
||||
description = Integrates Rules with Content access. Allows to act on access events, conditions, and actions.
|
||||
package = Access control
|
||||
core = 7.x
|
||||
dependencies[] = content_access
|
||||
dependencies[] = rules
|
||||
files[] = content_access.rules.inc
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-01-22
|
||||
version = "7.x-1.2-beta1+10-dev"
|
||||
core = "7.x"
|
||||
project = "content_access"
|
||||
datestamp = "1358858714"
|
||||
|
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Hooks and callback functions for rules.module integration.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_content_type_access().
|
||||
*/
|
||||
function content_access_rules_content_type_access($settings) {
|
||||
rules_invoke_event('content_access_content_type');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_user_acl().
|
||||
*/
|
||||
function content_access_rules_user_acl($settings) {
|
||||
rules_invoke_event('content_access_user_acl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_per_node().
|
||||
*/
|
||||
function content_access_rules_per_node($settings) {
|
||||
rules_invoke_event('content_access_per_node');
|
||||
}
|
@@ -0,0 +1,396 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Rules specific functions that expose content_access' API.
|
||||
*
|
||||
* @todo
|
||||
* A way to enable per-node settings when a rule created, otherwise no effects
|
||||
* will be noticed.
|
||||
* Clean-up function names.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_rules_event_info().
|
||||
*
|
||||
* @ingroup rules
|
||||
*/
|
||||
function content_access_rules_rules_event_info() {
|
||||
$events['content_access_content_type'] = array('label' => t('Content type access control was changed'));
|
||||
$events['content_access_per_node'] = array('label' => t('Per node access control was changed'));
|
||||
|
||||
if (module_exists('acl')) {
|
||||
$events['content_access_user_acl'] = array('label' => t('User was added to ACL'));
|
||||
}
|
||||
|
||||
$items = array();
|
||||
foreach ($events as $name => $event) {
|
||||
$items[$name] = array(
|
||||
'label' => $event['label'],
|
||||
'group' => t('Content Access'),
|
||||
);
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_rules_action_info().
|
||||
*
|
||||
* @ingroup rules
|
||||
*/
|
||||
function content_access_rules_rules_action_info() {
|
||||
$role_actions = array(
|
||||
'content_access_action_grant_node_permissions' => array(
|
||||
'label' => t('Grant access by role'),
|
||||
'description' => t('Grant access to the following content'),
|
||||
),
|
||||
'content_access_action_revoke_node_permissions' => array(
|
||||
'label' => t('Revoke access by role'),
|
||||
'description' => t('Revoke access to the following content'),
|
||||
),
|
||||
);
|
||||
|
||||
$reset_actions = array(
|
||||
'content_access_action_reset_node_permissions' => array(
|
||||
'label' => t('Reset access to content type defaults'),
|
||||
'description' => t('Reset node permissions to default permissions'),
|
||||
),
|
||||
);
|
||||
|
||||
$user_actions = array(
|
||||
'content_access_action_user_grant' => array(
|
||||
'label' => t('Grant access by user'),
|
||||
'operation' => t('Grant'),
|
||||
'description' => t('Grant access to the following content'),
|
||||
),
|
||||
'content_access_action_user_revoke' => array(
|
||||
'label' => t('Revoke access by user'),
|
||||
'operation' => t('Revoke'),
|
||||
'description' => t('Revoke access to the following content'),
|
||||
),
|
||||
);
|
||||
|
||||
$items = array();
|
||||
foreach ($role_actions as $name => $action) {
|
||||
$items[$name] = array(
|
||||
'label' => $action['label'],
|
||||
'parameter' => array(
|
||||
'node' => array(
|
||||
'type' => 'node',
|
||||
'label' => t('Content'),
|
||||
'description' => $action['description'],
|
||||
),
|
||||
'permissions' => array(
|
||||
'type' => 'list<text>',
|
||||
'label' => t('Role-based access control settings'),
|
||||
'optional' => TRUE,
|
||||
'options list' => 'content_access_action_roles_permissions_list',
|
||||
'restriction' => 'input',
|
||||
),
|
||||
),
|
||||
'group' => t('Content Access'),
|
||||
'callbacks' => array(
|
||||
'form_alter' => 'content_access_rules_action_form_alter',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($reset_actions as $name => $action) {
|
||||
$items[$name] = array(
|
||||
'label' => $action['label'],
|
||||
'parameter' => array(
|
||||
'node' => array(
|
||||
'type' => 'node',
|
||||
'label' => t('Content'),
|
||||
'description' => $action['description'],
|
||||
),
|
||||
),
|
||||
'group' => t('Content Access'),
|
||||
);
|
||||
}
|
||||
|
||||
if (module_exists('acl')) {
|
||||
foreach ($user_actions as $name => $action) {
|
||||
$items[$name] = array(
|
||||
'label' => $action['label'],
|
||||
'named parameter' => TRUE,
|
||||
'parameter' => array(
|
||||
'node' => array(
|
||||
'type' => 'node',
|
||||
'label' => t('Content'),
|
||||
'description' => $action['description'],
|
||||
),
|
||||
'content_access_user_view' => array(
|
||||
'type' => 'user',
|
||||
'label' => t('@action view access', array('@action' => $action['operation'])),
|
||||
'optional' => TRUE,
|
||||
'description' => t('@action view access to the following user.', array('@action' => $action['operation'])),
|
||||
),
|
||||
'content_access_user_update' => array(
|
||||
'type' => 'user',
|
||||
'label' => t('@action update access', array('@action' => $action['operation'])),
|
||||
'optional' => TRUE,
|
||||
'description' => t('@action edit access to the following user.', array('@action' => $action['operation'])),
|
||||
),
|
||||
'content_access_user_delete' => array(
|
||||
'type' => 'user',
|
||||
'label' => t('@action delete access', array('@action' => $action['operation'])),
|
||||
'optional' => TRUE,
|
||||
'description' => t('@action delete access to the following user.', array('@action' => $action['operation'])),
|
||||
),
|
||||
),
|
||||
'group' => t('Content Access User'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an options list array for the content access permission parameter.
|
||||
*/
|
||||
function content_access_action_roles_permissions_list() {
|
||||
$options = array();
|
||||
$roles = array_map('filter_xss_admin', user_roles());
|
||||
|
||||
foreach (_content_access_get_operations() as $op => $label) {
|
||||
foreach ($roles as $rid => $role) {
|
||||
$options[$op][$op . ':' . $rid] = $op . ' ' . $role;
|
||||
}
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the settings form to render the text<list> as checkboxes.
|
||||
*/
|
||||
function content_access_rules_action_form_alter(&$form, &$form_state) {
|
||||
// Per node access control should be enabled for this type of action to be
|
||||
// effective.
|
||||
drupal_set_message(t('Access control settings will not be executed for the affected node unless you enabled \'%per_node\' from the Access Control tab on content type page of the node', array('%per_node' => 'Per content node access control settings')), 'warning');
|
||||
|
||||
// Alter the text<list> to make it into checkboxes groups
|
||||
$elements =& $form['parameter']['permissions']['settings']['permissions'];
|
||||
$elements = content_access_rules_checkboxes_form((array) $elements['#default_value']);
|
||||
|
||||
// Add our own after build callback for fixing the form value afterwards.
|
||||
$elements['#after_build'][] = 'content_access_rules_action_form_after_build';
|
||||
|
||||
// Make sure our include file is loaded when FAPI processes the form.
|
||||
form_load_include($form_state, 'inc', 'content_access_rules', 'content_access_rules.rules');
|
||||
}
|
||||
|
||||
/**
|
||||
* Form after build callback.
|
||||
*
|
||||
* Get the form settings as checkboxes, convert them back to list<text>.
|
||||
*/
|
||||
function content_access_rules_action_form_after_build($element, &$form_state) {
|
||||
if ($form_state['process_input']) {
|
||||
$form_value = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
|
||||
$value = content_access_rules_transform_to_rule_value($form_value);
|
||||
form_set_value($element, $value, $form_state);
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the form elements for configuring content access per-role permissions.
|
||||
*/
|
||||
function content_access_rules_checkboxes_form($value) {
|
||||
$form = array();
|
||||
$roles = array_map('filter_xss_admin', user_roles());
|
||||
$defaults = content_access_rules_transform_rules_value($value);
|
||||
|
||||
foreach (_content_access_get_operations() as $op => $label) {
|
||||
$form[$op] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#prefix' => '<div class="content_access-div">',
|
||||
'#suffix' => '</div>',
|
||||
'#options' => $roles,
|
||||
'#title' => $label,
|
||||
'#default_value' => isset($defaults[$op]) ? $defaults[$op] : array(),
|
||||
'#process' => array('form_process_checkboxes', 'content_access_disable_checkboxes'),
|
||||
);
|
||||
}
|
||||
$form['clearer'] = array(
|
||||
'#value' => '<br clear="all" />',
|
||||
);
|
||||
drupal_add_css(drupal_get_path('module', 'content_access') . '/content_access.css');
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the array of text values used by Rules to an array keyed by $op and $rid.
|
||||
*
|
||||
* @see content_access_rules_transform_to_rule_value()
|
||||
*/
|
||||
function content_access_rules_transform_rules_value($value) {
|
||||
$array = array();
|
||||
foreach ($value as $op_role) {
|
||||
$parts = explode(':', $op_role);
|
||||
// The first item is $op and the second $rid.
|
||||
$array[$parts[0]][] = $parts[1];
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the form values array keyed by $op and $rid to an array of text values as used by Rules.
|
||||
*
|
||||
* @see content_access_rules_transform_rules_value()
|
||||
*/
|
||||
function content_access_rules_transform_to_rule_value($form_values) {
|
||||
$value = array();
|
||||
foreach ($form_values as $op => $array) {
|
||||
foreach (array_filter($array) as $rid => $data) {
|
||||
$value[] = $op . ':' . $rid;
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action implementation: Grant permissions for a node.
|
||||
*/
|
||||
function content_access_action_grant_node_permissions($node, $permissions) {
|
||||
if (!empty($node->nid) && _content_access_rules_check_setting($node)) {
|
||||
// Transform the value to the content-access format.
|
||||
$settings = content_access_rules_transform_rules_value($permissions);
|
||||
$ca_settings = array();
|
||||
foreach (_content_access_get_operations() as $op => $label) {
|
||||
// Merge in the array of role-ids for each operation.
|
||||
$settings += array($op => array());
|
||||
$ca_settings[$op] = array_keys(array_flip(content_access_per_node_setting($op, $node)) + array_flip($settings[$op]));
|
||||
}
|
||||
content_access_save_per_node_settings($node, $ca_settings);
|
||||
content_access_action_aquire_grants($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action implementation: Revoke permissions for a node.
|
||||
*/
|
||||
function content_access_action_revoke_node_permissions($node, $permissions) {
|
||||
if (!empty($node->nid) && _content_access_rules_check_setting($node)) {
|
||||
// Transform the value to the content-access format.
|
||||
$settings = content_access_rules_transform_rules_value($permissions);
|
||||
|
||||
$ca_settings = array();
|
||||
foreach (_content_access_get_operations() as $op => $label) {
|
||||
$settings += array($op => array());
|
||||
$ca_settings[$op] = array_diff(content_access_per_node_setting($op, $node), $settings[$op]);
|
||||
}
|
||||
content_access_save_per_node_settings($node, $ca_settings);
|
||||
content_access_action_aquire_grants($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action implementation: Reset permissions for a node.
|
||||
*/
|
||||
function content_access_action_reset_node_permissions($node) {
|
||||
content_access_delete_per_node_settings($node);
|
||||
content_access_action_aquire_grants($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that per content settings are activated for the given node.
|
||||
*/
|
||||
function _content_access_rules_check_setting($node) {
|
||||
$type = $node->type;
|
||||
$settings = variable_get('content_access_' . $type, array());
|
||||
|
||||
if (isset($settings['per_node']) && $settings['per_node']) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// If we didn't find any settings in content access for this type return
|
||||
// false as we don't want to process it.
|
||||
rules_log("Can't set per content permissions for content type @type. Make sure to have per content settings activated for content types you want to alter access control for.", array('@type' => $node->type), RulesLog::WARN);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the settings string into array.
|
||||
*/
|
||||
function content_access_action_settings($action_settings = array()) {
|
||||
$roles_ids = array_flip(user_roles());
|
||||
|
||||
foreach (_content_access_get_operations() as $op => $label) {
|
||||
$settings[$op] = array();
|
||||
}
|
||||
|
||||
foreach ($action_settings as $op_role => $role) {
|
||||
$op = substr($op_role, 0, strpos($op_role, ':'));
|
||||
$rid = $roles_ids[$role];
|
||||
$settings[$op][] = $rid;
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action implementation: Grant user access.
|
||||
*/
|
||||
function content_access_action_user_grant($params) {
|
||||
content_access_action_user($params, 'grant');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action implementation: Revoke user access.
|
||||
*/
|
||||
function content_access_action_user_revoke($params) {
|
||||
content_access_action_user($params, 'revoke');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Rule's param, and grant by the passed operation.
|
||||
*/
|
||||
function content_access_action_user($params, $type) {
|
||||
$ops = array('view', 'update', 'delete');
|
||||
$settings = array();
|
||||
$node = $params['node'];
|
||||
|
||||
foreach ($ops as $op) {
|
||||
if ($params['content_access_user_' . $op]) {
|
||||
$settings[$op] = $params['content_access_user_' . $op]->uid;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($settings as $op => $uid) {
|
||||
$acl_id = content_access_get_acl_id($node, $op);
|
||||
acl_node_add_acl($node->nid, $acl_id, (int) ($op == 'view'), (int) ($op == 'update'), (int) ($op == 'delete'), content_access_get_settings('priority', $node->type));
|
||||
|
||||
db_delete('acl_user')
|
||||
->condition('acl_id', $acl_id)
|
||||
->condition('uid', $uid)
|
||||
->execute();
|
||||
|
||||
if ($type == 'grant') {
|
||||
db_insert('acl_user')
|
||||
->fields(array(
|
||||
'acl_id' => $acl_id,
|
||||
'uid' => $uid,
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
content_access_action_aquire_grants($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the new grants to the affected node.
|
||||
*/
|
||||
function content_access_action_aquire_grants($node) {
|
||||
// node_save() does implement node_access_acquire_grants() so we don't want
|
||||
// to execute it again or we'll get a duplicated key exception
|
||||
if (!isset($node->op) ||
|
||||
(isset($node->op) && $node->op != 'Save')) {
|
||||
node_access_acquire_grants($node);
|
||||
}
|
||||
}
|
@@ -0,0 +1,332 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Automatd SimpleTest Case for content access module
|
||||
*/
|
||||
|
||||
require_once(drupal_get_path('module', 'content_access') .'/tests/content_access_test_help.php');
|
||||
|
||||
class ContentAccessModuleTestCase extends ContentAccessTestCase {
|
||||
|
||||
/**
|
||||
* Implementation of get_info() for information
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => t('Content Access Module Tests'),
|
||||
'description' => t('Various tests to check permission settings on nodes.'),
|
||||
'group' => t('Content Access'),
|
||||
);
|
||||
}
|
||||
|
||||
function setUp($module = '') {
|
||||
parent::setUp();
|
||||
|
||||
// Create test nodes
|
||||
$this->node1 = $this->drupalCreateNode(array('type' => $this->content_type->type));
|
||||
$this->node2 = $this->drupalCreateNode(array('type' => $this->content_type->type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for viewing nodes
|
||||
*/
|
||||
function testViewAccess() {
|
||||
// Restrict access to the content type (access is only allowed for the author)
|
||||
$access_permissions = array(
|
||||
'view[1]' => FALSE,
|
||||
'view[2]' => FALSE,
|
||||
);
|
||||
$this->changeAccessContentType($access_permissions);
|
||||
|
||||
// Logout admin and try to access the node anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertText(t('Access denied'), 'node is not viewable');
|
||||
|
||||
// Login test user, view node, access must be denied
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertText(t('Access denied'), 'node is not viewable');
|
||||
|
||||
// Login admin and grant access for viewing to the test user
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$this->changeAccessContentTypeKeyword('view');
|
||||
|
||||
// Logout admin and try to access the node anonymously
|
||||
// access must be denied again
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertText(t('Access denied'), 'node is not viewable');
|
||||
|
||||
// Login test user, view node, access must be granted
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertNoText(t('Access denied'), 'node is viewable');
|
||||
|
||||
// Login admin and enable per node access
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$this->changeAccessPerNode();
|
||||
|
||||
// Restrict access on node2 for the test user role
|
||||
$this->changeAccessNodeKeyword($this->node2, 'view', FALSE);
|
||||
|
||||
// Logout admin and try to access both nodes anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertText(t('Access denied'), 'node1 is not viewable');
|
||||
$this->drupalGet('node/'. $this->node2->nid);
|
||||
$this->assertText(t('Access denied'), 'node2 is not viewable');
|
||||
|
||||
// Login test user, view node1, access must be granted
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertNoText(t('Access denied'), 'node1 is viewable');
|
||||
|
||||
// View node2, access must be denied
|
||||
$this->drupalGet('node/'. $this->node2->nid);
|
||||
$this->assertText(t('Access denied'), 'node2 is not viewable');
|
||||
|
||||
// Login admin, swap permissions between content type and node2
|
||||
$this->drupalLogin($this->admin_user);
|
||||
|
||||
// Restrict access to content type
|
||||
$this->changeAccessContentTypeKeyword('view', FALSE);
|
||||
|
||||
// Grant access to node2
|
||||
$this->changeAccessNodeKeyword($this->node2, 'view');
|
||||
|
||||
// Logout admin and try to access both nodes anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertText(t('Access denied'), 'node1 is not viewable');
|
||||
$this->drupalGet('node/'. $this->node2->nid);
|
||||
$this->assertText(t('Access denied'), 'node2 is not viewable');
|
||||
|
||||
// Login test user, view node1, access must be denied
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertText(t('Access denied'), 'node1 is not viewable');
|
||||
|
||||
// View node2, access must be granted
|
||||
$this->drupalGet('node/'. $this->node2->nid);
|
||||
$this->assertNoText(t('Access denied'), 'node2 is viewable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for editing nodes
|
||||
*/
|
||||
function testEditAccess() {
|
||||
// Logout admin and try to edit the node anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'edit access denied for anonymous');
|
||||
|
||||
// Login test user, edit node, access must be denied
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'edit access denied for test user');
|
||||
|
||||
// Login admin and grant access for editing to the test user
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$this->changeAccessContentTypeKeyword('update');
|
||||
|
||||
// Logout admin and try to edit the node anonymously
|
||||
// access must be denied again
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'edit access denied for anonymous');
|
||||
|
||||
// Login test user, edit node, access must be granted
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/edit');
|
||||
$this->assertNoText(t('Access denied'), 'node1 is editable');
|
||||
|
||||
// Login admin and enable per node access
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$this->changeAccessPerNode();
|
||||
|
||||
// Restrict access for this content type for the test user
|
||||
$this->changeAccessContentTypeKeyword('update', FALSE);
|
||||
|
||||
// Allow acces for node1 only
|
||||
$this->changeAccessNodeKeyword($this->node1, 'update');
|
||||
|
||||
// Logout admin and try to edit both nodes anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'node1 is not editable');
|
||||
$this->drupalGet('node/'. $this->node2->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'node2 is not editable');
|
||||
|
||||
// Login test user, edit node1, access must be granted
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/edit');
|
||||
$this->assertNoText(t('Access denied'), 'node1 is editable');
|
||||
|
||||
// Edit node2, access must be denied
|
||||
$this->drupalGet('node/'. $this->node2->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'node2 is not editable');
|
||||
|
||||
// Login admin, swap permissions between node1 and node2
|
||||
$this->drupalLogin($this->admin_user);
|
||||
|
||||
// Grant edit access to node2
|
||||
$this->changeAccessNodeKeyword($this->node2, 'update');
|
||||
// Restrict edit acces to node1
|
||||
$this->changeAccessNodeKeyword($this->node1, 'update', FALSE);
|
||||
|
||||
// Logout admin and try to edit both nodes anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'node1 is not editable');
|
||||
$this->drupalGet('node/'. $this->node2->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'node2 is not editable');
|
||||
|
||||
// Login test user, edit node1, access must be denied
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'node1 is not editable');
|
||||
|
||||
// Edit node2, access must be granted
|
||||
$this->drupalGet('node/'. $this->node2->nid .'/edit');
|
||||
$this->assertNoText(t('Access denied'), 'node2 is editable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for deleting nodes
|
||||
*/
|
||||
function testDeleteAccess() {
|
||||
// Logout admin and try to delete the node anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'delete access denied for anonymous');
|
||||
|
||||
// Login test user, delete node, access must be denied
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'delete access denied for test user');
|
||||
|
||||
// Login admin and grant access for deleting to the test user
|
||||
$this->drupalLogin($this->admin_user);
|
||||
|
||||
$this->changeAccessContentTypeKeyword('delete');
|
||||
|
||||
// Logout admin and try to edit the node anonymously
|
||||
// access must be denied again
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'delete access denied for anonymous');
|
||||
|
||||
// Login test user, delete node, access must be granted
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalPost('node/'. $this->node1->nid .'/delete', array(), 'Delete');
|
||||
$this->assertRaw(t('%node has been deleted', array('%node' => $this->node1->title)), 'Test node was deleted successfully by test user');
|
||||
|
||||
// Login admin and recreate test node1
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$this->node1 = $this->drupalCreateNode(array('type' => $this->content_type->type));
|
||||
|
||||
// Enable per node access
|
||||
$this->changeAccessPerNode();
|
||||
|
||||
// Restrict access for this content type for the test user
|
||||
$this->changeAccessContentTypeKeyword('delete', FALSE);
|
||||
|
||||
// Allow acces for node1 only
|
||||
$this->changeAccessNodeKeyword($this->node1, 'delete');
|
||||
|
||||
// Logout admin and try to delete both nodes anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'node1 is not deletable');
|
||||
$this->drupalGet('node/'. $this->node2->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'node2 is not deletable');
|
||||
|
||||
// Login test user, delete node1, access must be granted
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/delete');
|
||||
$this->assertNoText(t('Access denied'), 'node1 is deletable');
|
||||
|
||||
// Delete node2, access must be denied
|
||||
$this->drupalGet('node/'. $this->node2->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'node2 is not deletable');
|
||||
|
||||
// Login admin, swap permissions between node1 and node2
|
||||
$this->drupalLogin($this->admin_user);
|
||||
|
||||
// Grant delete access to node2
|
||||
$this->changeAccessNodeKeyword($this->node2, 'delete');
|
||||
// Restrict delete acces to node1
|
||||
$this->changeAccessNodeKeyword($this->node1, 'delete', FALSE);
|
||||
|
||||
// Logout admin and try to delete both nodes anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'node1 is not deletable');
|
||||
$this->drupalGet('node/'. $this->node2->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'node2 is not deletable');
|
||||
|
||||
// Login test user, delete node1, access must be denied
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node1->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'node1 is not deletable');
|
||||
|
||||
// Delete node2, access must be granted
|
||||
$this->drupalGet('node/'. $this->node2->nid .'/delete');
|
||||
$this->assertNoText(t('Access denied'), 'node2 is deletable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test own view access
|
||||
*/
|
||||
function testOwnViewAccess() {
|
||||
// Setup 2 test users
|
||||
$test_user1 = $this->test_user;
|
||||
$test_user2 = $this->drupalCreateUser();
|
||||
|
||||
// Change ownership of test nodes to test users
|
||||
$this->node1->uid = $test_user1->uid;
|
||||
node_save($this->node1);
|
||||
$this->node2->uid = $test_user2->uid;
|
||||
node_save($this->node2);
|
||||
|
||||
// Remove all view permissions for this content type
|
||||
$access_permissions = array(
|
||||
'view[1]' => FALSE,
|
||||
'view[2]' => FALSE,
|
||||
'view_own[1]' => FALSE,
|
||||
'view_own[2]' => FALSE,
|
||||
);
|
||||
$this->changeAccessContentType($access_permissions);
|
||||
|
||||
// Allow view own content for test user 1 and 2 roles
|
||||
$this->changeAccessContentTypeKeyword('view_own', TRUE, $test_user1);
|
||||
$this->changeAccessContentTypeKeyword('view_own', TRUE, $test_user2);
|
||||
|
||||
// Logout admin and try to access both nodes anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertText(t('Access denied'), 'node1 is not viewable');
|
||||
$this->drupalGet('node/'. $this->node2->nid);
|
||||
$this->assertText(t('Access denied'), 'node2 is not viewable');
|
||||
|
||||
// Login test user 1, view node1, access must be granted
|
||||
$this->drupalLogin($test_user1);
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertNoText(t('Access denied'), 'node1 is viewable');
|
||||
|
||||
// View node2, access must be denied
|
||||
$this->drupalGet('node/'. $this->node2->nid);
|
||||
$this->assertText(t('Access denied'), 'node2 is not viewable');
|
||||
|
||||
// Login test user 2, view node1, access must be denied
|
||||
$this->drupalLogin($test_user2);
|
||||
$this->drupalGet('node/'. $this->node1->nid);
|
||||
$this->assertText(t('Access denied'), 'node1 is not viewable');
|
||||
|
||||
// View node2, access must be granted
|
||||
$this->drupalGet('node/'. $this->node2->nid);
|
||||
$this->assertNoText(t('Access denied'), 'node2 is viewable');
|
||||
}
|
||||
}
|
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Automatd SimpleTest Case for using content access module with acl module
|
||||
*/
|
||||
|
||||
require_once(drupal_get_path('module', 'content_access') .'/tests/content_access_test_help.php');
|
||||
|
||||
class ContentAccessACLTestCase extends ContentAccessTestCase {
|
||||
|
||||
var $node;
|
||||
|
||||
/**
|
||||
* Implementation of get_info() for information
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => t('Content Access Module with ACL Module Tests'),
|
||||
'description' => t('Various tests to check the combination of content access and ACL module.'),
|
||||
'group' => 'Content Access',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup configuration before each test
|
||||
*/
|
||||
function setUp($module = '') {
|
||||
parent::setUp('acl');
|
||||
|
||||
if (!module_exists('acl')) {
|
||||
$this->pass('No ACL module present, skipping test');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create test nodes
|
||||
$this->node = $this->drupalCreateNode(array('type' => $this->content_type->type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Viewing accessibility with permissions for single users
|
||||
*/
|
||||
function testViewAccess() {
|
||||
// Exit test if ACL module could not be enabled
|
||||
if (!module_exists('acl')) {
|
||||
$this->pass('No ACL module present, skipping test');
|
||||
return;
|
||||
}
|
||||
|
||||
// Restrict access to this content type (access is only allowed for the author)
|
||||
// Enable per node access control
|
||||
$access_permissions = array(
|
||||
'view[1]' => FALSE,
|
||||
'view[2]' => FALSE,
|
||||
'per_node' => TRUE,
|
||||
);
|
||||
$this->changeAccessContentType($access_permissions);
|
||||
|
||||
// Allow access for test user
|
||||
$edit = array(
|
||||
'acl[view][add]' => $this->test_user->name,
|
||||
);
|
||||
$this->drupalPost('node/'. $this->node->nid .'/access', $edit, t('Add User'));
|
||||
$this->drupalPost(NULL, array(), t('Submit'));
|
||||
|
||||
// Logout admin, try to access the node anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node->nid);
|
||||
$this->assertText(t('Access denied'), 'node is not viewable');
|
||||
|
||||
// Login test user, view access should be allowed now
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node->nid);
|
||||
$this->assertNoText(t('Access denied'), 'node is viewable');
|
||||
|
||||
// Login admin and disable per node access
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$this->changeAccessPerNode(FALSE);
|
||||
|
||||
// Logout admin, try to access the node anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node->nid);
|
||||
$this->assertText(t('Access denied'), 'node is not viewable');
|
||||
|
||||
// Login test user, view access should be denied now
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node->nid);
|
||||
$this->assertText(t('Access denied'), 'node is not viewable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Editing accessibility with permissions for single users
|
||||
*/
|
||||
function testEditAccess() {
|
||||
// Exit test if ACL module could not be enabled
|
||||
if (!module_exists('acl')) {
|
||||
$this->pass('No ACL module present, skipping test');
|
||||
return;
|
||||
}
|
||||
|
||||
// Enable per node access control
|
||||
$this->changeAccessPerNode();
|
||||
|
||||
// Allow edit access for test user
|
||||
$edit = array(
|
||||
'acl[update][add]' => $this->test_user->name,
|
||||
);
|
||||
$this->drupalPost('node/'. $this->node->nid .'/access', $edit, t('Add User'));
|
||||
$this->drupalPost(NULL, array(), t('Submit'));
|
||||
|
||||
// Logout admin, try to edit the node anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'node is not editable');
|
||||
|
||||
// Login test user, edit access should be allowed now
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node->nid .'/edit');
|
||||
$this->assertNoText(t('Access denied'), 'node is editable');
|
||||
|
||||
// Login admin and disable per node access
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$this->changeAccessPerNode(FALSE);
|
||||
|
||||
// Logout admin, try to edit the node anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'node is not editable');
|
||||
|
||||
// Login test user, edit access should be denied now
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node->nid .'/edit');
|
||||
$this->assertText(t('Access denied'), 'node is not editable');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Deleting accessibility with permissions for single users
|
||||
*/
|
||||
function testDeleteAccess() {
|
||||
// Exit test if ACL module could not be enabled
|
||||
if (!module_exists('acl')) {
|
||||
$this->pass('No ACL module present, skipping test');
|
||||
return;
|
||||
}
|
||||
|
||||
// Enable per node access control
|
||||
$this->changeAccessPerNode();
|
||||
|
||||
// Allow delete access for test user
|
||||
$edit = array(
|
||||
'acl[delete][add]' => $this->test_user->name,
|
||||
);
|
||||
$this->drupalPost('node/'. $this->node->nid .'/access', $edit, t('Add User'));
|
||||
$this->drupalPost(NULL, array(), t('Submit'));
|
||||
|
||||
// Logout admin, try to delete the node anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'node is not deletable');
|
||||
|
||||
// Login test user, delete access should be allowed now
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node->nid .'/delete');
|
||||
$this->assertNoText(t('Access denied'), 'node is deletable');
|
||||
|
||||
// Login admin and disable per node access
|
||||
$this->drupalLogin($this->admin_user);
|
||||
$this->changeAccessPerNode(FALSE);
|
||||
|
||||
// Logout admin, try to delete the node anonymously
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet('node/'. $this->node->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'node is not deletable');
|
||||
|
||||
// Login test user, delete access should be denied now
|
||||
$this->drupalLogin($this->test_user);
|
||||
$this->drupalGet('node/'. $this->node->nid .'/delete');
|
||||
$this->assertText(t('Access denied'), 'node is not deletable');
|
||||
}
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper class with auxiliary functions for content access module tests
|
||||
*/
|
||||
|
||||
class ContentAccessTestCase extends DrupalWebTestCase {
|
||||
|
||||
var $test_user;
|
||||
var $rid;
|
||||
var $admin_user;
|
||||
var $content_type;
|
||||
var $url_content_type_name;
|
||||
var $node1;
|
||||
var $node2;
|
||||
|
||||
/**
|
||||
* Preparation work that is done before each test.
|
||||
* Test users, content types, nodes etc. are created.
|
||||
*/
|
||||
function setUp($module = '') {
|
||||
if (empty($module)) {
|
||||
// Enable content access module
|
||||
parent::setUp('content_access');
|
||||
}
|
||||
else {
|
||||
// Enable content access module plus another module
|
||||
parent::setUp('content_access', $module);
|
||||
// Stop setup when module could not be enabled
|
||||
if (!module_exists($module)) {
|
||||
$this->pass('No ' . $module . ' module present, skipping test');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create test user with seperate role
|
||||
$this->test_user = $this->drupalCreateUser();
|
||||
|
||||
// Get the value of the new role
|
||||
// Needed in D7 because it's by default create two roles for new users
|
||||
// one role is Authenticated and the second is new default one
|
||||
// @see drupalCreateUser()
|
||||
foreach ($this->test_user->roles as $rid => $role) {
|
||||
if (!in_array($rid, array(DRUPAL_AUTHENTICATED_RID))) {
|
||||
$this->rid = $rid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create admin user
|
||||
$this->admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'grant content access', 'grant own content access', 'administer nodes', 'access administration pages'));
|
||||
$this->drupalLogin($this->admin_user);
|
||||
|
||||
// Rebuild content access permissions
|
||||
node_access_rebuild();
|
||||
|
||||
// Create test content type
|
||||
$this->content_type = $this->drupalCreateContentType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change access permissions for a content type
|
||||
*/
|
||||
function changeAccessContentType($access_settings) {
|
||||
$this->drupalPost('admin/structure/types/manage/'. $this->content_type->type .'/access', $access_settings, t('Submit'));
|
||||
$this->assertText(t('Your changes have been saved.'), 'access rules of content type were updated successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* Change access permissions for a content type by a given keyword (view, update or delete)
|
||||
* for the role of the user
|
||||
*/
|
||||
function changeAccessContentTypeKeyword($keyword, $access = TRUE, $user = NULL) {
|
||||
if ($user === NULL) {
|
||||
$user = $this->test_user;
|
||||
$roles[$this->rid] = $user->roles[$this->rid];
|
||||
} else {
|
||||
foreach ($user->roles as $rid => $role) {
|
||||
if (!in_array($rid, array(DRUPAL_AUTHENTICATED_RID))) {
|
||||
$roles[$rid] = $user->roles[$rid];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$access_settings = array(
|
||||
$keyword .'['. key($roles) .']' => $access,
|
||||
);
|
||||
|
||||
$this->changeAccessContentType($access_settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the per node access setting for a content type
|
||||
*/
|
||||
function changeAccessPerNode($access = TRUE) {
|
||||
$access_permissions = array(
|
||||
'per_node' => $access,
|
||||
);
|
||||
$this->changeAccessContentType($access_permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change access permissions for a node by a given keyword (view, update or delete)
|
||||
*/
|
||||
function changeAccessNodeKeyword($node, $keyword, $access = TRUE) {
|
||||
$user = $this->test_user;
|
||||
$roles[$this->rid] = $user->roles[$this->rid];
|
||||
|
||||
$access_settings = array(
|
||||
$keyword .'['. key($roles) .']' => $access,
|
||||
);
|
||||
|
||||
$this->changeAccessNode($node, $access_settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change access permission for a node
|
||||
*/
|
||||
function changeAccessNode($node, $access_settings) {
|
||||
$this->drupalPost('node/'. $node->nid .'/access', $access_settings, t('Submit'));
|
||||
$this->assertText(t('Your changes have been saved.'), 'access rules of node were updated successfully');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user