Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / rest / tests / src / Functional / EntityResource / Comment / CommentResourceTestBase.php
1 <?php
2
3 namespace Drupal\Tests\rest\Functional\EntityResource\Comment;
4
5 use Drupal\comment\Entity\Comment;
6 use Drupal\comment\Entity\CommentType;
7 use Drupal\comment\Tests\CommentTestTrait;
8 use Drupal\entity_test\Entity\EntityTest;
9 use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
10 use Drupal\user\Entity\User;
11 use GuzzleHttp\RequestOptions;
12
13 abstract class CommentResourceTestBase extends EntityResourceTestBase {
14
15   use CommentTestTrait;
16
17   /**
18    * {@inheritdoc}
19    */
20   public static $modules = ['comment', 'entity_test'];
21
22   /**
23    * {@inheritdoc}
24    */
25   protected static $entityTypeId = 'comment';
26
27   /**
28    * {@inheritdoc}
29    */
30   protected static $patchProtectedFieldNames = [
31     'status',
32     'pid',
33     'entity_id',
34     'uid',
35     'name',
36     'homepage',
37     'created',
38     'changed',
39     'thread',
40     'entity_type',
41     'field_name',
42   ];
43
44   /**
45    * @var \Drupal\comment\CommentInterface
46    */
47   protected $entity;
48
49   /**
50    * {@inheritdoc}
51    */
52   protected function setUpAuthorization($method) {
53     switch ($method) {
54       case 'GET':
55         $this->grantPermissionsToTestedRole(['access comments', 'view test entity']);
56         break;
57       case 'POST':
58         $this->grantPermissionsToTestedRole(['post comments']);
59         break;
60       case 'PATCH':
61         // Anononymous users are not ever allowed to edit their own comments. To
62         // be able to test PATCHing comments as the anonymous user, the more
63         // permissive 'administer comments' permission must be granted.
64         // @see \Drupal\comment\CommentAccessControlHandler::checkAccess
65         if (static::$auth) {
66           $this->grantPermissionsToTestedRole(['edit own comments']);
67         }
68         else {
69           $this->grantPermissionsToTestedRole(['administer comments']);
70         }
71         break;
72       case 'DELETE':
73         $this->grantPermissionsToTestedRole(['administer comments']);
74         break;
75     }
76   }
77
78   /**
79    * {@inheritdoc}
80    */
81   protected function createEntity() {
82     // Create a "bar" bundle for the "entity_test" entity type and create.
83     $bundle = 'bar';
84     entity_test_create_bundle($bundle, NULL, 'entity_test');
85
86     // Create a comment field on this bundle.
87     $this->addDefaultCommentField('entity_test', 'bar', 'comment');
88
89     // Create a "Camelids" test entity that the comment will be assigned to.
90     $commented_entity = EntityTest::create([
91       'name' => 'Camelids',
92       'type' => 'bar',
93     ]);
94     $commented_entity->save();
95
96     // Create a "Llama" comment.
97     $comment = Comment::create([
98       'comment_body' => [
99         'value' => 'The name "llama" was adopted by European settlers from native Peruvians.',
100         'format' => 'plain_text',
101       ],
102       'entity_id' => $commented_entity->id(),
103       'entity_type' => 'entity_test',
104       'field_name' => 'comment',
105     ]);
106     $comment->setSubject('Llama')
107       ->setOwnerId(static::$auth ? $this->account->id() : 0)
108       ->setPublished(TRUE)
109       ->setCreatedTime(123456789)
110       ->setChangedTime(123456789);
111     $comment->save();
112
113     return $comment;
114   }
115
116   /**
117    * {@inheritdoc}
118    */
119   protected function getExpectedNormalizedEntity() {
120     $author = User::load($this->entity->getOwnerId());
121     return [
122       'cid' => [
123         ['value' => 1],
124       ],
125       'uuid' => [
126         ['value' => $this->entity->uuid()],
127       ],
128       'langcode' => [
129         [
130           'value' => 'en',
131         ],
132       ],
133       'comment_type' => [
134         [
135           'target_id' => 'comment',
136           'target_type' => 'comment_type',
137           'target_uuid' => CommentType::load('comment')->uuid(),
138         ],
139       ],
140       'subject' => [
141         [
142           'value' => 'Llama',
143         ],
144       ],
145       'status' => [
146         [
147           'value' => TRUE,
148         ],
149       ],
150       'created' => [
151         [
152           'value' => 123456789,
153         ],
154       ],
155       'changed' => [
156         [
157           'value' => $this->entity->getChangedTime(),
158         ],
159       ],
160       'default_langcode' => [
161         [
162           'value' => TRUE,
163         ],
164       ],
165       'uid' => [
166         [
167           'target_id' => (int) $author->id(),
168           'target_type' => 'user',
169           'target_uuid' => $author->uuid(),
170           'url' => base_path() . 'user/' . $author->id(),
171         ],
172       ],
173       'pid' => [],
174       'entity_type' => [
175         [
176           'value' => 'entity_test',
177         ],
178       ],
179       'entity_id' => [
180         [
181           'target_id' => 1,
182           'target_type' => 'entity_test',
183           'target_uuid' => EntityTest::load(1)->uuid(),
184           'url' => base_path() . 'entity_test/1',
185         ],
186       ],
187       'field_name' => [
188         [
189           'value' => 'comment',
190         ],
191       ],
192       'name' => [],
193       'homepage' => [],
194       'thread' => [
195         [
196           'value' => '01/',
197         ],
198       ],
199       'comment_body' => [
200         [
201           'value' => 'The name "llama" was adopted by European settlers from native Peruvians.',
202           'format' => 'plain_text',
203         ],
204       ],
205     ];
206   }
207
208   /**
209    * {@inheritdoc}
210    */
211   protected function getNormalizedPostEntity() {
212     return [
213       'comment_type' => [
214         [
215           'target_id' => 'comment',
216         ],
217       ],
218       'entity_type' => [
219         [
220           'value' => 'entity_test',
221         ],
222       ],
223       'entity_id' => [
224         [
225           'target_id' => EntityTest::load(1)->id(),
226         ],
227       ],
228       'field_name' => [
229         [
230           'value' => 'comment',
231         ],
232       ],
233       'subject' => [
234         [
235           'value' => 'Dramallama',
236         ],
237       ],
238       'comment_body' => [
239         [
240           'value' => 'Llamas are awesome.',
241           'format' => 'plain_text',
242         ],
243       ],
244     ];
245   }
246
247   /**
248    * {@inheritdoc}
249    */
250   protected function getNormalizedPatchEntity() {
251     return array_diff_key($this->getNormalizedPostEntity(), ['entity_type' => TRUE, 'entity_id' => TRUE, 'field_name' => TRUE]);
252   }
253
254   /**
255    * Tests POSTing a comment without critical base fields.
256    *
257    * testPost() is testing with the most minimal normalization possible: the one
258    * returned by ::getNormalizedPostEntity().
259    *
260    * But Comment entities have some very special edge cases:
261    * - base fields that are not marked as required in
262    *   \Drupal\comment\Entity\Comment::baseFieldDefinitions() yet in fact are
263    *   required.
264    * - base fields that are marked as required, but yet can still result in
265    *   validation errors other than "missing required field".
266    */
267   public function testPostDxWithoutCriticalBaseFields() {
268     $this->initAuthentication();
269     $this->provisionEntityResource();
270     $this->setUpAuthorization('POST');
271
272     $url = $this->getEntityResourcePostUrl()->setOption('query', ['_format' => static::$format]);
273     $request_options = [];
274     $request_options[RequestOptions::HEADERS]['Accept'] = static::$mimeType;
275     $request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
276     $request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('POST'));
277
278     // DX: 422 when missing 'entity_type' field.
279     $request_options[RequestOptions::BODY] = $this->serializer->encode(array_diff_key($this->getNormalizedPostEntity(), ['entity_type' => TRUE]), static::$format);
280     $response = $this->request('POST', $url, $request_options);
281     // @todo Uncomment, remove next 3 lines in https://www.drupal.org/node/2820364.
282     $this->assertSame(500, $response->getStatusCode());
283     $this->assertSame(['application/json'], $response->getHeader('Content-Type'));
284     $this->assertSame('{"message":"A fatal error occurred: Internal Server Error"}', (string) $response->getBody());
285     //$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nentity_type: This value should not be null.\n", $response);
286
287     // DX: 422 when missing 'entity_id' field.
288     $request_options[RequestOptions::BODY] = $this->serializer->encode(array_diff_key($this->getNormalizedPostEntity(), ['entity_id' => TRUE]), static::$format);
289     // @todo Remove the try/catch in favor of the two commented lines in
290     // https://www.drupal.org/node/2820364.
291     try {
292       $response = $this->request('POST', $url, $request_options);
293       // This happens on DrupalCI.
294       //$this->assertSame(500, $response->getStatusCode());
295     }
296     catch (\Exception $e) {
297       // This happens on Wim's local machine.
298       //$this->assertSame("Error: Call to a member function get() on null\nDrupal\\comment\\Plugin\\Validation\\Constraint\\CommentNameConstraintValidator->getAnonymousContactDetailsSetting()() (Line: 96)\n", $e->getMessage());
299     }
300     //$response = $this->request('POST', $url, $request_options);
301     //$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nentity_type: This value should not be null.\n", $response);
302
303     // DX: 422 when missing 'entity_type' field.
304     $request_options[RequestOptions::BODY] = $this->serializer->encode(array_diff_key($this->getNormalizedPostEntity(), ['field_name' => TRUE]), static::$format);
305     $response = $this->request('POST', $url, $request_options);
306     // @todo Uncomment, remove next 3 lines in https://www.drupal.org/node/2820364.
307     $this->assertSame(500, $response->getStatusCode());
308     $this->assertSame(['application/json'], $response->getHeader('Content-Type'));
309     $this->assertSame('{"message":"A fatal error occurred: Field  is unknown."}', (string) $response->getBody());
310     //$this->assertResourceErrorResponse(422, "Unprocessable Entity: validation failed.\nfield_name: This value should not be null.\n", $response);
311   }
312
313   /**
314    * {@inheritdoc}
315    */
316   protected function getExpectedUnauthorizedAccessMessage($method) {
317     if ($this->config('rest.settings')->get('bc_entity_resource_permissions')) {
318       return parent::getExpectedUnauthorizedAccessMessage($method);
319     }
320
321     switch ($method) {
322       case 'GET';
323         return "The 'access comments' permission is required and the comment must be published.";
324       case 'POST';
325         return "The 'post comments' permission is required.";
326       default:
327         return parent::getExpectedUnauthorizedAccessMessage($method);
328     }
329   }
330
331   /**
332    * Tests POSTing a comment with and without 'skip comment approval'
333    */
334   public function testPostSkipCommentApproval() {
335     $this->initAuthentication();
336     $this->provisionEntityResource();
337     $this->setUpAuthorization('POST');
338
339     // Create request.
340     $request_options = [];
341     $request_options[RequestOptions::HEADERS]['Accept'] = static::$mimeType;
342     $request_options[RequestOptions::HEADERS]['Content-Type'] = static::$mimeType;
343     $request_options = array_merge_recursive($request_options, $this->getAuthenticationRequestOptions('POST'));
344     $request_options[RequestOptions::BODY] = $this->serializer->encode($this->getNormalizedPostEntity(), static::$format);
345
346     $url = $this->getEntityResourcePostUrl()->setOption('query', ['_format' => static::$format]);
347
348     // Status should be FALSE when posting as anonymous.
349     $response = $this->request('POST', $url, $request_options);
350     $unserialized = $this->serializer->deserialize((string) $response->getBody(), get_class($this->entity), static::$format);
351     $this->assertResourceResponse(201, FALSE, $response);
352     $this->assertFalse($unserialized->getStatus());
353
354     // Grant anonymous permission to skip comment approval.
355     $this->grantPermissionsToTestedRole(['skip comment approval']);
356
357     // Status should be TRUE when posting as anonymous and skip comment approval.
358     $response = $this->request('POST', $url, $request_options);
359     $unserialized = $this->serializer->deserialize((string) $response->getBody(), get_class($this->entity), static::$format);
360     $this->assertResourceResponse(201, FALSE, $response);
361     $this->assertTrue($unserialized->getStatus());
362   }
363
364 }