Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\Tests\node\Kernel;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Component\Render\FormattableMarkup;
|
Chris@0
|
6 use Drupal\Core\Session\AccountInterface;
|
Chris@0
|
7 use Drupal\KernelTests\KernelTestBase;
|
Chris@0
|
8 use Drupal\node\NodeInterface;
|
Chris@18
|
9 use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
|
Chris@18
|
10 use Drupal\Tests\node\Traits\NodeCreationTrait;
|
Chris@18
|
11 use Drupal\Tests\user\Traits\UserCreationTrait;
|
Chris@0
|
12 use Drupal\user\RoleInterface;
|
Chris@0
|
13
|
Chris@0
|
14 /**
|
Chris@0
|
15 * Tests basic node_access functionality.
|
Chris@0
|
16 *
|
Chris@0
|
17 * @group node
|
Chris@0
|
18 */
|
Chris@0
|
19 class NodeAccessTest extends KernelTestBase {
|
Chris@0
|
20
|
Chris@0
|
21 use NodeCreationTrait {
|
Chris@0
|
22 getNodeByTitle as drupalGetNodeByTitle;
|
Chris@0
|
23 createNode as drupalCreateNode;
|
Chris@0
|
24 }
|
Chris@0
|
25 use UserCreationTrait {
|
Chris@0
|
26 createUser as drupalCreateUser;
|
Chris@0
|
27 createRole as drupalCreateRole;
|
Chris@0
|
28 createAdminRole as drupalCreateAdminRole;
|
Chris@0
|
29 }
|
Chris@0
|
30 use ContentTypeCreationTrait {
|
Chris@0
|
31 createContentType as drupalCreateContentType;
|
Chris@0
|
32 }
|
Chris@0
|
33
|
Chris@0
|
34 /**
|
Chris@0
|
35 * {@inheritdoc}
|
Chris@0
|
36 */
|
Chris@0
|
37 public static $modules = [
|
Chris@0
|
38 'node',
|
Chris@0
|
39 'datetime',
|
Chris@0
|
40 'user',
|
Chris@0
|
41 'system',
|
Chris@0
|
42 'filter',
|
Chris@0
|
43 'field',
|
Chris@0
|
44 'text',
|
Chris@0
|
45 ];
|
Chris@0
|
46
|
Chris@0
|
47 /**
|
Chris@0
|
48 * Access handler.
|
Chris@0
|
49 *
|
Chris@0
|
50 * @var \Drupal\Core\Entity\EntityAccessControlHandlerInterface
|
Chris@0
|
51 */
|
Chris@0
|
52 protected $accessHandler;
|
Chris@0
|
53
|
Chris@0
|
54 /**
|
Chris@0
|
55 * {@inheritdoc}
|
Chris@0
|
56 */
|
Chris@0
|
57 protected function setUp() {
|
Chris@0
|
58 parent::setUp();
|
Chris@0
|
59 $this->installSchema('system', 'sequences');
|
Chris@0
|
60 $this->installSchema('node', 'node_access');
|
Chris@0
|
61 $this->installEntitySchema('user');
|
Chris@0
|
62 $this->installEntitySchema('node');
|
Chris@0
|
63 $this->installConfig('filter');
|
Chris@0
|
64 $this->installConfig('node');
|
Chris@0
|
65 $this->accessHandler = $this->container->get('entity_type.manager')
|
Chris@0
|
66 ->getAccessControlHandler('node');
|
Chris@0
|
67 // Clear permissions for authenticated users.
|
Chris@0
|
68 $this->config('user.role.' . RoleInterface::AUTHENTICATED_ID)
|
Chris@0
|
69 ->set('permissions', [])
|
Chris@0
|
70 ->save();
|
Chris@0
|
71
|
Chris@0
|
72 // Create user 1 who has special permissions.
|
Chris@0
|
73 $this->drupalCreateUser();
|
Chris@0
|
74
|
Chris@0
|
75 // Create a node type.
|
Chris@0
|
76 $this->drupalCreateContentType([
|
Chris@0
|
77 'type' => 'page',
|
Chris@0
|
78 'name' => 'Basic page',
|
Chris@0
|
79 'display_submitted' => FALSE,
|
Chris@0
|
80 ]);
|
Chris@0
|
81 }
|
Chris@0
|
82
|
Chris@0
|
83 /**
|
Chris@0
|
84 * Runs basic tests for node_access function.
|
Chris@0
|
85 */
|
Chris@0
|
86 public function testNodeAccess() {
|
Chris@0
|
87 // Ensures user without 'access content' permission can do nothing.
|
Chris@0
|
88 $web_user1 = $this->drupalCreateUser([
|
Chris@0
|
89 'create page content',
|
Chris@0
|
90 'edit any page content',
|
Chris@0
|
91 'delete any page content',
|
Chris@0
|
92 ]);
|
Chris@0
|
93 $node1 = $this->drupalCreateNode(['type' => 'page']);
|
Chris@0
|
94 $this->assertNodeCreateAccess($node1->bundle(), FALSE, $web_user1);
|
Chris@0
|
95 $this->assertNodeAccess([
|
Chris@0
|
96 'view' => FALSE,
|
Chris@0
|
97 'update' => FALSE,
|
Chris@0
|
98 'delete' => FALSE,
|
Chris@0
|
99 ], $node1, $web_user1);
|
Chris@0
|
100
|
Chris@0
|
101 // Ensures user with 'bypass node access' permission can do everything.
|
Chris@0
|
102 $web_user2 = $this->drupalCreateUser(['bypass node access']);
|
Chris@0
|
103 $node2 = $this->drupalCreateNode(['type' => 'page']);
|
Chris@0
|
104 $this->assertNodeCreateAccess($node2->bundle(), TRUE, $web_user2);
|
Chris@0
|
105 $this->assertNodeAccess([
|
Chris@0
|
106 'view' => TRUE,
|
Chris@0
|
107 'update' => TRUE,
|
Chris@0
|
108 'delete' => TRUE,
|
Chris@0
|
109 ], $node2, $web_user2);
|
Chris@0
|
110
|
Chris@0
|
111 // User cannot 'view own unpublished content'.
|
Chris@0
|
112 $web_user3 = $this->drupalCreateUser(['access content']);
|
Chris@0
|
113 $node3 = $this->drupalCreateNode([
|
Chris@0
|
114 'status' => 0,
|
Chris@0
|
115 'uid' => $web_user3->id(),
|
Chris@0
|
116 ]);
|
Chris@0
|
117 $this->assertNodeAccess(['view' => FALSE], $node3, $web_user3);
|
Chris@0
|
118
|
Chris@0
|
119 // User cannot create content without permission.
|
Chris@0
|
120 $this->assertNodeCreateAccess($node3->bundle(), FALSE, $web_user3);
|
Chris@0
|
121
|
Chris@0
|
122 // User can 'view own unpublished content', but another user cannot.
|
Chris@0
|
123 $web_user4 = $this->drupalCreateUser([
|
Chris@0
|
124 'access content',
|
Chris@0
|
125 'view own unpublished content',
|
Chris@0
|
126 ]);
|
Chris@0
|
127 $web_user5 = $this->drupalCreateUser([
|
Chris@0
|
128 'access content',
|
Chris@0
|
129 'view own unpublished content',
|
Chris@0
|
130 ]);
|
Chris@0
|
131 $node4 = $this->drupalCreateNode([
|
Chris@0
|
132 'status' => 0,
|
Chris@0
|
133 'uid' => $web_user4->id(),
|
Chris@0
|
134 ]);
|
Chris@0
|
135 $this->assertNodeAccess([
|
Chris@0
|
136 'view' => TRUE,
|
Chris@0
|
137 'update' => FALSE,
|
Chris@0
|
138 ], $node4, $web_user4);
|
Chris@0
|
139 $this->assertNodeAccess(['view' => FALSE], $node4, $web_user5);
|
Chris@0
|
140
|
Chris@0
|
141 // Tests the default access provided for a published node.
|
Chris@0
|
142 $node5 = $this->drupalCreateNode();
|
Chris@0
|
143 $this->assertNodeAccess([
|
Chris@0
|
144 'view' => TRUE,
|
Chris@0
|
145 'update' => FALSE,
|
Chris@0
|
146 'delete' => FALSE,
|
Chris@0
|
147 ], $node5, $web_user3);
|
Chris@0
|
148
|
Chris@0
|
149 // Tests the "edit any BUNDLE" and "delete any BUNDLE" permissions.
|
Chris@0
|
150 $web_user6 = $this->drupalCreateUser([
|
Chris@0
|
151 'access content',
|
Chris@0
|
152 'edit any page content',
|
Chris@0
|
153 'delete any page content',
|
Chris@0
|
154 ]);
|
Chris@0
|
155 $node6 = $this->drupalCreateNode(['type' => 'page']);
|
Chris@0
|
156 $this->assertNodeAccess([
|
Chris@0
|
157 'view' => TRUE,
|
Chris@0
|
158 'update' => TRUE,
|
Chris@0
|
159 'delete' => TRUE,
|
Chris@0
|
160 ], $node6, $web_user6);
|
Chris@0
|
161
|
Chris@0
|
162 // Tests the "edit own BUNDLE" and "delete own BUNDLE" permission.
|
Chris@0
|
163 $web_user7 = $this->drupalCreateUser([
|
Chris@0
|
164 'access content',
|
Chris@0
|
165 'edit own page content',
|
Chris@0
|
166 'delete own page content',
|
Chris@0
|
167 ]);
|
Chris@0
|
168 // User should not be able to edit or delete nodes they do not own.
|
Chris@0
|
169 $this->assertNodeAccess([
|
Chris@0
|
170 'view' => TRUE,
|
Chris@0
|
171 'update' => FALSE,
|
Chris@0
|
172 'delete' => FALSE,
|
Chris@0
|
173 ], $node6, $web_user7);
|
Chris@0
|
174
|
Chris@0
|
175 // User should be able to edit or delete nodes they own.
|
Chris@0
|
176 $node7 = $this->drupalCreateNode([
|
Chris@0
|
177 'type' => 'page',
|
Chris@0
|
178 'uid' => $web_user7->id(),
|
Chris@0
|
179 ]);
|
Chris@0
|
180 $this->assertNodeAccess([
|
Chris@0
|
181 'view' => TRUE,
|
Chris@0
|
182 'update' => TRUE,
|
Chris@0
|
183 'delete' => TRUE,
|
Chris@0
|
184 ], $node7, $web_user7);
|
Chris@0
|
185 }
|
Chris@0
|
186
|
Chris@0
|
187 /**
|
Chris@0
|
188 * Test operations not supported by node grants.
|
Chris@0
|
189 */
|
Chris@0
|
190 public function testUnsupportedOperation() {
|
Chris@0
|
191 $this->enableModules(['node_access_test_empty']);
|
Chris@0
|
192 $web_user = $this->drupalCreateUser(['access content']);
|
Chris@0
|
193 $node = $this->drupalCreateNode();
|
Chris@0
|
194 $this->assertNodeAccess(['random_operation' => FALSE], $node, $web_user);
|
Chris@0
|
195 }
|
Chris@0
|
196
|
Chris@0
|
197 /**
|
Chris@0
|
198 * Asserts that node access correctly grants or denies access.
|
Chris@0
|
199 *
|
Chris@0
|
200 * @param array $ops
|
Chris@0
|
201 * An associative array of the expected node access grants for the node
|
Chris@0
|
202 * and account, with each key as the name of an operation (e.g. 'view',
|
Chris@0
|
203 * 'delete') and each value a Boolean indicating whether access to that
|
Chris@0
|
204 * operation should be granted.
|
Chris@0
|
205 * @param \Drupal\node\NodeInterface $node
|
Chris@0
|
206 * The node object to check.
|
Chris@0
|
207 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
208 * The user account for which to check access.
|
Chris@0
|
209 */
|
Chris@0
|
210 public function assertNodeAccess(array $ops, NodeInterface $node, AccountInterface $account) {
|
Chris@0
|
211 foreach ($ops as $op => $result) {
|
Chris@0
|
212 $this->assertEquals($result, $this->accessHandler->access($node, $op, $account), $this->nodeAccessAssertMessage($op, $result, $node->language()
|
Chris@0
|
213 ->getId()));
|
Chris@0
|
214 }
|
Chris@0
|
215 }
|
Chris@0
|
216
|
Chris@0
|
217 /**
|
Chris@0
|
218 * Asserts that node create access correctly grants or denies access.
|
Chris@0
|
219 *
|
Chris@0
|
220 * @param string $bundle
|
Chris@0
|
221 * The node bundle to check access to.
|
Chris@0
|
222 * @param bool $result
|
Chris@0
|
223 * Whether access should be granted or not.
|
Chris@0
|
224 * @param \Drupal\Core\Session\AccountInterface $account
|
Chris@0
|
225 * The user account for which to check access.
|
Chris@0
|
226 * @param string|null $langcode
|
Chris@0
|
227 * (optional) The language code indicating which translation of the node
|
Chris@0
|
228 * to check. If NULL, the untranslated (fallback) access is checked.
|
Chris@0
|
229 */
|
Chris@0
|
230 public function assertNodeCreateAccess($bundle, $result, AccountInterface $account, $langcode = NULL) {
|
Chris@0
|
231 $this->assertEquals($result, $this->accessHandler->createAccess($bundle, $account, [
|
Chris@0
|
232 'langcode' => $langcode,
|
Chris@0
|
233 ]), $this->nodeAccessAssertMessage('create', $result, $langcode));
|
Chris@0
|
234 }
|
Chris@0
|
235
|
Chris@0
|
236 /**
|
Chris@0
|
237 * Constructs an assert message to display which node access was tested.
|
Chris@0
|
238 *
|
Chris@0
|
239 * @param string $operation
|
Chris@0
|
240 * The operation to check access for.
|
Chris@0
|
241 * @param bool $result
|
Chris@0
|
242 * Whether access should be granted or not.
|
Chris@0
|
243 * @param string|null $langcode
|
Chris@0
|
244 * (optional) The language code indicating which translation of the node
|
Chris@0
|
245 * to check. If NULL, the untranslated (fallback) access is checked.
|
Chris@0
|
246 *
|
Chris@0
|
247 * @return string
|
Chris@0
|
248 * An assert message string which contains information in plain English
|
Chris@0
|
249 * about the node access permission test that was performed.
|
Chris@0
|
250 */
|
Chris@0
|
251 public function nodeAccessAssertMessage($operation, $result, $langcode = NULL) {
|
Chris@0
|
252 return new FormattableMarkup(
|
Chris@0
|
253 'Node access returns @result with operation %op, language code %langcode.',
|
Chris@0
|
254 [
|
Chris@0
|
255 '@result' => $result ? 'true' : 'false',
|
Chris@0
|
256 '%op' => $operation,
|
Chris@0
|
257 '%langcode' => !empty($langcode) ? $langcode : 'empty',
|
Chris@0
|
258 ]
|
Chris@0
|
259 );
|
Chris@0
|
260 }
|
Chris@0
|
261
|
Chris@0
|
262 }
|